@@ -7,8 +7,13 @@ if (!window.CFPredictorInjected) {
7
7
const tbody = document . querySelector ( "tbody" ) ;
8
8
if ( ! tbody ) {
9
9
setTimeout ( setEventListener , 100 ) ;
10
+ return ;
10
11
}
11
12
const trs = tbody . querySelectorAll ( "tr" ) ;
13
+ if ( ! trs ) {
14
+ setTimeout ( setEventListener , 100 ) ;
15
+ return ;
16
+ }
12
17
if ( trs . length <= 1 ) {
13
18
// listen only if there is more than one row
14
19
isListenerActive = false ;
@@ -19,33 +24,54 @@ if (!window.CFPredictorInjected) {
19
24
isListenerActive = false ;
20
25
return ;
21
26
}
27
+ if ( isListenerActive ) return ;
22
28
isListenerActive = true ;
23
- tds [ 1 ] . addEventListener ( "DOMCharacterDataModified" , ( ) => {
29
+ tds [ 1 ] . addEventListener ( "DOMCharacterDataModified" , async ( ) => {
24
30
window . clearTimeout ( predictionsTimer ) ;
25
- predictionsTimer = setTimeout ( fetchPredictions , 1000 ) ;
31
+ predictionsTimer = setTimeout ( fetchPredictions , 500 ) ;
26
32
} ) ;
27
33
} catch ( err ) {
28
34
console . error ( err ) ;
29
35
}
30
36
} ;
31
37
38
+ const isContestRankingPage = ( url ) => {
39
+ return / ^ h t t p s : \/ \/ l e e t c o d e .c o m \/ c o n t e s t \/ .* \/ r a n k i n g / . test ( url ) ;
40
+ } ;
41
+
32
42
let rowsChanged = new Map ( ) ;
33
- let colInserted = false ;
43
+ let deltaTHInserted = false ;
34
44
35
45
const fetchPredictions = async ( ) => {
36
46
const thead = document . querySelector ( "thead" ) ;
37
47
if ( ! thead ) {
38
- predictionsTimer = setTimeout ( fetchPredictions , 100 ) ;
48
+ predictionsTimer = setTimeout ( fetchPredictions , 500 ) ;
39
49
return ;
40
50
}
51
+
41
52
const tbody = document . querySelector ( "tbody" ) ;
53
+ if ( ! tbody ) {
54
+ predictionsTimer = setTimeout ( fetchPredictions , 500 ) ;
55
+ return ;
56
+ }
57
+
42
58
const rows = tbody . querySelectorAll ( "tr" ) ;
43
- const contestId = document
44
- . querySelector ( ".ranking-title-wrapper" )
45
- . querySelector ( "span" )
46
- . querySelector ( "a" )
47
- . innerHTML . toLowerCase ( )
48
- . replace ( / \s / g, "-" ) ;
59
+ if ( ! rows ) {
60
+ predictionsTimer = setTimeout ( fetchPredictions , 500 ) ;
61
+ return ;
62
+ }
63
+ let contestId ;
64
+ try {
65
+ contestId = document
66
+ . querySelector ( ".ranking-title-wrapper" )
67
+ . querySelector ( "span" )
68
+ . querySelector ( "a" )
69
+ . innerHTML . toLowerCase ( )
70
+ . replace ( / \s / g, "-" ) ;
71
+ } catch {
72
+ predictionsTimer = setTimeout ( fetchPredictions , 500 ) ;
73
+ return ;
74
+ }
49
75
const handlesMap = new Map ( ) ;
50
76
51
77
const handles = [ ...rows ] . map ( ( row , index ) => {
@@ -70,90 +96,114 @@ if (!window.CFPredictorInjected) {
70
96
return handle ;
71
97
}
72
98
} catch ( err ) {
73
- console . error ( err ) ;
99
+ console . debug ( err ) ;
74
100
}
75
101
} ) ;
76
102
77
103
chrome . runtime . sendMessage (
78
104
{
79
105
message : "get_predictions" ,
80
- data : { contestId, handles } ,
106
+ data : {
107
+ contestId,
108
+ handles,
109
+ } ,
81
110
} ,
82
111
( response ) => {
83
- if ( response . status === "OK" ) {
84
- if ( ! colInserted ) {
85
- const th = document . createElement ( "th" ) ;
86
- th . innerText = "Δ" ;
87
- thead . querySelector ( "tr" ) . appendChild ( th ) ;
88
- colInserted = true ;
89
- }
90
- const rowsUpdated = new Map ( ) ;
91
- for ( item of response . items ) {
92
- try {
93
- const id = (
94
- item . data_region +
95
- "/" +
96
- item . _id
97
- ) . toLowerCase ( ) ;
98
- if ( handlesMap . has ( id ) ) {
99
- const rowIndex = handlesMap . get ( id ) ;
100
- const row = rows [ rowIndex ] ;
101
- let td ;
102
- if ( rowsChanged . has ( rowIndex ) ) {
103
- td = row . lastChild ;
104
- } else {
105
- td = document . createElement ( "td" ) ;
106
- }
107
- if ( item . delta == null ) {
108
- td . innerText = "?" ;
109
- td . style . color = "gray" ;
110
- } else {
111
- const delta =
112
- Math . round ( item . delta * 100 ) / 100 ;
113
- td . innerText =
114
- delta > 0 ? "+" + delta : delta ;
115
- if ( delta > 0 ) {
116
- td . style . color = "green" ;
112
+ if ( ! response ) {
113
+ return ;
114
+ }
115
+ try {
116
+ if ( response . status === "OK" ) {
117
+ if ( ! deltaTHInserted && response . meta . total_count ) {
118
+ const th = document . createElement ( "th" ) ;
119
+ th . innerText = "Δ" ;
120
+ thead . querySelector ( "tr" ) . appendChild ( th ) ;
121
+ deltaTHInserted = true ;
122
+ }
123
+ const rowsUpdated = new Map ( ) ;
124
+ for ( item of response . items ) {
125
+ try {
126
+ const id = (
127
+ item . data_region +
128
+ "/" +
129
+ item . _id
130
+ ) . toLowerCase ( ) ;
131
+ if ( handlesMap . has ( id ) ) {
132
+ const rowIndex = handlesMap . get ( id ) ;
133
+ const row = rows [ rowIndex ] ;
134
+ let td ;
135
+ if ( rowsChanged . has ( rowIndex ) ) {
136
+ td = row . lastChild ;
117
137
} else {
138
+ td = document . createElement ( "td" ) ;
139
+ }
140
+ if ( item . delta == null ) {
141
+ td . innerText = "?" ;
118
142
td . style . color = "gray" ;
143
+ } else {
144
+ const delta =
145
+ Math . round ( item . delta * 100 ) / 100 ;
146
+ td . innerText =
147
+ delta > 0 ? "+" + delta : delta ;
148
+ if ( delta > 0 ) {
149
+ td . style . color = "green" ;
150
+ } else {
151
+ td . style . color = "gray" ;
152
+ }
153
+ // td.style.fontWeight = "bold";
119
154
}
120
- // td.style.fontWeight = "bold";
121
- }
122
- if ( ! rowsChanged . has ( rowIndex ) ) {
123
- row . appendChild ( td ) ;
155
+ if ( ! rowsChanged . has ( rowIndex ) ) {
156
+ row . appendChild ( td ) ;
157
+ }
158
+ rowsUpdated . set ( rowIndex , true ) ;
124
159
}
125
- rowsUpdated . set ( rowIndex , true ) ;
160
+ } catch ( err ) {
161
+ console . warn ( err ) ;
126
162
}
127
- } catch ( err ) {
128
- console . error ( err ) ;
129
163
}
130
- }
131
- for ( rowIndex of rowsChanged . keys ( ) ) {
132
- if ( ! rowsUpdated . has ( rowIndex ) ) {
133
- try {
134
- const row = rows [ rowIndex ] ;
135
- row . lastChild . innerText = "" ;
136
- } catch ( err ) {
137
- console . error ( err ) ;
164
+ for ( rowIndex of rowsChanged . keys ( ) ) {
165
+ if (
166
+ ! rowsUpdated . has ( rowIndex ) &&
167
+ rowIndex < rows . length
168
+ ) {
169
+ try {
170
+ const row = rows [ rowIndex ] ;
171
+ row . lastChild . innerText = "" ;
172
+ } catch { }
173
+ }
174
+ if ( rowIndex >= rows . length ) {
175
+ rowsChanged . delete ( rowIndex ) ;
138
176
}
139
177
}
178
+ for ( rowIndex of rowsUpdated . keys ( ) ) {
179
+ rowsChanged . set ( rowIndex , true ) ;
180
+ }
140
181
}
141
- for ( rowIndex of rowsUpdated . keys ( ) ) {
142
- rowsChanged . set ( rowIndex , true ) ;
143
- }
182
+ } catch ( err ) {
183
+ console . warn ( err ) ;
144
184
}
145
185
}
146
186
) ;
147
187
} ;
148
- fetchPredictions ( ) ;
149
- setEventListener ( ) ;
150
188
151
- // event listener for "click" event on page-btn class items
152
- [ ...document . querySelectorAll ( ".page-btn" ) ] . forEach ( ( item ) => {
153
- item . addEventListener ( "click" , ( e ) => {
154
- if ( ! isListenerActive ) {
189
+ // listen to url changes
190
+ chrome . runtime . onMessage . addListener ( function (
191
+ request ,
192
+ sender ,
193
+ sendResponse
194
+ ) {
195
+ if ( request . message === "url_updated" ) {
196
+ if ( ! isListenerActive && isContestRankingPage ( request . url ) ) {
197
+ window . clearTimeout ( predictionsTimer ) ;
198
+ predictionsTimer = setTimeout ( fetchPredictions , 500 ) ;
199
+ }
200
+ if ( ! isContestRankingPage ( request . url ) ) {
201
+ isListenerActive = false ;
202
+ rowsChanged . clear ( ) ;
203
+ deltaTHInserted = false ;
204
+ } else {
155
205
setEventListener ( ) ;
156
206
}
157
- } ) ;
207
+ }
158
208
} ) ;
159
209
}
0 commit comments