1
- import getSelector from './get-selector' ;
2
1
import getAncestry from './get-ancestry' ;
3
2
import getXpath from './get-xpath' ;
4
3
import getNodeFromTree from './get-node-from-tree' ;
@@ -7,30 +6,80 @@ import cache from '../base/cache';
7
6
8
7
const CACHE_KEY = 'DqElm.RunOptions' ;
9
8
10
- function truncate ( str , maxLength ) {
11
- maxLength = maxLength || 300 ;
9
+ function getFullPathSelector ( elm ) {
10
+ if ( elm . nodeName === 'BODY' ) {
11
+ return 'BODY' ;
12
+ }
13
+
14
+ if ( cache . get ( 'getFullPathSelector' ) === undefined ) {
15
+ cache . set ( 'getFullPathSelector' , new WeakMap ( ) ) ;
16
+ }
12
17
13
- if ( str . length > maxLength ) {
14
- var index = str . indexOf ( '>' ) ;
15
- str = str . substring ( 0 , index + 1 ) ;
18
+ // Check cache first
19
+ const sourceCache = cache . get ( 'getFullPathSelector' ) ;
20
+ if ( sourceCache . has ( elm ) ) {
21
+ return sourceCache . get ( elm ) ;
16
22
}
17
23
18
- return str ;
24
+ const element = elm ;
25
+ const names = [ ] ;
26
+ while ( elm . parentElement && elm . nodeName !== 'BODY' ) {
27
+ if ( elm . id ) {
28
+ names . unshift ( '#' + elm . getAttribute ( 'id' ) ) ;
29
+ break ;
30
+ } else {
31
+ let c = 1 ,
32
+ e = elm ;
33
+ for ( ; e . previousElementSibling ; e = e . previousElementSibling , c ++ ) { }
34
+ names . unshift ( elm . nodeName + ':nth-child(' + c + ')' ) ;
35
+ }
36
+ elm = elm . parentElement ;
37
+ }
38
+
39
+ const selector = names . join ( '>' ) ;
40
+ sourceCache . set ( element , selector ) ;
41
+ return selector ;
19
42
}
20
43
21
44
function getSource ( element ) {
22
- if ( ! element ?. outerHTML ) {
45
+ if ( ! element ) {
23
46
return '' ;
24
47
}
25
- var source = element . outerHTML ;
26
- if ( ! source && typeof window . XMLSerializer === 'function' ) {
27
- source = new window . XMLSerializer ( ) . serializeToString ( element ) ;
48
+
49
+ // Initialize cache if needed
50
+ if ( cache . get ( 'getSourceEfficient' ) === undefined ) {
51
+ cache . set ( 'getSourceEfficient' , new WeakMap ( ) ) ;
52
+ }
53
+
54
+ // Check cache first
55
+ const sourceCache = cache . get ( 'getSourceEfficient' ) ;
56
+ if ( sourceCache . has ( element ) ) {
57
+ return sourceCache . get ( element ) ;
28
58
}
29
- let htmlString = truncate ( source || '' ) ;
30
- // Remove unwanted attributes
31
- const regex = / \s * d a t a - p e r c y - [ ^ = ] + = " [ ^ " ] * " / g;
32
- htmlString = htmlString . replace ( regex , '' ) ;
33
- return htmlString ;
59
+
60
+ // Compute value if not cached
61
+ const tagName = element . nodeName ?. toLowerCase ( ) ;
62
+ if ( ! tagName ) {
63
+ return '' ;
64
+ }
65
+
66
+ let result ;
67
+ try {
68
+ const attributes = Array . from ( element . attributes || [ ] )
69
+ . filter ( attr => ! attr . name . startsWith ( 'data-percy-' ) )
70
+ . map ( attr => `${ attr . name } ="${ attr . value } "` )
71
+ . join ( ' ' ) ;
72
+
73
+ result = attributes ? `<${ tagName } ${ attributes } >` : `<${ tagName } >` ;
74
+
75
+ // Store in cache
76
+ sourceCache . set ( element , result ) ;
77
+ } catch ( e ) {
78
+ // Handle potential errors (like accessing attributes on non-element nodes)
79
+ result = `<${ tagName || 'unknown' } >` ;
80
+ }
81
+
82
+ return result ;
34
83
}
35
84
36
85
/**
@@ -94,7 +143,9 @@ DqElement.prototype = {
94
143
* @return {String }
95
144
*/
96
145
get selector ( ) {
97
- return this . spec . selector || [ getSelector ( this . element , this . _options ) ] ;
146
+ return (
147
+ this . spec . selector || [ getFullPathSelector ( this . element , this . _options ) ]
148
+ ) ;
98
149
} ,
99
150
100
151
/**
0 commit comments