-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmbSrvWrk.js
More file actions
442 lines (425 loc) · 32.5 KB
/
mbSrvWrk.js
File metadata and controls
442 lines (425 loc) · 32.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
/* mbSrvWrk.js
* --------------------------------
* Проект: MobileBalance
* Описание: Сервисный (фоновый) обработчик расширения MobileBalance (Service Worker)
* Редакция: 2025.10.20
*
*/
'use strict';
import { Delay, dbVersion } from './vars.mjs'; // Глобальные переменные расширения (из модуля vars.mjs)
// Указываем в подписи к иконке расширения его наименование и версию
chrome.action.setTitle( { title: `${chrome.runtime.getManifest().name} ${chrome.runtime.getManifest().version}` } );
// Инициализация структур расширения в local storage при его исходной установке
chrome.runtime.onInstalled.addListener( async ( details ) => { // Fired when the extension is first installed,
console.log( `[MB] Exeption 'runtime.onInstalled' fired with reason: '${details.reason}'` );
let dbMB, dbTrnsMB, dbObjStorMB, dbCrsrMB; // when the extension is updated to a new version,
switch( details.reason ) { // and when Chrome is updated to a new version
case 'install': {
try {
await chrome.storage.local.set( { inProgress: false } ); // Статус опроса (true = идёт, false = не начат/прерван)
// Инициализируем исходную коллекцию параметров для провайдеров (плагинов)
await chrome.storage.local.set( await (await fetch( `.\\providers\\providers.json` )).json() );
// Загружаем исходные параметры опроса
await chrome.storage.local.set( await (await fetch( `.\\options\\options.json` )).json() );
// Инициализируем структуру параметров номеров для опроса (пустая, загружаем отдельно или формируем в интерфейсе)
await chrome.storage.local.set( { accounts: [] } );
// Инициализируем таймер ежедневного опроса
await calcNextPoollingTime() // Получаем время следующего опроса по расписанию и обновляем таймер
.then( async function( alarmTime ) { updatePoollingTimer( alarmTime ) } )
// Создаём исходные структуры indexedDB
let dbRequest = indexedDB.open( 'BalanceHistory', dbVersion );
dbRequest.onerror = function( evnt ) {
// -------
console.log( `[MB] ${evnt.target.error}` );
}
dbRequest.onupgradeneeded = function( evnt ) {
// ---------------
dbMB = evnt.target.result;
if ( !dbMB.objectStoreNames.contains( 'Phones' ) ) { // Если хранилища 'Phones' не было - создаём его
dbObjStorMB = dbMB.createObjectStore( 'Phones',
{ keyPath: 'QueryDateTime', autoIncrement: false } );
}
else { // Если хранилище 'Phones' было - открываем его
dbTrnsMB = dbMB.transaction( [ 'Phones' ], 'readwrite' );
dbObjStorMB = dbTrnsMB.objectStore( 'Phones' );
}
if (!dbObjStorMB.indexNames.contains( 'PhoneNumber' ) ) // Если индекса 'PhoneNumber' не было - создаём его
dbObjStorMB.createIndex( 'PhoneNumber', 'PhoneNumber', { unique: false } );
console.log( `[MB] IndexedDB '${dbMB.name}' created / upgraded` );
}
}
catch( err ) { console.log( `[MB] ${err}` ); }
break;
}
case 'update': {
try {
console.log( `[MB] Extention updated from version '${details.previousVersion}' ` +
`to version '${chrome.runtime.getManifest().version}'` );
// Замещаем коллекцию провайдеров (плагинов) и их параметры на полученные в обновлении
let providerNew = (await (await fetch( `.\\providers\\providers.json` )).json()).provider;
let providerSet = (await chrome.storage.local.get( 'provider' )).provider;
providerSet.forEach( function ( item, index ) {
if ( ( item.custom ) && // Если в текущем наборе провайдеров есть добавленные пользователем...
( providerNew.findIndex( function( pItem ) {
return ( item.name === pItem.name ) } ) < 0 ) // ...и провайдеров с таким именем нет в составе обновлённой коллекции...
) providerNew.push( item ); // ...то такие пользовательские записи оставляем
});
await chrome.storage.local.set( { provider: providerNew } );
// Реинициализируем таймер ежедневного опроса, если он используется
await calcNextPoollingTime()
.then( async function( alarmTime ) { updatePoollingTimer( alarmTime ) } )
// Следующий код нужен только для перехода на версию v1.0.11, в которой в структуру записи хранилища IndexedDB 'Phones'
// добавлено поле 'Warning'. Нужно добавить его со значением 0 во все существующие записи
/* // -------
let dbRequest = indexedDB.open( 'BalanceHistory', dbVersion );
dbRequest.onerror = function( evnt ) { console.log( `[MB] ${evnt.target.error}` ); }
dbRequest.onupgradeneeded = function( evnt ) { console.log( `[MB] IndexedDB '${evnt.target.result.name}' upgrade needed` ); }
dbRequest.onsuccess = function( evnt ) {
dbMB = evnt.target.result;
dbTrnsMB = dbMB.transaction( [ 'Phones' ], 'readwrite' );
dbObjStorMB = dbTrnsMB.objectStore( 'Phones' );
dbObjStorMB.onerror = function( evnt ) { console.log( `[MB] ${evnt.target.error}` ); }
let recCount = 0;
console.log( `[MB] Adding key 'Warning' with value=0 to all records of storage '${dbObjStorMB.name}' in IndexedDB...` );
dbCrsrMB = dbObjStorMB.openCursor( IDBKeyRange.lowerBound(0), 'next' );
dbCrsrMB.onerror = function( evnt ) { console.log( `[MB] ${evnt.target.error}` ); }
dbCrsrMB.onsuccess = function( evnt ) {
let dbRec = evnt.target.result;
if ( dbRec ) {
if ( dbRec.value.Warning === undefined ) { // Если поля 'Warning' в записи ещё нет, то добавляеем его
dbRec.value.Warning = 0; // Добавляем в структуру записи поле 'Warning' со значением 0
let result = dbObjStorMB.put( dbRec.value ); // Обновляем запись в хранилище IndexedDB 'Phones'
result.onerror = function( evnt ) { console.log( `[MB] ${evnt.target.error}` ); }
++recCount;
}
dbRec.continue(); // Переходим к следующей записи
}
else { // Все записи в хранилище обработаны
dbTrnsMB.commit(); // Закрываем транзакцию, сохраняем результаты из кэша в хранилище
console.log( `[MB] Records updated: ${recCount}` );
}
}
}
// ------- */
// Установливаем popup-окно сообщения о составе обновления расширения
// Значение будет возвращено на popup-окно по умолчанию при показе окна сообщения
chrome.action.setPopup( { popup: 'content/updatePopup.html' } );
chrome.action.setBadgeText( { text: 'new' } ); // Показываем надпись об обновлении расширения
}
catch( err ) { console.log( `[MB] ${err}` ); }
break;
} // Edge, Safari - only supports 'install' and 'update'.
case 'chrome_update': // Chrome, Yandex, Opera
case 'browser_update': { // Firefox, Chromium (?)
// Реинициализируем таймер ежедневного опроса, если он используется
await calcNextPoollingTime() // Получаем время следующего опроса по расписанию и обновляем таймер
.then( async function( alarmTime ) { updatePoollingTimer( alarmTime ) } )
break;
}
} /* switch */
});
// Инициализация таймера ежедневного опроса при запуске браузера
chrome.runtime.onStartup.addListener( async ( evnt ) => {
console.log( `[MB] Exeption "runtime.onStartup" fired` );
await calcNextPoollingTime() // Получаем время следующего опроса по расписанию и обновляем таймер
.then( async function( alarmTime ) { updatePoollingTimer( alarmTime ) } )
});
// Чтение значения единичного параметра из local storage
function getParamFromStorage( param ) {
// ----------------------------
let fromStorage = new Promise( ( resolve, reject ) => {
chrome.storage.local.get( param, ( result ) => {
if ( Object.entries( result ).length > 0 ) {
resolve( Object.values( result )[ 0 ] )
}
else
resolve( undefined );
})
});
return fromStorage;
}
// Инициализация таймера опроса по расписанию
async function calcNextPoollingTime( inputAlarmTime = undefined ) {
// --------------------------------------------------
return new Promise( async function( resolve, reject ) {
let maintainPooling, maintainDays, maintainStartTime, maintainRepeat, maintainRepeatTime;
maintainPooling = await getParamFromStorage( 'maintainPooling' );
if ( maintainPooling === undefined ) { // Если параметра 'maintainPooling' в localStorage нет, то создаём его
// Очевидно, что и других параметров опроса в localStorage нет, добавляем их тоже
await chrome.storage.local.set( { maintainPooling: maintainPooling = true, // опрос разрешён
maintainDays: maintainDays = [ 1, 1, 1, 1, 1, 1, 1 ], // все дни включены
maintainStartTime: maintainStartTime = '16:00', // старт опроса в 16:00
maintainRepeat: maintainRepeat = false, // повторы опросов выключены
maintainRepeatTime: maintainRepeatTime = 0 // период повторных опросов 0 час
} );
}
else { // Получаем из localStorage остальные параметры опроса
maintainDays = await getParamFromStorage( 'maintainDays' );
maintainStartTime = await getParamFromStorage( 'maintainStartTime' );
maintainRepeat = await getParamFromStorage( 'maintainRepeat' );
maintainRepeatTime = await getParamFromStorage( 'maintainRepeatTime' );
}
// Если параметр выполнения опроса по расписанию установлен и указаны дни для проведения опросов, то определяем время следующего опроса
if ( ( maintainPooling === true ) && ( maintainDays.includes( 1 ) === true ) ) {
let alarmTime;
if ( inputAlarmTime === undefined ) // Если входного значения нет, то формируем его по значениям из хранилища
alarmTime = new Date().setHours( Number(maintainStartTime.slice(0, 2)), // Получаем время таймера для текущей даты
Number(maintainStartTime.slice(3, 5)), 0, 0 )
else
alarmTime = inputAlarmTime;
// Если текущая дата вне дней недели, указанных для опросов, то получаем дату очередного допустимого дня
while ( maintainDays[ new Date( alarmTime ).getDay() ] === 0 ) {
alarmTime += 86400000; // Устанавливаем следующую дату относительно заданной (+ сутки = 86400000 = 1000 * 60 * 60 * 24)
}
let nextDate = new Date( alarmTime + 86400000 ).setHours( 0, 0, 0, 0); // Cледующая дата относительно заданной даты-времени
// (+ сутки = 86400000 = 1000 * 60 * 60 * 24)
if ( ( alarmTime < Date.now() ) || // Определяем новое время опроса, если заданное время в текущей дате прошло ...
( inputAlarmTime !== undefined ) ) { // ... или требуется провести расчёт относительно входного значения
// Если задано повторение опросов до конца суток, то определяем время очередного повторного опроса
if ( maintainRepeat === true ) {
// Переводим заданное время периода из часов в миллисекунды
let period = parseFloat( maintainRepeatTime ) * 60 * 60 * 1000;
if ( period > 0 ) { // Если задано ненулевое значение значение периода повторного опроса
let periodAlarm = alarmTime;
for ( let i = 1; ; ++i ) {
// Если полученое время запуска опроса в пределах текущей даты ...
if ( new Date( alarmTime + ( period * i ) ).setHours( 0, 0, 0, 0 ) < nextDate ) {
if ( ( alarmTime + ( period * i ) ) > Date.now() ) { // ... и ещё не прошло
periodAlarm += period * i;
break;
}
}
else { // Вышли за пределы даты. Берём следующую дату и исходное время опроса, повторных запусков в текущей дате больше нет
periodAlarm = new Date( nextDate ).setHours( Number(maintainStartTime.slice(0, 2)), // Получаем время таймера в следующей дате
Number(maintainStartTime.slice(3, 5)), 0, 0 );
while ( maintainDays[ new Date( periodAlarm ).getDay() ] === 0 ) { // Если дата вне дней для опросов, то подбираем разрешённую
periodAlarm += 86400000;
}
break;
}
}
if ( periodAlarm > alarmTime ) // Если полученое время запуска опроса позднее даты-времени ранее выбранного,
alarmTime = periodAlarm; // то принимаем его для установки таймера
}
else { // При нулевом значении периода повторных запросов берём очередную дату из допустимых дней
alarmTime += 86400000; // Устанавливаем следующую дату относительно заданной
while ( maintainDays[ new Date( alarmTime ).getDay() ] === 0 ) { // Если дата вне дней для опросов, то подбираем разрешённую
alarmTime += 86400000;
}
}
}
else { // Если повторные опросы отключены, то определяем время очередного опроса по расписанию
alarmTime += 86400000; // Устанавливаем следующую дату относительно заданной
while ( maintainDays[ new Date( alarmTime ).getDay() ] === 0 ) { // Если дата вне дней для опросов, то подбираем разрешённую
alarmTime += 86400000;
}
}
}
resolve( alarmTime ); // Возвращием новое значение таймера
}
else
resolve( -1 ); // Выполнение опроса по расписанию отключено
});
}
// Инициализация таймера ежедневного опроса
async function updatePoollingTimer( alarmTime ) {
// --------------------------------
if ( alarmTime < 0 ) { // Опрос по расписанию отключён, снимаем таймер (если он был)
await chrome.alarms.clear( 'poolingTimer' );
console.log( `[MB] Pooling timer cleared` );
}
else { // Устанавливаем новое значение таймера
await chrome.alarms.create( 'poolingTimer', { when: alarmTime } );
console.log( `[MB] Pooling timer set up on '${new Date( alarmTime )}'` );
}
}
// При срабатывании таймера опроса по расписанию запустить процесс опроса
chrome.alarms.onAlarm.addListener( async function( alarm ) {
// ------------
chrome.runtime.onMessage.dispatch( { 'message': 'MB_startPooling', init: 'byTimer' }, { tab: null, id: self.location.origin }, null );
});
// Основной цикл работы по сообщениям
chrome.runtime.onMessage.addListener(
async function( request, sender, sendResponse ) {
switch ( request.message ) {
case 'MB_poolingTimerCalc': { // Передаём значения таймера для предложенного времени старта
if ( request.alarmTime !== undefined )
calcNextPoollingTime( request.alarmTime )
.then( function( alarmTime ) {
chrome.tabs.sendMessage( sender.tab.id, { message: 'MB_nextPoollingTime', alarmTime: alarmTime, command: request.message } );
});
else
console.log( `[MB] Undefined value for pooling time calculation` );
return true;
break;
}
case 'MB_poolingTimerReset': { // Устанавливаем обновлённые значения таймера запуска опроса по расписанию
if ( sendResponse ) sendResponse( 'done' ); // Ответ окну результатов опроса для поддержания канала связи
calcNextPoollingTime()
.then( async function( alarmTime ) {
updatePoollingTimer( alarmTime );
chrome.tabs.sendMessage( sender.tab.id, { message: 'MB_nextPoollingTime', alarmTime: alarmTime, command: request.message } );
});
return true;
break;
}
case 'MB_showNotification': { // Показать уведомление (оповещение)
if ( sendResponse ) sendResponse( 'done' ); // Ответ окну результатов опроса для поддержания канала связи
await self.registration.showNotification( request.title, request.options );
return true;
break;
}
case 'MB_startPooling': { // Запустить опрос в новом окне
if ( sendResponse ) sendResponse( 'done' ); // Ответ в popup для для поддержания канала связи
if ( !await getParamFromStorage( 'inProgress' ) ) { // Если нет текущего, то запускаем опрос
try { // Открываем в новом окне страницу для проведения опроса и передаём ей параметром тип опроса
let cycleOrder, workWin, workTab;
getParamFromStorage( 'cycleOrder' ) // Выясняем порядок опроса
.then( function( result ) { // Открываем новое окно для выполнения опроса
cycleOrder = result;
// По кнопке из popup открываем окно активным в нормальном режиме, по таймеру - минимизированным
let createData = { type: 'normal' };
switch ( request.init ) {
case 'fromPopUp': { createData.state = 'normal'; createData.focused = true;
break; }
case 'byTimer': { createData.state = 'minimized'; createData.focused = false;
calcNextPoollingTime() // Получаем время следующего опроса по расписанию и ...
.then( async function( alarmTime ) {
await updatePoollingTimer( alarmTime ); // ... обновляем таймер таймер опроса
// Выясняем, есть ли открытые страницы настроек расширения для обновления на них времени следующего опроса
chrome.management.getSelf() // Получаем параметры расширения
.then( function( extnData ) { // Ищем вкладку с адресом страницы его настроек
chrome.tabs.query( { currentWindow: true, url: extnData.optionsUrl } )
.then( function( result ) { // Страница настроек в текущем окне нашлась
if ( result.length > 0 ) // Отправляем время следующего опроса для обновления на странице
chrome.tabs.sendMessage( result[ 0 ].id, { message: 'MB_nextPoollingTime',
alarmTime: alarmTime, command: 'MB_poolingTimerCalc' } )
})
.catch( function( err ) { console.log( `[MB] Error occured: ${err}` ) } )
chrome.tabs.query( { currentWindow: false, url: extnData.optionsUrl } )
.then( function( result ) { // Страницы настроек в других окнах нашлись
if ( result.length > 0 ) // Отправляем время следующего опроса для обновления на странице
result.forEach( function( item ) {
chrome.tabs.sendMessage( item.id, { message: 'MB_nextPoollingTime',
alarmTime: alarmTime, command: 'MB_poolingTimerCalc' } );
})
})
.catch( function( err ) { console.log( `[MB] Error occured: ${err}` ) } )
})
})
break; }
};
chrome.windows.create( createData ) // Создаём новое окно для страницы для проведения опроса
.then( function( result ) {
workWin = result;
// Некоторые браузеры отказываются создавать минимизированное окно, пробуем установить нужный статус иначе
chrome.windows.update( workWin.id, { state: createData.state } )
.then( function() { // Сохраняем id окна опроса и id рабочей вкладки опроса
chrome.storage.local.set( { workWin: workWin.id, workTab: workWin.tabs[ 0 ].id } )
.then( function() { // Устанавливаем статус опроса - он запущен
chrome.storage.local.set( { inProgress: true } )
.then( function() { // Открываем в окне страницу опроса
chrome.tabs.update( workWin.tabs[ 0 ].id, { autoDiscardable: false,
url: chrome.runtime.getURL( `content/poolingCycle.html?co=${cycleOrder}` ) } )
.then( function() {
// Актуализируем (если окна открыты) доступность кнопок запуска опроса в popup-окне и
// восстановления исходных значений расширения в окне options
chrome.runtime.sendMessage( { message: 'MB_actualizeControls' } ) // Если открытых окон нет,
.catch( function() {} ); // то нет и кода обработки приёма сообщений - снимаем ошибку канала связи
// Выдаём оповещение о начале опроса
console.log( `[MB] Polling started in ${cycleOrder} order` );
getParamFromStorage( 'notificationsEnable' ) // Если разрешены уведомления вообще
.then( function( result ) { // и уведомления о начале опроса, в частности,
if ( result ) // то выдаём уведомление
getParamFromStorage( 'notificationsOnProcess' )
.then( function( result ) {
if ( result ) {
let d = new Date();
let timeStr =
`${(d.getHours() < 10) ? '0' + String(d.getHours()) : String(d.getHours())}:` +
`${(d.getMinutes() < 10) ? '0' + String(d.getMinutes()) : String(d.getMinutes())}:` +
`${(d.getSeconds() < 10) ? '0' + String(d.getSeconds()) : String(d.getSeconds())} - ` +
`${(d.getDate() < 10) ? '0' + String(d.getDate()) : String(d.getDate())}.` +
`${(d.getMonth() < 9) ? '0' + String(d.getMonth() + 1) : String(d.getMonth() + 1)}.` +
`${String(d.getFullYear())}`;
self.registration.showNotification( 'Опрос начат', { body: timeStr, dir: 'ltr',
requireInteraction: false,
badge: '/images/MB.png',
icon: '/images/MB.png' } );
}
})
})
})
})
})
})
})
});
}
catch( err ) {
console.log( `[MB] ${err}` );
}
}
return true;
break;
}
} /* switch */
// Для сообщений, которые не обрабатываются в Service Worker, выводим в консоль уведомление об их появлении
console.log( `[MB] Message in Service Worker: "${request.message}"` );
return true;
}
);
// Контроль и закрытие окна результатов опроса
chrome.tabs.onRemoved.addListener(
async function( tabId, removeInfo ) {
let workWin = await getParamFromStorage( 'workWin' );
let workTab = await getParamFromStorage( 'workTab' );
if ( workTab === tabId ) { // Рабочая вкладка окна опроса была закрыта
// Выдаём оповещение о завершении опроса
let d = new Date();
let timeStr = `${(d.getHours() < 10) ? '0' + String(d.getHours()) : String(d.getHours())}:` +
`${(d.getMinutes() < 10) ? '0' + String(d.getMinutes()) : String(d.getMinutes())}:` +
`${(d.getSeconds() < 10) ? '0' + String(d.getSeconds()) : String(d.getSeconds())} - ` +
`${(d.getDate() < 10) ? '0' + String(d.getDate()) : String(d.getDate())}.` +
`${(d.getMonth() < 9) ? '0' + String(d.getMonth() + 1) : String(d.getMonth() + 1)}.` +
`${String(d.getFullYear())}`;
let options = { dir: 'ltr', requireInteraction: false, badge: '/images/MB.png' };
if ( await getParamFromStorage( 'inProgress' ) ) { // Если статус опроса не был сброшен, то опроса был завершён некорректно
console.log( `[MB] Pooling window closed by user before pooling was completed (or browser failed)` );
if ( await getParamFromStorage( 'notificationsEnable' ) &&
await getParamFromStorage( 'notificationsOnProcess' ) ) {
options.body = 'Окно опроса было закрыто до его завершения\n' + timeStr;
options.icon = '/images/Alarm.png';
self.registration.showNotification( 'Опрос прекращён', options );
}
}
else {
console.log( `[MB] Pooling window closed, pooling prosess completed` );
if ( await getParamFromStorage( 'notificationsEnable' ) &&
await getParamFromStorage( 'notificationsOnProcess' ) ) {
options.body = 'Опрос завершён, окно опроса закрыто\n' + timeStr;
options.icon = '/images/MB.png';
self.registration.showNotification( 'Опрос завершён', options );
}
};
// Если закрытие рабочей вкладки опроса выполнено скриптом или пользователем, то она считается закрытой
// не по причине закрытия содержащего её окна. Если это окно всё ещё открыто, то закрываем его
if ( !removeInfo.isWindowClosing ) { // Если рабочая вкладка закрыта не из-за закрытия её окна...
chrome.windows.get( removeInfo.windowId )
.then( async function( Wnd ) {
if ( workWin === Wnd.id ) // ...и окно всё ещё открыто...
await chrome.windows.remove( workWin ); // ...то закрываем его
})
.catch( function() {} ); // Окна результатов опроса (с ID = workWin) нет, действий не требуется
}
await chrome.storage.local.remove( 'workTab' ); // Удаляем запись об ID рабочей вкладки окна результатов опроса
await chrome.storage.local.remove( 'workWin' ); // Удаляем запись об ID окна результатов опроса
await chrome.storage.local.set( { inProgress: false } ); // Сбрасываем статус опроса - он не идёт
// Актуализируем (если окна открыты) доступность кнопок запуска опроса в popup-окне и
// восстановления исходных значений расширения в окне options
chrome.runtime.sendMessage( { message: 'MB_actualizeControls' } ) // Если открытых окон нет,
.catch( function() {} ); // то не нужна и обработка приёма сообщений - снимаем ошибку канала связи
}
return true;
}
);