@@ -33,10 +33,11 @@ function selectorForValue(val: number | string): string {
33
33
export function setDataForNode (
34
34
node : HTMLElement | Node ,
35
35
nodeHash : string ,
36
- setToParentNode = false ,
36
+ setToParentNode : boolean , // should be false for default
37
+ currentWindow : typeof window ,
37
38
) : string {
38
39
const taskId = taskIdKey ;
39
- if ( ! ( node instanceof Element ) ) {
40
+ if ( ! ( node instanceof currentWindow . HTMLElement ) ) {
40
41
return '' ;
41
42
}
42
43
if ( ! taskId ) {
@@ -47,7 +48,7 @@ export function setDataForNode(
47
48
const selector = selectorForValue ( nodeHash ) ;
48
49
if ( getDebugMode ( ) ) {
49
50
if ( setToParentNode ) {
50
- if ( node . parentNode instanceof HTMLElement ) {
51
+ if ( node . parentNode instanceof currentWindow . HTMLElement ) {
51
52
node . parentNode . setAttribute ( taskIdKey , nodeHash . toString ( ) ) ;
52
53
}
53
54
} else {
@@ -57,17 +58,25 @@ export function setDataForNode(
57
58
return selector ;
58
59
}
59
60
60
- function isElementPartiallyInViewport ( rect : ReturnType < typeof getRect > ) {
61
+ function isElementPartiallyInViewport (
62
+ rect : ReturnType < typeof getRect > ,
63
+ currentWindow : typeof window ,
64
+ currentDocument : typeof document ,
65
+ ) {
61
66
const elementHeight = rect . height ;
62
67
const elementWidth = rect . width ;
63
68
64
69
const viewportRect = {
65
70
left : 0 ,
66
71
top : 0 ,
67
- width : window . innerWidth || document . documentElement . clientWidth ,
68
- height : window . innerHeight || document . documentElement . clientHeight ,
69
- right : window . innerWidth || document . documentElement . clientWidth ,
70
- bottom : window . innerHeight || document . documentElement . clientHeight ,
72
+ width :
73
+ currentWindow . innerWidth || currentDocument . documentElement . clientWidth ,
74
+ height :
75
+ currentWindow . innerHeight || currentDocument . documentElement . clientHeight ,
76
+ right :
77
+ currentWindow . innerWidth || currentDocument . documentElement . clientWidth ,
78
+ bottom :
79
+ currentWindow . innerHeight || currentDocument . documentElement . clientHeight ,
71
80
x : 0 ,
72
81
y : 0 ,
73
82
zoom : 1 ,
@@ -84,17 +93,20 @@ function isElementPartiallyInViewport(rect: ReturnType<typeof getRect>) {
84
93
return visibleArea / totalArea >= 2 / 3 ;
85
94
}
86
95
87
- export function getPseudoElementContent ( element : Node ) : {
96
+ export function getPseudoElementContent (
97
+ element : Node ,
98
+ currentWindow : typeof window ,
99
+ ) : {
88
100
before : string ;
89
101
after : string ;
90
102
} {
91
- if ( ! ( element instanceof HTMLElement ) ) {
103
+ if ( ! ( element instanceof currentWindow . HTMLElement ) ) {
92
104
return { before : '' , after : '' } ;
93
105
}
94
- const beforeContent = window
106
+ const beforeContent = currentWindow
95
107
. getComputedStyle ( element , '::before' )
96
108
. getPropertyValue ( 'content' ) ;
97
- const afterContent = window
109
+ const afterContent = currentWindow
98
110
. getComputedStyle ( element , '::after' )
99
111
. getPropertyValue ( 'content' ) ;
100
112
return {
@@ -103,8 +115,11 @@ export function getPseudoElementContent(element: Node): {
103
115
} ;
104
116
}
105
117
106
- export function hasOverflowY ( element : HTMLElement ) : boolean {
107
- const style = window . getComputedStyle ( element ) ;
118
+ export function hasOverflowY (
119
+ element : HTMLElement ,
120
+ currentWindow : typeof window ,
121
+ ) : boolean {
122
+ const style = currentWindow . getComputedStyle ( element ) ;
108
123
return (
109
124
style . overflowY === 'scroll' ||
110
125
style . overflowY === 'auto' ||
@@ -149,18 +164,22 @@ export function overlappedRect(
149
164
return null ;
150
165
}
151
166
152
- export function getRect ( el : HTMLElement | Node , baseZoom = 1 ) : ExtractedRect {
167
+ export function getRect (
168
+ el : HTMLElement | Node ,
169
+ baseZoom : number , // base zoom
170
+ currentWindow : typeof window ,
171
+ ) : ExtractedRect {
153
172
let originalRect : DOMRect ;
154
173
let newZoom = 1 ;
155
- if ( ! ( el instanceof HTMLElement ) ) {
156
- const range = document . createRange ( ) ;
174
+ if ( ! ( el instanceof currentWindow . HTMLElement ) ) {
175
+ const range = currentWindow . document . createRange ( ) ;
157
176
range . selectNodeContents ( el ) ;
158
177
originalRect = range . getBoundingClientRect ( ) ;
159
178
} else {
160
179
originalRect = el . getBoundingClientRect ( ) ;
161
180
// from Chrome v128, the API would return differently https://docs.google.com/document/d/1AcnDShjT-kEuRaMchZPm5uaIgNZ4OiYtM4JI9qiV8Po/edit
162
181
if ( ! ( 'currentCSSZoom' in el ) ) {
163
- newZoom = Number . parseFloat ( window . getComputedStyle ( el ) . zoom ) || 1 ;
182
+ newZoom = Number . parseFloat ( currentWindow . getComputedStyle ( el ) . zoom ) || 1 ;
164
183
}
165
184
}
166
185
@@ -179,13 +198,17 @@ export function getRect(el: HTMLElement | Node, baseZoom = 1): ExtractedRect {
179
198
} ;
180
199
}
181
200
182
- const isElementCovered = ( el : HTMLElement | Node , rect : ExtractedRect ) => {
201
+ const isElementCovered = (
202
+ el : HTMLElement | Node ,
203
+ rect : ExtractedRect ,
204
+ currentWindow : typeof window ,
205
+ ) => {
183
206
// Gets the center coordinates of the element
184
207
const x = rect . left + rect . width / 2 ;
185
208
const y = rect . top + rect . height / 2 ;
186
209
187
210
// Gets the element above that point
188
- const topElement = document . elementFromPoint ( x , y ) ;
211
+ const topElement = currentWindow . document . elementFromPoint ( x , y ) ;
189
212
if ( ! topElement ) {
190
213
return false ; // usually because it's outside the screen
191
214
}
@@ -201,7 +224,7 @@ const isElementCovered = (el: HTMLElement | Node, rect: ExtractedRect) => {
201
224
return false ;
202
225
}
203
226
204
- const rectOfTopElement = getRect ( topElement as HTMLElement , 1 ) ;
227
+ const rectOfTopElement = getRect ( topElement as HTMLElement , 1 , currentWindow ) ;
205
228
206
229
// get the remaining area of the base element
207
230
const overlapRect = overlappedRect ( rect , rectOfTopElement ) ;
@@ -232,6 +255,8 @@ const isElementCovered = (el: HTMLElement | Node, rect: ExtractedRect) => {
232
255
233
256
export function visibleRect (
234
257
el : HTMLElement | Node | null ,
258
+ currentWindow : typeof window ,
259
+ currentDocument : typeof document ,
235
260
baseZoom = 1 ,
236
261
) :
237
262
| { left : number ; top : number ; width : number ; height : number ; zoom : number }
@@ -242,16 +267,16 @@ export function visibleRect(
242
267
}
243
268
244
269
if (
245
- ! ( el instanceof HTMLElement ) &&
270
+ ! ( el instanceof currentWindow . HTMLElement ) &&
246
271
el . nodeType !== Node . TEXT_NODE &&
247
272
el . nodeName . toLowerCase ( ) !== 'svg'
248
273
) {
249
274
logger ( el , 'Element is not in the DOM hierarchy' ) ;
250
275
return false ;
251
276
}
252
277
253
- if ( el instanceof HTMLElement ) {
254
- const style = window . getComputedStyle ( el ) ;
278
+ if ( el instanceof currentWindow . HTMLElement ) {
279
+ const style = currentWindow . getComputedStyle ( el ) ;
255
280
if (
256
281
style . display === 'none' ||
257
282
style . visibility === 'hidden' ||
@@ -262,7 +287,7 @@ export function visibleRect(
262
287
}
263
288
}
264
289
265
- const rect = getRect ( el , baseZoom ) ;
290
+ const rect = getRect ( el , baseZoom , currentWindow ) ;
266
291
267
292
if ( rect . width === 0 && rect . height === 0 ) {
268
293
logger ( el , 'Element has no size' ) ;
@@ -271,18 +296,24 @@ export function visibleRect(
271
296
272
297
// check if the element is covered by another element
273
298
// if the element is zoomed, the coverage check should be done with the original zoom
274
- if ( baseZoom === 1 && isElementCovered ( el , rect ) ) {
299
+ if ( baseZoom === 1 && isElementCovered ( el , rect , currentWindow ) ) {
275
300
return false ;
276
301
}
277
302
278
- const scrollLeft = window . pageXOffset || document . documentElement . scrollLeft ;
279
- const scrollTop = window . pageYOffset || document . documentElement . scrollTop ;
303
+ const scrollLeft =
304
+ currentWindow . pageXOffset || currentDocument . documentElement . scrollLeft ;
305
+ const scrollTop =
306
+ currentWindow . pageYOffset || currentDocument . documentElement . scrollTop ;
280
307
const viewportWidth =
281
- window . innerWidth || document . documentElement . clientWidth ;
308
+ currentWindow . innerWidth || currentDocument . documentElement . clientWidth ;
282
309
const viewportHeight =
283
- window . innerHeight || document . documentElement . clientHeight ;
310
+ currentWindow . innerHeight || currentDocument . documentElement . clientHeight ;
284
311
285
- const isPartiallyInViewport = isElementPartiallyInViewport ( rect ) ;
312
+ const isPartiallyInViewport = isElementPartiallyInViewport (
313
+ rect ,
314
+ currentWindow ,
315
+ currentDocument ,
316
+ ) ;
286
317
287
318
if ( ! isPartiallyInViewport ) {
288
319
logger ( el , 'Element is completely outside the viewport' , {
@@ -297,14 +328,14 @@ export function visibleRect(
297
328
298
329
// check if the element is hidden by an ancestor
299
330
let parent : HTMLElement | Node | null = el ;
300
- while ( parent && parent !== document . body ) {
301
- if ( ! ( parent instanceof HTMLElement ) ) {
331
+ while ( parent && parent !== currentDocument . body ) {
332
+ if ( ! ( parent instanceof currentWindow . HTMLElement ) ) {
302
333
parent = parent . parentElement ;
303
334
continue ;
304
335
}
305
- const parentStyle = window . getComputedStyle ( parent ) ;
336
+ const parentStyle = currentWindow . getComputedStyle ( parent ) ;
306
337
if ( parentStyle . overflow === 'hidden' ) {
307
- const parentRect = getRect ( parent , 1 ) ;
338
+ const parentRect = getRect ( parent , 1 , currentWindow ) ;
308
339
const tolerance = 10 ;
309
340
310
341
if (
@@ -348,23 +379,6 @@ export function validTextNodeContent(node: Node): string | false {
348
379
return false ;
349
380
}
350
381
351
- // const everyChildNodeIsText = Array.from(node.childNodes).every((child) => {
352
- // const tagName = ((child as HTMLElement).tagName || '').toLowerCase();
353
- // if (
354
- // tagName === 'script' ||
355
- // tagName === 'style' ||
356
- // tagName === 'link' ||
357
- // tagName !== '#text'
358
- // ) {
359
- // return false;
360
- // }
361
- // return true;
362
- // });
363
-
364
- // if (!everyChildNodeIsText) {
365
- // return false;
366
- // }
367
-
368
382
const content = node . textContent || ( node as HTMLElement ) . innerText ;
369
383
if ( content && ! / ^ \s * $ / . test ( content ) ) {
370
384
return content . trim ( ) ;
@@ -375,8 +389,13 @@ export function validTextNodeContent(node: Node): string | false {
375
389
376
390
export function getNodeAttributes (
377
391
node : HTMLElement | Node ,
392
+ currentWindow : typeof window ,
378
393
) : Record < string , string > {
379
- if ( ! node || ! ( node instanceof HTMLElement ) || ! node . attributes ) {
394
+ if (
395
+ ! node ||
396
+ ! ( node instanceof currentWindow . HTMLElement ) ||
397
+ ! node . attributes
398
+ ) {
380
399
return { } ;
381
400
}
382
401
@@ -464,7 +483,7 @@ export function setExtractTextWithPositionOnWindow() {
464
483
}
465
484
}
466
485
467
- export function getDocument ( ) : HTMLElement {
486
+ export function getTopDocument ( ) : HTMLElement {
468
487
const container : HTMLElement = document . body || document ;
469
488
return container ;
470
489
}
0 commit comments