@@ -683,23 +683,65 @@ Utils.getClickablePoint = function(element) {
683
683
element = element . wrappedJSObject ? element . wrappedJSObject : element ;
684
684
var rect = bot . dom . getClientRect ( element ) ;
685
685
686
- if ( element . getClientRects ( ) . length > 1 ) {
687
- for ( var i = 0 ; i < element . getClientRects ( ) . length ; i ++ ) {
688
- var candidate = element . getClientRects ( ) [ i ] ;
689
- if ( candidate . width != 0 && candidate . height != 0 ) {
690
- return {
691
- x : ( candidate . left - rect . left + Math . floor ( candidate . width / 2 ) ) ,
692
- y : ( candidate . top - rect . top + Math . floor ( candidate . height / 2 ) )
693
- } ;
686
+ var rects = goog . array . filter ( element . getClientRects ( ) , function ( r ) {
687
+ return r . width != 0 && r . height != 0 ;
688
+ } ) ;
689
+
690
+ if ( rects . length > 0 ) {
691
+ for ( var i = 0 ; i < rects . length ; i ++ ) {
692
+ var candidate = rects [ i ] ;
693
+ if ( clickable_point = findClickablePoint ( candidate ) ) {
694
+ return clickable_point ;
694
695
}
695
696
}
697
+ rect = rects [ 0 ] ;
696
698
}
697
699
698
- // Fallback to the main rect
699
- return {
700
- x : ( rect . width ? Math . floor ( rect . width / 2 ) : 0 ) ,
701
- y : ( rect . height ? Math . floor ( rect . height / 2 ) : 0 )
702
- } ;
700
+ // Fallback to the main rect - expected to return a point so if no clickable point return middle
701
+ return findClickablePoint ( rect ) || { x : Math . floor ( rect . width / 2 ) , y : Math . floor ( rect . height / 2 ) } ;
702
+
703
+ function findClickablePoint ( rect ) {
704
+ var offsets = [
705
+ { x : Math . floor ( rect . width / 2 ) , y : Math . floor ( rect . height / 2 ) } ,
706
+ { x : 0 , y : 0 } ,
707
+ { x : rect . width , y : 0 } ,
708
+ { x : 0 , y : rect . height } ,
709
+ { x : rect . width , y : rect . height }
710
+ ]
711
+
712
+ return goog . array . find ( offsets , function ( offset ) {
713
+ return isClickableAt ( { x : rect . left + offset . x , y : rect . top + offset . y } ) ;
714
+ } )
715
+ }
716
+
717
+ function isClickableAt ( coord ) {
718
+ // get the outermost ancestor of the element. This will be either the document
719
+ // or a shadow root.
720
+ var owner = element ;
721
+ while ( owner . parentNode ) {
722
+ owner = owner . parentNode ;
723
+ }
724
+
725
+ var elementAtPoint = owner . elementFromPoint ( coord . x , coord . y ) ;
726
+
727
+ // element may be huge, so coordinates are outside the viewport
728
+ if ( elementAtPoint === null ) {
729
+ return true ;
730
+ }
731
+
732
+ if ( element == elementAtPoint ) {
733
+ return true ;
734
+ }
735
+
736
+ // allow clicks to element descendants
737
+ var parentElemIter = elementAtPoint . parentNode ;
738
+ while ( parentElemIter ) {
739
+ if ( parentElemIter == element ) {
740
+ return true ;
741
+ }
742
+ parentElemIter = parentElemIter . parentNode ;
743
+ }
744
+ }
703
745
} ;
704
746
705
747
0 commit comments