@@ -68,13 +68,19 @@ export function nearestInteractiveElement(element: Element): Element | null {
6868/// Returns the `Locator` object to the first block element that is visible on
6969/// the screen.
7070export function findFirstVisibleLocator ( wnd : ReadiumWindow , scrolling : boolean ) {
71- const element = findElement ( wnd , wnd . document . body , scrolling ) ;
71+ const element = findElement ( wnd , wnd . document . body , scrolling ) as HTMLElement ;
72+
73+ // Use only the allowed selectors to generate the cssSelector and avoid a crash
74+ const cssSelector = wnd . _readium_cssSelectorGenerator . getCssSelector ( element , {
75+ selectors : [ "tag" , "id" , "class" , "nthchild" , "nthoftype" , "attribute" ]
76+ } ) ;
77+
7278 return new Locator ( {
7379 href : "#" ,
7480 type : "application/xhtml+xml" ,
7581 locations : new LocatorLocations ( {
7682 otherLocations : new Map ( [
77- [ "cssSelector" , wnd . _readium_cssSelectorGenerator . getCssSelector ( element ) ]
83+ [ "cssSelector" , cssSelector ]
7884 ] )
7985 } ) ,
8086 text : new LocatorText ( {
@@ -87,6 +93,9 @@ function findElement(wnd: ReadiumWindow, rootElement: Element, scrolling: boolea
8793 for ( var i = 0 ; i < rootElement . children . length ; i ++ ) {
8894 const child = rootElement . children [ i ] ;
8995 if ( ! shouldIgnoreElement ( child ) && isElementVisible ( wnd , child , scrolling ) ) {
96+ // Once we get a fully visible element, return it
97+ if ( isElementFullyVisible ( wnd , child ) ) return child ;
98+ // if the parent is not fully visible, search in the childs
9099 return findElement ( wnd , child , scrolling ) ;
91100 }
92101 }
@@ -111,11 +120,29 @@ function isElementVisible(wnd: ReadiumWindow, element: Element, scrolling: boole
111120 }
112121}
113122
123+ /**
124+ * Check if an element is fully visible in the current viewport.
125+ * @param wnd Window instance to operate on
126+ * @param element Element to check visibility of
127+ * @returns True if the element is fully visible, false otherwise
128+ */
129+ function isElementFullyVisible ( wnd : ReadiumWindow , element : Element ) : boolean {
130+ const rect = element . getBoundingClientRect ( ) ;
131+ const isFullyVisible =
132+ rect . top >= 0 &&
133+ rect . left >= 0 &&
134+ rect . bottom <= wnd . innerHeight &&
135+ rect . right <= wnd . innerWidth ;
136+ return isFullyVisible ;
137+ }
138+
114139function shouldIgnoreElement ( element : Element ) {
115140 const elStyle = getComputedStyle ( element ) ;
116141 if ( elStyle ) {
117142 const display = elStyle . getPropertyValue ( "display" ) ;
118- if ( display != "block" ) {
143+ // Added list-item as it is a common display property for list items
144+ // TODO: Check if there are other display properties that should be ignored/considered
145+ if ( display != "block" && display != "list-item" ) {
119146 return true ;
120147 }
121148 // Cannot be relied upon, because web browser engine reports invisible when out of view in
0 commit comments