import { LocatorBuilder , EvaluateFn } from '../types' ; export class VisibleTextLocator implements LocatorBuilder { constructor ( public linkText , public partial = false ) { } get pageFuncArgs ( ) : any [ ] { return [ this . linkText , this . partial ] ; } get pageFunc ( ) : EvaluateFn { return ( targetText , partial = true ) => { const expression = `//*[contains(text(), ${ JSON . stringify ( targetText ) })]` ; const iterator = document . evaluate ( expression , document , null , XPathResult . ORDERED_NODE_ITERATOR_TYPE , null ) ; let node = iterator . iterateNext ( ) ; function hasVisibleBoundingBox ( element ) { const rect = element . getBoundingClientRect ( ) ; return ! ! ( rect . top || rect . bottom || rect . width || rect . height ) ; } while ( node ) { if ( node && node . nodeType === Node . ELEMENT_NODE ) { const element = node as HTMLElement ; const style = window . getComputedStyle ( element ) ; const isVisible = style && style . visibility !== 'hidden' && hasVisibleBoundingBox ( element ) ; if ( isVisible ) return node ; } node = iterator . iterateNext ( ) ; } return null ; } ; } get pageFuncMany ( ) : EvaluateFn { return ( targetText , partial ) => { const elements = Array . from ( document . querySelectorAll ( '*' ) ) ; function hasVisibleBoundingBox ( node ) { const rect = node . getBoundingClientRect ( ) ; return ! ! ( rect . top || rect . bottom || rect . width || rect . height ) ; } return elements . filter ( ( link ) => { if ( ! link . textContent ) return false ; const text = link . textContent . trim ( ) ; return ( partial && text . indexOf ( targetText ) !== - 1 ) || text === targetText ; } ) . filter ( ( node ) => { const style = window . getComputedStyle ( node ) ; const isVisible = style && style . visibility !== 'hidden' && hasVisibleBoundingBox ( node ) ; return isVisible ; } ) ; } ; } toString ( ) { return `By.partialVisibleText("${ this . linkText }")` ; } }