@@ -36,11 +36,12 @@ function on_click(sel, fn) {
36
36
function getCellValue ( row , column = 0 ) {
37
37
const cell = row . cells [ column ] // nosemgrep: eslint.detect-object-injection
38
38
if ( cell . childElementCount == 1 ) {
39
- const child = cell . firstElementChild
40
- if ( child instanceof HTMLTimeElement && child . dateTime ) {
41
- return child . dateTime
42
- } else if ( child instanceof HTMLDataElement && child . value ) {
43
- return child . value
39
+ var child = cell . firstElementChild ;
40
+ if ( child . tagName === "A" ) {
41
+ child = child . firstElementChild ;
42
+ }
43
+ if ( child instanceof HTMLDataElement && child . value ) {
44
+ return child . value ;
44
45
}
45
46
}
46
47
return cell . innerText || cell . textContent ;
@@ -50,28 +51,37 @@ function rowComparator(rowA, rowB, column = 0) {
50
51
let valueA = getCellValue ( rowA , column ) ;
51
52
let valueB = getCellValue ( rowB , column ) ;
52
53
if ( ! isNaN ( valueA ) && ! isNaN ( valueB ) ) {
53
- return valueA - valueB
54
+ return valueA - valueB ;
54
55
}
55
56
return valueA . localeCompare ( valueB , undefined , { numeric : true } ) ;
56
57
}
57
58
58
59
function sortColumn ( th ) {
59
60
// Get the current sorting direction of the selected header,
60
- // clear state on other headers and then set the new sorting direction
61
+ // clear state on other headers and then set the new sorting direction.
61
62
const currentSortOrder = th . getAttribute ( "aria-sort" ) ;
62
63
[ ...th . parentElement . cells ] . forEach ( header => header . setAttribute ( "aria-sort" , "none" ) ) ;
64
+ var direction ;
63
65
if ( currentSortOrder === "none" ) {
64
- th . setAttribute ( "aria-sort" , th . dataset . defaultSortOrder || "ascending" ) ;
65
- } else {
66
- th . setAttribute ( "aria-sort" , currentSortOrder === "ascending" ? "descending" : "ascending" ) ;
66
+ direction = th . dataset . defaultSortOrder || "ascending" ;
67
+ }
68
+ else if ( currentSortOrder === "ascending" ) {
69
+ direction = "descending" ;
70
+ }
71
+ else {
72
+ direction = "ascending" ;
67
73
}
74
+ th . setAttribute ( "aria-sort" , direction ) ;
68
75
69
76
const column = [ ...th . parentElement . cells ] . indexOf ( th )
70
77
71
- // Sort all rows and afterwards append them in order to move them in the DOM
78
+ // Sort all rows and afterwards append them in order to move them in the DOM.
72
79
Array . from ( th . closest ( "table" ) . querySelectorAll ( "tbody tr" ) )
73
- . sort ( ( rowA , rowB ) => rowComparator ( rowA , rowB , column ) * ( th . getAttribute ( "aria-sort" ) === "ascending" ? 1 : - 1 ) )
74
- . forEach ( tr => tr . parentElement . appendChild ( tr ) ) ;
80
+ . sort ( ( rowA , rowB ) => rowComparator ( rowA , rowB , column ) * ( direction === "ascending" ? 1 : - 1 ) )
81
+ . forEach ( tr => tr . parentElement . appendChild ( tr ) ) ;
82
+
83
+ // Save the sort order for next time.
84
+ localStorage . setItem ( coverage . INDEX_SORT_STORAGE , JSON . stringify ( { column, direction} ) ) ;
75
85
}
76
86
77
87
// Find all the elements with data-shortcut attribute, and use them to assign a shortcut key.
@@ -96,15 +106,40 @@ coverage.wire_up_filter = function () {
96
106
const no_rows = document . getElementById ( "no_rows" ) ;
97
107
98
108
// Observe filter keyevents.
99
- document . getElementById ( "filter" ) . addEventListener ( "input" , debounce ( event => {
109
+ const filter_handler = ( event => {
100
110
// Keep running total of each metric, first index contains number of shown rows
101
111
const totals = new Array ( table . rows [ 0 ] . cells . length ) . fill ( 0 ) ;
102
112
// Accumulate the percentage as fraction
103
113
totals [ totals . length - 1 ] = { "numer" : 0 , "denom" : 0 } ; // nosemgrep: eslint.detect-object-injection
104
114
115
+ var text = document . getElementById ( "filter" ) . value ;
116
+ const casefold = ( text === text . toLowerCase ( ) ) ;
117
+ const hide100 = document . getElementById ( "hide100" ) . checked ;
118
+
105
119
// Hide / show elements.
106
120
table_body_rows . forEach ( row => {
107
- if ( ! row . cells [ 0 ] . textContent . includes ( event . target . value ) ) {
121
+ var show = false ;
122
+ // Check the text filter.
123
+ for ( let column = 0 ; column < totals . length ; column ++ ) {
124
+ cell = row . cells [ column ] ;
125
+ if ( cell . classList . contains ( "name" ) ) {
126
+ var celltext = cell . textContent ;
127
+ if ( casefold ) {
128
+ celltext = celltext . toLowerCase ( ) ;
129
+ }
130
+ if ( celltext . includes ( text ) ) {
131
+ show = true ;
132
+ }
133
+ }
134
+ }
135
+
136
+ // Check the "hide covered" filter.
137
+ if ( show && hide100 ) {
138
+ const [ numer , denom ] = row . cells [ row . cells . length - 1 ] . dataset . ratio . split ( " " ) ;
139
+ show = ( numer !== denom ) ;
140
+ }
141
+
142
+ if ( ! show ) {
108
143
// hide
109
144
row . classList . add ( "hidden" ) ;
110
145
return ;
@@ -114,15 +149,19 @@ coverage.wire_up_filter = function () {
114
149
row . classList . remove ( "hidden" ) ;
115
150
totals [ 0 ] ++ ;
116
151
117
- for ( let column = 1 ; column < totals . length ; column ++ ) {
152
+ for ( let column = 0 ; column < totals . length ; column ++ ) {
118
153
// Accumulate dynamic totals
119
154
cell = row . cells [ column ] // nosemgrep: eslint.detect-object-injection
155
+ if ( cell . classList . contains ( "name" ) ) {
156
+ continue ;
157
+ }
120
158
if ( column === totals . length - 1 ) {
121
159
// Last column contains percentage
122
160
const [ numer , denom ] = cell . dataset . ratio . split ( " " ) ;
123
161
totals [ column ] [ "numer" ] += parseInt ( numer , 10 ) ; // nosemgrep: eslint.detect-object-injection
124
162
totals [ column ] [ "denom" ] += parseInt ( denom , 10 ) ; // nosemgrep: eslint.detect-object-injection
125
- } else {
163
+ }
164
+ else {
126
165
totals [ column ] += parseInt ( cell . textContent , 10 ) ; // nosemgrep: eslint.detect-object-injection
127
166
}
128
167
}
@@ -142,9 +181,12 @@ coverage.wire_up_filter = function () {
142
181
143
182
const footer = table . tFoot . rows [ 0 ] ;
144
183
// Calculate new dynamic sum values based on visible rows.
145
- for ( let column = 1 ; column < totals . length ; column ++ ) {
184
+ for ( let column = 0 ; column < totals . length ; column ++ ) {
146
185
// Get footer cell element.
147
186
const cell = footer . cells [ column ] ; // nosemgrep: eslint.detect-object-injection
187
+ if ( cell . classList . contains ( "name" ) ) {
188
+ continue ;
189
+ }
148
190
149
191
// Set value into dynamic footer cell element.
150
192
if ( column === totals . length - 1 ) {
@@ -158,48 +200,47 @@ coverage.wire_up_filter = function () {
158
200
cell . textContent = denom
159
201
? `${ ( numer * 100 / denom ) . toFixed ( places ) } %`
160
202
: `${ ( 100 ) . toFixed ( places ) } %` ;
161
- } else {
203
+ }
204
+ else {
162
205
cell . textContent = totals [ column ] ; // nosemgrep: eslint.detect-object-injection
163
206
}
164
207
}
165
- } ) ) ;
208
+ } ) ;
209
+
210
+ document . getElementById ( "filter" ) . addEventListener ( "input" , debounce ( filter_handler ) ) ;
211
+ document . getElementById ( "hide100" ) . addEventListener ( "input" , debounce ( filter_handler ) ) ;
166
212
167
213
// Trigger change event on setup, to force filter on page refresh
168
214
// (filter value may still be present).
169
215
document . getElementById ( "filter" ) . dispatchEvent ( new Event ( "input" ) ) ;
216
+ document . getElementById ( "hide100" ) . dispatchEvent ( new Event ( "input" ) ) ;
170
217
} ;
171
218
172
- coverage . INDEX_SORT_STORAGE = "COVERAGE_INDEX_SORT_2" ;
173
-
174
- // Loaded on index.html
175
- coverage . index_ready = function ( ) {
176
- coverage . assign_shortkeys ( ) ;
177
- coverage . wire_up_filter ( ) ;
219
+ // Set up the click-to-sort columns.
220
+ coverage . wire_up_sorting = function ( ) {
178
221
document . querySelectorAll ( "[data-sortable] th[aria-sort]" ) . forEach (
179
222
th => th . addEventListener ( "click" , e => sortColumn ( e . target ) )
180
223
) ;
181
224
182
225
// Look for a localStorage item containing previous sort settings:
226
+ var column = 0 , direction = "ascending" ;
183
227
const stored_list = localStorage . getItem ( coverage . INDEX_SORT_STORAGE ) ;
184
-
185
228
if ( stored_list ) {
186
- const { column, direction} = JSON . parse ( stored_list ) ;
187
- const th = document . querySelector ( "[data-sortable]" ) . tHead . rows [ 0 ] . cells [ column ] ; // nosemgrep: eslint.detect-object-injection
188
- th . setAttribute ( "aria-sort" , direction === "ascending" ? "descending" : "ascending" ) ;
189
- th . click ( )
229
+ ( { column, direction} = JSON . parse ( stored_list ) ) ;
190
230
}
191
231
192
- // Watch for page unload events so we can save the final sort settings:
193
- window . addEventListener ( "unload" , function ( ) {
194
- const th = document . querySelector ( '[data-sortable] th[aria-sort="ascending"], [data-sortable] [aria-sort="descending"]' ) ;
195
- if ( ! th ) {
196
- return ;
197
- }
198
- localStorage . setItem ( coverage . INDEX_SORT_STORAGE , JSON . stringify ( {
199
- column : [ ...th . parentElement . cells ] . indexOf ( th ) ,
200
- direction : th . getAttribute ( "aria-sort" ) ,
201
- } ) ) ;
202
- } ) ;
232
+ const th = document . querySelector ( "[data-sortable]" ) . tHead . rows [ 0 ] . cells [ column ] ; // nosemgrep: eslint.detect-object-injection
233
+ th . setAttribute ( "aria-sort" , direction === "ascending" ? "descending" : "ascending" ) ;
234
+ th . click ( )
235
+ } ;
236
+
237
+ coverage . INDEX_SORT_STORAGE = "COVERAGE_INDEX_SORT_2" ;
238
+
239
+ // Loaded on index.html
240
+ coverage . index_ready = function ( ) {
241
+ coverage . assign_shortkeys ( ) ;
242
+ coverage . wire_up_filter ( ) ;
243
+ coverage . wire_up_sorting ( ) ;
203
244
204
245
on_click ( ".button_prev_file" , coverage . to_prev_file ) ;
205
246
on_click ( ".button_next_file" , coverage . to_next_file ) ;
@@ -217,7 +258,8 @@ coverage.pyfile_ready = function () {
217
258
if ( frag . length > 2 && frag [ 1 ] === "t" ) {
218
259
document . querySelector ( frag ) . closest ( ".n" ) . classList . add ( "highlight" ) ;
219
260
coverage . set_sel ( parseInt ( frag . substr ( 2 ) , 10 ) ) ;
220
- } else {
261
+ }
262
+ else {
221
263
coverage . set_sel ( 0 ) ;
222
264
}
223
265
@@ -441,7 +483,8 @@ coverage.to_next_chunk_nicely = function () {
441
483
if ( line . parentElement !== document . getElementById ( "source" ) ) {
442
484
// The element is not a source line but the header or similar
443
485
coverage . select_line_or_chunk ( 1 ) ;
444
- } else {
486
+ }
487
+ else {
445
488
// We extract the line number from the id
446
489
coverage . select_line_or_chunk ( parseInt ( line . id . substring ( 1 ) , 10 ) ) ;
447
490
}
@@ -460,7 +503,8 @@ coverage.to_prev_chunk_nicely = function () {
460
503
if ( line . parentElement !== document . getElementById ( "source" ) ) {
461
504
// The element is not a source line but the header or similar
462
505
coverage . select_line_or_chunk ( coverage . lines_len ) ;
463
- } else {
506
+ }
507
+ else {
464
508
// We extract the line number from the id
465
509
coverage . select_line_or_chunk ( parseInt ( line . id . substring ( 1 ) , 10 ) ) ;
466
510
}
@@ -562,7 +606,8 @@ coverage.build_scroll_markers = function () {
562
606
if ( line_number === previous_line + 1 ) {
563
607
// If this solid missed block just make previous mark higher.
564
608
last_mark . style . height = `${ line_top + line_height - last_top } px` ;
565
- } else {
609
+ }
610
+ else {
566
611
// Add colored line in scroll_marker block.
567
612
last_mark = document . createElement ( "div" ) ;
568
613
last_mark . id = `m${ line_number } ` ;
@@ -590,7 +635,8 @@ coverage.wire_up_sticky_header = function () {
590
635
function updateHeader ( ) {
591
636
if ( window . scrollY > header_bottom ) {
592
637
header . classList . add ( "sticky" ) ;
593
- } else {
638
+ }
639
+ else {
594
640
header . classList . remove ( "sticky" ) ;
595
641
}
596
642
}
@@ -618,7 +664,8 @@ coverage.expand_contexts = function (e) {
618
664
document . addEventListener ( "DOMContentLoaded" , ( ) => {
619
665
if ( document . body . classList . contains ( "indexfile" ) ) {
620
666
coverage . index_ready ( ) ;
621
- } else {
667
+ }
668
+ else {
622
669
coverage . pyfile_ready ( ) ;
623
670
}
624
671
} ) ;
0 commit comments