1
- /* globals saveToStorage, toggleContentMenus */
1
+ import "./lib/browser-polyfill.js" ;
2
+ import { saveToStorage } from "./storage.js" ;
3
+ import { toggleContentMenus } from "./menu.js" ;
4
+
2
5
const BADGE_BACKGROUND_COLOR = '#d51b15' ;
3
- const BADGE_TEXT_COLOR = '#ffffff'
6
+ const BADGE_TEXT_COLOR = '#ffffff' ;
4
7
const OPTIONS_VERSION = 3 ; // Increment when there are new options
5
8
6
- let refreshTimeout ;
7
9
let last_unread_count = 0 ;
8
- let notificationTimeout ;
9
10
let retryCount = 0 ;
10
11
let lastError = "" ;
11
12
12
13
function getBrowserName ( ) {
13
- if ( typeof browser !== 'undefined' ) {
14
+ // Credit to https://github.com/mozilla/webextension-polyfill/issues/55#issuecomment-329676034 since polyfill makes old "check if browser is defined impossible"
15
+ if ( browser . runtime . id === 'theoldreader@knyar' ) {
14
16
return 'Mozilla' ;
15
17
} else {
16
18
return 'Chrome' ;
17
19
}
18
20
}
19
21
20
- function showNotification ( title , body , id = "theoldreader" ) {
22
+ async function showNotification ( title , body , id = "theoldreader" ) {
21
23
if ( id != "theoldreader-newOptions" && localStorage . show_notifications != 'yes' ) {
22
24
return ;
23
25
}
@@ -35,80 +37,99 @@ function showNotification(title, body, id = "theoldreader") {
35
37
options . isClickable = true ;
36
38
}
37
39
38
- chrome . notifications . create ( id , options ) ;
40
+ browser . notifications . create ( id , options ) ;
39
41
40
42
if ( id == "theoldreader" && localStorage . notification_timeout > 0 ) {
41
- window . clearTimeout ( notificationTimeout ) ; // If updating a notification, reset timeout
42
- notificationTimeout = window . setTimeout (
43
- function ( ) { chrome . notifications . clear ( "theoldreader" ) ; } ,
44
- localStorage . notification_timeout * 1000
43
+ let timeout = localStorage . notification_timeout ;
44
+
45
+ // Chrome does not allow alarms shorter than 30 seconds
46
+ if ( getBrowserName ( ) === "Chrome" && timeout < 30 ) {
47
+ timeout = 30 ;
48
+ }
49
+
50
+ await browser . alarms . clear ( "notification-clear" ) ;
51
+ browser . alarms . create (
52
+ "notification-clear" ,
53
+ {
54
+ delayInMinutes : timeout / 60
55
+ }
45
56
) ;
46
57
}
47
58
}
48
59
49
- /* exported onNotificationClick */
50
- function onNotificationClick ( id ) {
60
+ // Listener for browser.alarms.onAlarm
61
+ export function onAlarm ( alarm ) {
62
+ switch ( alarm . name ) {
63
+ case "notification-clear" :
64
+ browser . notifications . clear ( "theoldreader" ) ;
65
+ break ;
66
+ case "server-refresh" :
67
+ getCountersFromHTTP ( ) ;
68
+ break ;
69
+ }
70
+ }
71
+
72
+ export async function onNotificationClick ( id ) {
51
73
switch ( id ) {
52
74
case "theoldreader" :
53
75
openOurTab ( ) ;
54
76
break ;
55
77
case "theoldreader-newOptions" :
56
- chrome . runtime . openOptionsPage ( ) ;
78
+ await browser . runtime . openOptionsPage ( ) ;
57
79
break ;
58
80
}
59
- chrome . notifications . clear ( id ) ;
81
+ await browser . notifications . clear ( id ) ;
60
82
}
61
83
62
- function baseUrl ( ) {
84
+ export function baseUrl ( ) {
63
85
return ( localStorage . force_http == 'yes' ? 'http://theoldreader.com/' : 'https://theoldreader.com/' ) ;
64
86
}
65
87
66
- function findOurTab ( callback , windowId ) {
67
- chrome . tabs . query (
88
+ async function findOurTab ( windowId ) {
89
+ const tabs = await chrome . tabs . query (
68
90
{
69
91
url : "*://theoldreader.com/*" ,
70
92
windowId : windowId
71
- } ,
72
- function ( tabs ) {
73
- callback ( tabs [ 0 ] ) ;
74
93
}
75
94
) ;
95
+
96
+ return tabs [ 0 ] ;
76
97
}
77
98
78
- function openOurTab ( windowId ) {
79
- findOurTab ( function ( tab ) {
80
- if ( tab ) {
81
- chrome . tabs . update ( tab . id , { active : true } ) ;
82
- } else {
83
- let url = baseUrl ( ) ;
84
- const pinned = ( localStorage . prefer_pinned_tab == 'yes' ? true : false ) ;
85
- if ( localStorage . click_page == 'all_items' ) { url += 'posts/all' ; }
86
- chrome . tabs . create ( { url : url , pinned : pinned , windowId : windowId } ) ;
87
- }
88
- } , windowId ) ;
99
+ export async function openOurTab ( windowId ) {
100
+ const maybeTab = await findOurTab ( windowId ) ;
101
+
102
+ if ( maybeTab ) {
103
+ browser . tabs . update ( maybeTab . id , { active : true } ) ;
104
+ } else {
105
+ let url = baseUrl ( ) ;
106
+ const pinned = ( localStorage . prefer_pinned_tab == 'yes' ? true : false ) ;
107
+ if ( localStorage . click_page == 'all_items' ) { url += 'posts/all' ; }
108
+ browser . tabs . create ( { url : url , pinned : pinned , windowId : windowId } ) ;
109
+ }
89
110
}
90
111
91
112
function reportError ( details ) {
92
113
console . warn ( details . errorText ) ;
93
114
94
- chrome . browserAction . setIcon ( {
115
+ browser . action . setIcon ( {
95
116
path : {
96
117
19 : 'img/icon-inactive.png' ,
97
118
38 : 'img/icon-inactive-scale2.png'
98
119
}
99
120
} ) ;
100
121
101
122
if ( details . loggedOut ) {
102
- chrome . browserAction . setBadgeText ( { text : '!' } ) ;
103
- chrome . browserAction . setTitle ( { title : chrome . i18n . getMessage ( 'button_title_loggedOut' ) } ) ;
123
+ browser . action . setBadgeText ( { text : '!' } ) ;
124
+ browser . action . setTitle ( { title : browser . i18n . getMessage ( 'button_title_loggedOut' ) } ) ;
104
125
if ( lastError != details . errorText ) { // Suppress repeat notifications about the same error
105
- showNotification ( chrome . i18n . getMessage ( 'notification_loggedOut_title' ) , chrome . i18n . getMessage ( 'notification_loggedOut_body' ) ) ;
126
+ showNotification ( browser . i18n . getMessage ( 'notification_loggedOut_title' ) , browser . i18n . getMessage ( 'notification_loggedOut_body' ) ) ;
106
127
}
107
128
} else {
108
- chrome . browserAction . setBadgeText ( { text : '' } ) ;
109
- chrome . browserAction . setTitle ( { title : chrome . i18n . getMessage ( 'button_title_fetchError' ) } ) ;
129
+ browser . action . setBadgeText ( { text : '' } ) ;
130
+ browser . action . setTitle ( { title : browser . i18n . getMessage ( 'button_title_fetchError' ) } ) ;
110
131
if ( lastError != details . errorText ) { // Suppress repeat notifications about the same error
111
- showNotification ( chrome . i18n . getMessage ( 'notification_fetchError_title' ) , chrome . i18n . getMessage ( 'notification_fetchError_body' ) + details . errorText ) ;
132
+ showNotification ( browser . i18n . getMessage ( 'notification_fetchError_title' ) , browser . i18n . getMessage ( 'notification_fetchError_body' ) + details . errorText ) ;
112
133
}
113
134
}
114
135
@@ -128,29 +149,29 @@ function updateIcon(count) {
128
149
} else {
129
150
count = countInt . toString ( ) ;
130
151
}
131
- chrome . browserAction . setIcon ( {
152
+ browser . action . setIcon ( {
132
153
path : {
133
154
19 : 'img/icon-active.png' ,
134
155
38 : 'img/icon-active-scale2.png'
135
156
}
136
157
} ) ;
137
- chrome . browserAction . setBadgeBackgroundColor ( { color : BADGE_BACKGROUND_COLOR } ) ;
138
- if ( typeof ( chrome . browserAction . setBadgeTextColor ) === "function" ) {
139
- chrome . browserAction . setBadgeTextColor ( { color : BADGE_TEXT_COLOR } ) ;
140
- }
141
- chrome . browserAction . setBadgeText ( { text : count } ) ;
142
- chrome . browserAction . setTitle ( { title : 'The Old Reader' + title_suffix } ) ;
158
+
159
+ browser . action . setBadgeBackgroundColor ( { color : BADGE_BACKGROUND_COLOR } ) ;
160
+ // Not supported in Firefox
161
+ browser . action . setBadgeTextColor ?. ( { color : BADGE_TEXT_COLOR } ) ;
162
+ browser . action . setBadgeText ( { text : count } ) ;
163
+ browser . action . setTitle ( { title : 'The Old Reader' + title_suffix } ) ;
143
164
144
165
lastError = "" ; // Clear last remembered error
145
166
146
167
if ( countInt > last_unread_count ) {
147
168
const text = 'You have ' + countInt + ' unread post' + ( countInt > 1 ? 's' : '' ) + '.' ;
148
- showNotification ( chrome . i18n . getMessage ( 'notification_newPosts_title' ) , text ) ;
169
+ showNotification ( browser . i18n . getMessage ( 'notification_newPosts_title' ) , text ) ;
149
170
}
150
171
last_unread_count = countInt ;
151
172
}
152
173
153
- function getCountersFromHTTP ( ) {
174
+ export function getCountersFromHTTP ( ) {
154
175
// If request times out or if we get unexpected output, report error and reschedule
155
176
function refreshFailed ( details ) {
156
177
window . clearTimeout ( requestTimeout ) ;
@@ -210,17 +231,28 @@ function getCountersFromHTTP() {
210
231
}
211
232
212
233
function scheduleRefresh ( ) {
213
- let interval = ( localStorage . refresh_interval || 15 ) * 60 * 1000 ;
214
- window . clearTimeout ( refreshTimeout ) ;
234
+ let intervalMinutes = Number ( localStorage . refresh_interval ) || 15 ;
235
+
215
236
if ( retryCount ) { // There was an error
216
- interval = Math . min ( interval , 5 * 1000 * Math . pow ( 2 , retryCount - 1 ) ) ;
217
- // 0:05 -> 0:10 -> 0:20 -> 0:40 -> 1:20 -> 2:40 -> 5:20 -> ...
237
+ intervalMinutes = Math . min ( intervalMinutes , 0.5 * Math . pow ( 2 , retryCount - 1 ) ) ;
238
+ // 0.5m -> 1m -> 2m -> 4m -> 8m -> 16m -> ...
218
239
}
219
- refreshTimeout = window . setTimeout ( getCountersFromHTTP , interval ) ;
240
+
241
+ console . debug ( `Scheduled refresh for ${ intervalMinutes } minutes` ) ;
242
+
243
+ browser . alarms . clear ( "server-refresh" ) ;
244
+
245
+ browser . alarms . create (
246
+ "server-refresh" ,
247
+ {
248
+ delayInMinutes : intervalMinutes
249
+ }
250
+ ) ;
220
251
}
221
252
222
- /* exported onMessage */
223
- function onMessage ( request , sender , callback ) {
253
+ export function onMessage ( request , sender , callback ) {
254
+ console . debug ( request ) ;
255
+
224
256
if ( typeof request . count !== 'undefined' ) {
225
257
setCountFromObserver ( request . count ) ;
226
258
}
@@ -232,45 +264,35 @@ function onMessage(request, sender, callback) {
232
264
toggleContentMenus ( localStorage . context_menu ) ;
233
265
}
234
266
if ( request . openInBackground ) {
235
- chrome . tabs . create ( {
267
+ browser . tabs . create ( {
236
268
url : request . url ,
237
269
active : false
238
270
} ) ;
239
271
}
240
- if ( request . type == 'close-this-tab' && typeof sender . tab !== 'undefined' ) {
241
- chrome . tabs . remove ( sender . tab . id ) ;
242
- }
243
272
}
244
273
245
274
function setCountFromObserver ( count ) {
246
275
updateIcon ( count ) ;
247
276
scheduleRefresh ( ) ;
248
277
}
249
278
250
- /* exported onExtensionUpdate */
251
- function onExtensionUpdate ( details ) {
279
+ export function onExtensionUpdate ( details ) {
252
280
if ( details . reason == "update" && localStorage . options_version < OPTIONS_VERSION ) {
253
281
showNotification (
254
- chrome . i18n . getMessage ( 'notification_newOptions_title' ) ,
255
- chrome . i18n . getMessage ( 'notification_newOptions_body' ) ,
282
+ browser . i18n . getMessage ( 'notification_newOptions_title' ) ,
283
+ browser . i18n . getMessage ( 'notification_newOptions_body' ) ,
256
284
"theoldreader-newOptions"
257
285
) ;
258
286
}
259
287
localStorage . options_version = OPTIONS_VERSION ;
260
288
saveToStorage ( ) ;
261
289
}
262
290
263
- /* exported startupInject */
264
- function startupInject ( ) {
291
+ export async function startupInject ( ) {
265
292
// At this point, all old content scripts, if any, cannot communicate with the extension anymore
266
293
// Old instances of content scripts have a "kill-switch" to terminate their event listeners
267
294
// Here we inject new instances in existing tabs
268
- chrome . tabs . query (
269
- { url : "*://theoldreader.com/*" } ,
270
- function ( tabs ) {
271
- for ( let tab of tabs ) {
272
- chrome . tabs . executeScript ( tab . id , { file : "js/observer.js" } ) ;
273
- }
274
- }
275
- ) ;
295
+ for await ( const tab of browser . tabs . query ( { url : "*://theoldreader.com/*" } ) ) {
296
+ await browser . scripting . executeScript ( { files : [ "js/observer.js" ] , target : { tabId : tab . id } } ) ;
297
+ }
276
298
}
0 commit comments