@@ -558,7 +558,6 @@ LocalHints =
558
558
getVisibleClickable : (element ) ->
559
559
tagName = element .tagName .toLowerCase ()
560
560
isClickable = false
561
- onlyHasTabIndex = false
562
561
possibleFalsePositive = false
563
562
visibleElements = []
564
563
reason = null
@@ -650,18 +649,17 @@ LocalHints =
650
649
if not isClickable and 0 <= element .getAttribute (" class" )? .toLowerCase ().indexOf " button"
651
650
possibleFalsePositive = isClickable = true
652
651
653
- # Elements with tabindex are sometimes useful, but usually not. We can treat them as second class
654
- # citizens when it improves UX, so take special note of them .
655
- tabIndexValue = element . getAttribute ( " tabindex " )
656
- tabIndex = if tabIndexValue == " " then 0 else parseInt tabIndexValue
657
- unless isClickable or isNaN ( tabIndex) or tabIndex < 0
658
- isClickable = onlyHasTabIndex = true
652
+ isClickable ?= do ->
653
+ # Elements with tabindex are sometimes useful .
654
+ # NOTE(smblott) We should consider removing these, they are noise more often than not.
655
+ tabIndexValue = element . getAttribute " tabindex "
656
+ tabIndex = if tabIndexValue == " " then 0 else parseInt tabIndexValue
657
+ not isNaN (tabIndex) and 0 <= tabIndex
659
658
660
659
if isClickable
661
- clientRect = DomUtils .getVisibleClientRect element, true
662
- if clientRect != null
663
- visibleElements .push {element : element, rect : clientRect, secondClassCitizen : onlyHasTabIndex,
664
- possibleFalsePositive, reason}
660
+ rect = DomUtils .getVisibleClientRect element, true
661
+ if rect != null
662
+ visibleElements .push {element, rect, possibleFalsePositive, reason}
665
663
666
664
visibleElements
667
665
@@ -709,34 +707,26 @@ LocalHints =
709
707
false # This is not a false positive.
710
708
element
711
709
712
- # TODO(mrmr1993): Consider z-index. z-index affects behaviour as follows:
713
- # * The document has a local stacking context.
714
- # * An element with z-index specified
715
- # - sets its z-order position in the containing stacking context, and
716
- # - creates a local stacking context containing its children.
717
- # * An element (1) is shown above another element (2) if either
718
- # - in the last stacking context which contains both an ancestor of (1) and an ancestor of (2), the
719
- # ancestor of (1) has a higher z-index than the ancestor of (2); or
720
- # - in the last stacking context which contains both an ancestor of (1) and an ancestor of (2),
721
- # + the ancestors of (1) and (2) have equal z-index, and
722
- # + the ancestor of (1) appears later in the DOM than the ancestor of (2).
723
- #
724
- # Remove rects from elements where another clickable element lies above it.
725
- localHints = nonOverlappingElements = []
726
- while visibleElement = visibleElements .pop ()
727
- rects = [visibleElement .rect ]
728
- for {rect : negativeRect} in visibleElements
729
- # Subtract negativeRect from every rect in rects, and concatenate the arrays of rects that result.
730
- rects = [].concat (rects .map (rect) -> Rect .subtract rect, negativeRect)...
731
- if rects .length > 0
732
- nonOverlappingElements .push extend visibleElement, rect : rects[0 ]
733
- else
734
- # Every part of the element is covered by some other element, so just insert the whole element's
735
- # rect. Except for elements with tabIndex set (second class citizens); these are often more trouble
736
- # than they're worth.
737
- # TODO(mrmr1993): This is probably the wrong thing to do, but we don't want to stop being able to
738
- # click some elements that we could click before.
739
- nonOverlappingElements .push visibleElement unless visibleElement .secondClassCitizen
710
+ # Only keep elements where one of the corners or the center is visible.
711
+ localHints = nonOverlappingElements =
712
+ for visibleElement in visibleElements
713
+ {rect , element } = visibleElement
714
+
715
+ # We use a small offset inwards to handle some edge cases where another element would be found
716
+ # instead.
717
+ xs = [rect .left + 0.1 , rect .right - 0.1 ]
718
+ ys = [rect .top + 0.1 , rect .bottom - 0.1 ]
719
+
720
+ # We check the center and then the four corners.
721
+ points = [[rect .left + (rect .width * 0.5 ), rect .top + (rect .height * 0.5 )],
722
+ [xs[0 ], ys[0 ]], [xs[0 ], ys[1 ]], [xs[1 ], ys[0 ]], [xs[1 ], ys[1 ]]]
723
+
724
+ continue unless do ->
725
+ for [x, y] in points
726
+ return true if DomUtils .elementIsVisible element, x, y
727
+ false
728
+
729
+ visibleElement
740
730
741
731
# Position the rects within the window.
742
732
for hint in nonOverlappingElements
0 commit comments