@@ -18,28 +18,8 @@ function extractPageMapData() {
1818
1919 // ── XPath generator ──────────────────────────────────────────────────────
2020 function getXPath ( el ) {
21- if ( el . id ) return `//*[@id="${ el . id } "]` ;
22- const stableAttrs = [ 'name' , 'data-testid' , 'aria-label' , 'placeholder' ] ;
23- for ( const attr of stableAttrs ) {
24- const val = el . getAttribute ( attr ) ;
25- if ( val ) {
26- const tag = el . tagName . toLowerCase ( ) ;
27- try {
28- if ( document . querySelectorAll ( `${ tag } [${ attr } ="${ CSS . escape ( val ) } "]` ) . length === 1 )
29- return `//${ tag } [@${ attr } ="${ val } "]` ;
30- } catch ( e ) {
31- // Ignore escaping errors
32- }
33- }
34- }
35- if ( [ 'BUTTON' , 'A' ] . includes ( el . tagName ) ) {
36- const txt = el . innerText . trim ( ) . slice ( 0 , 60 ) ;
37- if ( txt ) {
38- const tag = el . tagName . toLowerCase ( ) ;
39- const hits = [ ...document . querySelectorAll ( tag ) ] . filter ( e => e . innerText . trim ( ) . startsWith ( txt ) ) ;
40- if ( hits . length === 1 ) return `//${ tag } [normalize-space()="${ txt } "]` ;
41- }
42- }
21+ // Always return full absolute xpath from document root.
22+ // This keeps page_map_json xpaths deterministic and directly resolvable later.
4323 function pos ( e ) {
4424 const tag = e . tagName . toLowerCase ( ) ;
4525 const sibs = [ ...e . parentNode . children ] . filter ( c => c . tagName === e . tagName ) ;
@@ -121,6 +101,9 @@ function extractPageMapData() {
121101 _type : 'action' ,
122102 _el : el ,
123103 _order : domOrderMap . get ( el ) || 0 ,
104+ attributes : Object . fromEntries (
105+ [ ...el . attributes ] . map ( attr => [ attr . name , attr . value ] )
106+ ) ,
124107 tag : el . tagName . toLowerCase ( ) ,
125108 type : el . getAttribute ( 'type' ) || null ,
126109 role : el . getAttribute ( 'role' ) || el . tagName . toLowerCase ( ) ,
0 commit comments