@@ -2,7 +2,6 @@ import $ from 'jquery';
2
2
import prettyMilliseconds from 'pretty-ms' ;
3
3
4
4
const { appSubUrl, csrfToken, notificationSettings, enableTimeTracking} = window . config ;
5
- let updateTimeInterval = null ; // holds setInterval id when active
6
5
7
6
export function initStopwatch ( ) {
8
7
if ( ! enableTimeTracking ) {
@@ -26,28 +25,48 @@ export function initStopwatch() {
26
25
$ ( this ) . parent ( ) . trigger ( 'submit' ) ;
27
26
} ) ;
28
27
29
- if ( notificationSettings . EventSourceUpdateTime > 0 && ! ! window . EventSource && window . SharedWorker ) {
28
+ // global stop watch (in the head_navbar), it should always work in any case either the EventSource or the TimerPoller is used.
29
+ const currSeconds = $ ( '.stopwatch-time' ) . attr ( 'data-seconds' ) ;
30
+ if ( currSeconds ) {
31
+ updateStopwatchTime ( currSeconds ) ;
32
+ }
33
+
34
+ let usingPeriodicPoller = false ;
35
+ // poll the stopwatch status periodically
36
+ const startPeriodicPoller = ( timeout ) => {
37
+ if ( timeout <= 0 || ! Number . isFinite ( timeout ) ) return ;
38
+ usingPeriodicPoller = true ;
39
+ setTimeout ( async ( ) => {
40
+ await updateStopwatchWithCallback ( startPeriodicPoller , timeout ) ;
41
+ } , timeout ) ;
42
+ } ;
43
+
44
+ // if the browser supports EventSource and SharedWorker, use it instead of the periodic poller
45
+ if ( notificationSettings . EventSourceUpdateTime > 0 && window . EventSource && window . SharedWorker ) {
30
46
// Try to connect to the event source via the shared worker first
31
47
const worker = new SharedWorker ( `${ __webpack_public_path__ } js/eventsource.sharedworker.js` , 'notification-worker' ) ;
32
48
worker . addEventListener ( 'error' , ( event ) => {
33
- console . error ( event ) ;
49
+ console . error ( 'worker error' , event ) ;
34
50
} ) ;
35
51
worker . port . addEventListener ( 'messageerror' , ( ) => {
36
- console . error ( 'Unable to deserialize message' ) ;
52
+ console . error ( 'unable to deserialize message' ) ;
37
53
} ) ;
38
54
worker . port . postMessage ( {
39
55
type : 'start' ,
40
56
url : `${ window . location . origin } ${ appSubUrl } /user/events` ,
41
57
} ) ;
42
58
worker . port . addEventListener ( 'message' , ( event ) => {
43
59
if ( ! event . data || ! event . data . type ) {
44
- console . error ( event ) ;
60
+ console . error ( 'unknown worker message event' , event ) ;
45
61
return ;
46
62
}
47
63
if ( event . data . type === 'stopwatches' ) {
48
64
updateStopwatchData ( JSON . parse ( event . data . data ) ) ;
65
+ } else if ( event . data . type === 'no-event-source' ) {
66
+ console . error ( `browser doesn't support EventSource, falling back to periodic poller` ) ;
67
+ if ( ! usingPeriodicPoller ) startPeriodicPoller ( notificationSettings . MinTimeout ) ;
49
68
} else if ( event . data . type === 'error' ) {
50
- console . error ( event . data ) ;
69
+ console . error ( 'worker port event error' , event . data ) ;
51
70
} else if ( event . data . type === 'logout' ) {
52
71
if ( event . data . data !== 'here' ) {
53
72
return ;
@@ -65,7 +84,7 @@ export function initStopwatch() {
65
84
}
66
85
} ) ;
67
86
worker . port . addEventListener ( 'error' , ( e ) => {
68
- console . error ( e ) ;
87
+ console . error ( 'worker port error' , e ) ;
69
88
} ) ;
70
89
worker . port . start ( ) ;
71
90
window . addEventListener ( 'beforeunload' , ( ) => {
@@ -78,22 +97,7 @@ export function initStopwatch() {
78
97
return ;
79
98
}
80
99
81
- if ( notificationSettings . MinTimeout <= 0 ) {
82
- return ;
83
- }
84
-
85
- const fn = ( timeout ) => {
86
- setTimeout ( ( ) => {
87
- const _promise = updateStopwatchWithCallback ( fn , timeout ) ;
88
- } , timeout ) ;
89
- } ;
90
-
91
- fn ( notificationSettings . MinTimeout ) ;
92
-
93
- const currSeconds = $ ( '.stopwatch-time' ) . data ( 'seconds' ) ;
94
- if ( currSeconds ) {
95
- updateTimeInterval = updateStopwatchTime ( currSeconds ) ;
96
- }
100
+ startPeriodicPoller ( notificationSettings . MinTimeout ) ;
97
101
}
98
102
99
103
async function updateStopwatchWithCallback ( callback , timeout ) {
@@ -114,23 +118,14 @@ async function updateStopwatch() {
114
118
url : `${ appSubUrl } /user/stopwatches` ,
115
119
headers : { 'X-Csrf-Token' : csrfToken } ,
116
120
} ) ;
117
-
118
- if ( updateTimeInterval ) {
119
- clearInterval ( updateTimeInterval ) ;
120
- updateTimeInterval = null ;
121
- }
122
-
123
121
return updateStopwatchData ( data ) ;
124
122
}
125
123
126
124
function updateStopwatchData ( data ) {
127
125
const watch = data [ 0 ] ;
128
126
const btnEl = $ ( '.active-stopwatch-trigger' ) ;
129
127
if ( ! watch ) {
130
- if ( updateTimeInterval ) {
131
- clearInterval ( updateTimeInterval ) ;
132
- updateTimeInterval = null ;
133
- }
128
+ clearStopwatchTimer ( ) ;
134
129
btnEl . addClass ( 'hidden' ) ;
135
130
} else {
136
131
const { repo_owner_name, repo_name, issue_index, seconds} = watch ;
@@ -139,22 +134,32 @@ function updateStopwatchData(data) {
139
134
$ ( '.stopwatch-commit' ) . attr ( 'action' , `${ issueUrl } /times/stopwatch/toggle` ) ;
140
135
$ ( '.stopwatch-cancel' ) . attr ( 'action' , `${ issueUrl } /times/stopwatch/cancel` ) ;
141
136
$ ( '.stopwatch-issue' ) . text ( `${ repo_owner_name } /${ repo_name } #${ issue_index } ` ) ;
142
- $ ( '.stopwatch-time' ) . text ( prettyMilliseconds ( seconds * 1000 ) ) ;
143
- updateTimeInterval = updateStopwatchTime ( seconds ) ;
137
+ updateStopwatchTime ( seconds ) ;
144
138
btnEl . removeClass ( 'hidden' ) ;
145
139
}
146
-
147
140
return ! ! data . length ;
148
141
}
149
142
143
+ let updateTimeIntervalId = null ; // holds setInterval id when active
144
+ function clearStopwatchTimer ( ) {
145
+ if ( updateTimeIntervalId !== null ) {
146
+ clearInterval ( updateTimeIntervalId ) ;
147
+ updateTimeIntervalId = null ;
148
+ }
149
+ }
150
150
function updateStopwatchTime ( seconds ) {
151
151
const secs = parseInt ( seconds ) ;
152
- if ( ! Number . isFinite ( secs ) ) return null ;
153
-
152
+ if ( ! Number . isFinite ( secs ) ) {
153
+ return ;
154
+ }
155
+ clearStopwatchTimer ( ) ;
156
+ const $stopwatch = $ ( '.stopwatch-time' ) ;
154
157
const start = Date . now ( ) ;
155
- return setInterval ( ( ) => {
158
+ const updateUi = ( ) => {
156
159
const delta = Date . now ( ) - start ;
157
160
const dur = prettyMilliseconds ( secs * 1000 + delta , { compact : true } ) ;
158
- $ ( '.stopwatch-time' ) . text ( dur ) ;
159
- } , 1000 ) ;
161
+ $stopwatch . text ( dur ) ;
162
+ } ;
163
+ updateUi ( ) ;
164
+ updateTimeIntervalId = setInterval ( updateUi , 1000 ) ;
160
165
}
0 commit comments