@ -16,7 +16,6 @@ try {
}
// Include the getXpath script directly, easier than fetching
function getxpath ( e ) {
var n = e ;
@ -59,14 +58,14 @@ const findUpTag = (el) => {
// Strategy 2: Keep going up until we hit an ID tag, imagine it's like #list-widget div h4
while ( r . parentNode ) {
if ( depth == 5 ) {
if ( depth == = 5 ) {
break ;
}
if ( '' !== r . id ) {
chained _css . unshift ( "#" + CSS . escape ( r . id ) ) ;
final _selector = chained _css . join ( ' > ' ) ;
// Be sure theres only one, some sites have multiples of the same ID tag :-(
if ( window . document . querySelectorAll ( final _selector ) . length == 1 ) {
if ( window . document . querySelectorAll ( final _selector ) . length == = 1 ) {
return final _selector ;
}
return null ;
@ -82,30 +81,60 @@ const findUpTag = (el) => {
// @todo - if it's SVG or IMG, go into image diff mode
// %ELEMENTS% replaced at injection time because different interfaces use it with different settings
var elements = window . document . querySelectorAll ( "%ELEMENTS%" ) ;
var size _pos = [ ] ;
// after page fetch, inject this JS
// build a map of all elements and their positions (maybe that only include text?)
var bbox ;
for ( var i = 0 ; i < elements . length ; i ++ ) {
bbox = elements [ i ] . getBoundingClientRect ( ) ;
console . log ( "Scanning %ELEMENTS%" ) ;
function collectVisibleElements ( parent , visibleElements ) {
if ( ! parent ) return ; // Base case: if parent is null or undefined, return
// Add the parent itself to the visible elements array if it's of the specified types
const tagName = parent . tagName . toLowerCase ( ) ;
if ( "%ELEMENTS%" . split ( ',' ) . includes ( tagName ) ) {
visibleElements . push ( parent ) ;
}
// Exclude items that are not interactable or visible
if ( elements [ i ] . style . opacity === "0" ) {
continue
// Iterate over the parent's children
const children = parent . children ;
for ( let i = 0 ; i < children . length ; i ++ ) {
const child = children [ i ] ;
if (
child . nodeType === Node . ELEMENT _NODE &&
window . getComputedStyle ( child ) . display !== 'none' &&
window . getComputedStyle ( child ) . visibility !== 'hidden' &&
child . offsetWidth >= 0 &&
child . offsetHeight >= 0 &&
window . getComputedStyle ( child ) . contentVisibility !== 'hidden'
) {
// If the child is an element and is visible, recursively collect visible elements
collectVisibleElements ( child , visibleElements ) ;
}
if ( elements [ i ] . style . display === "none" || elements [ i ] . style . pointerEvents === "none" ) {
continue
}
}
// Create an array to hold the visible elements
const visibleElementsArray = [ ] ;
// Call collectVisibleElements with the starting parent element
collectVisibleElements ( document . body , visibleElementsArray ) ;
visibleElementsArray . forEach ( function ( element ) {
bbox = element . getBoundingClientRect ( ) ;
// Skip really small ones, and where width or height ==0
if ( bbox [ 'width' ] * bbox [ 'height' ] < 100 ) {
continue ;
if ( bbox [ 'width' ] * bbox [ 'height' ] < 10 ) {
return
}
// Don't include elements that are offset from canvas
if ( bbox [ 'top' ] + scroll _y < 0 || bbox [ 'left' ] < 0 ) {
continue ;
return
}
// @todo the getXpath kind of sucks, it doesnt know when there is for example just one ID sometimes
@ -114,46 +143,41 @@ for (var i = 0; i < elements.length; i++) {
// 1st primitive - if it has class, try joining it all and select, if theres only one.. well thats us.
xpath _result = false ;
try {
var d = findUpTag ( element s[ i ] ) ;
var d = findUpTag ( element ) ;
if ( d ) {
xpath _result = d ;
}
} catch ( e ) {
console . log ( e ) ;
}
// You could swap it and default to getXpath and then try the smarter one
// default back to the less intelligent one
if ( ! xpath _result ) {
try {
// I've seen on FB and eBay that this doesnt work
// ReferenceError: getXPath is not defined at eval (eval at evaluate (:152:29), <anonymous>:67:20) at UtilityScript.evaluate (<anonymous>:159:18) at UtilityScript.<anonymous> (<anonymous>:1:44)
xpath _result = getxpath ( element s[ i ] ) ;
xpath _result = getxpath ( element ) ;
} catch ( e ) {
console . log ( e ) ;
continue;
return
}
}
if ( window . getComputedStyle ( elements [ i ] ) . visibility === "hidden" ) {
continue ;
}
// @todo Possible to ONLY list where it's clickable to save JSON xfer size
size _pos . push ( {
xpath : xpath _result ,
width : Math . round ( bbox [ 'width' ] ) ,
height : Math . round ( bbox [ 'height' ] ) ,
left : Math . floor ( bbox [ 'left' ] ) ,
top : Math . floor ( bbox [ 'top' ] ) + scroll _y ,
tagName : ( elements [ i ] . tagName ) ? elements [ i ] . tagName . toLowerCase ( ) : '' ,
tagtype : ( elements [ i ] . tagName == 'INPUT' && elements [ i ] . type ) ? elements [ i ] . type . toLowerCase ( ) : '' ,
isClickable : ( elements [ i ] . onclick ) || window . getComputedStyle ( elements [ i ] ) . cursor == "pointer"
tagName : ( element . tagName ) ? element . tagName . toLowerCase ( ) : '' ,
tagtype : ( element . tagName . toLowerCase ( ) === 'input' && element . type ) ? element . type . toLowerCase ( ) : '' ,
isClickable : window . getComputedStyle ( element ) . cursor == "pointer"
} ) ;
} ) ;
}
// Inject the current one set in the include_filters, which may be a CSS rule
// used for displaying the current one in VisualSelector, where its not one we generated.