diff options
| author | Stephen Blott | 2015-03-03 15:48:08 +0000 | 
|---|---|---|
| committer | Stephen Blott | 2015-03-03 16:00:08 +0000 | 
| commit | b7535a604954b5873d825eb66bfecd08f1f2c99b (patch) | |
| tree | 86064fb8d9d142aa22c8afbfa9bc8638ceecb52b | |
| parent | c48c26354e4382ca96d9e98b0b7291ad940368ce (diff) | |
| download | vimium-b7535a604954b5873d825eb66bfecd08f1f2c99b.tar.bz2 | |
Do not include duplicated texts in link hints.
This only effects link hints with "Use the link's name and numbers for
link-hint filtering" enabled.
We have been matching the *entire text content* of each link-hint
element.
With two (or more) hints, and with one of the elements a descendent of
the other, we have been using the entire text content of the outer node
(which includes the text content of the inner node).  This leads to odd
situations where the inner element cannot be selected just by typing its
text, because its text is a substring of the outer element's text.
For example, on Google calendar, the "Today" button shows up as two
hints, one inside the other.  Typing "today" never disambiguates the
hint.  You always have to hit enter.
There's another nasty example on feedly, where an outer container is
clickable, but its text contains all of the (many) texts of the (many)
contained links.  So the hint always has to be selected manually.
Here, when generating the text for an element, we exclude the texts from
any descendent node which has already been considered.
| -rw-r--r-- | content_scripts/link_hints.coffee | 5 | ||||
| -rw-r--r-- | lib/dom_utils.coffee | 19 | 
2 files changed, 23 insertions, 1 deletions
| diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index 2abfa001..f904c7d5 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -231,6 +231,8 @@ LinkHints =      # Remove rects from elements where another clickable element lies above it.      nonOverlappingElements = []      # Traverse the DOM from first to last, since later elements show above earlier elements. +    # NOTE(smblott). filterHints.generateLinkText also assumes this order when generating the content text for +    # each hint.  Specifically, we consider descendents before we consider their ancestors.      visibleElements = visibleElements.reverse()      while visibleElement = visibleElements.pop()        rects = [visibleElement.rect] @@ -469,7 +471,7 @@ filterHints =        linkText = element.firstElementChild.alt || element.firstElementChild.title        showLinkText = true if (linkText)      else -      linkText = element.textContent || element.innerHTML +      linkText = DomUtils.textContent.get element      { text: linkText, show: showLinkText } @@ -479,6 +481,7 @@ filterHints =    fillInMarkers: (hintMarkers) ->      @generateLabelMap() +    DomUtils.textContent.reset()      for marker, idx in hintMarkers        marker.hintString = @generateHintString(idx)        linkTextObject = @generateLinkText(marker.clickableItem) diff --git a/lib/dom_utils.coffee b/lib/dom_utils.coffee index 2ae9412e..9d4df1b1 100644 --- a/lib/dom_utils.coffee +++ b/lib/dom_utils.coffee @@ -295,5 +295,24 @@ DomUtils =        document.body.removeChild div        coordinates +  # Get the text content of an element (and its descendents), but omit the text content of previously-visited +  # nodes. +  # NOTE(smblott).  This is currently O(N^2) (when called on N elements).  An alternative would be to mark +  # each node visited, and then clear the marks when we're done. +  textContent: do -> +    visitedNodes = null +    reset: -> visitedNodes = [] +    get: (element) -> +      nodes = document.createTreeWalker element, NodeFilter.SHOW_TEXT +      texts = +        while node = nodes.nextNode() +          continue unless node.nodeType == 3 +          continue if node in visitedNodes +          text = node.data.trim() +          continue unless 0 < text.length +          visitedNodes.push node +          text +      texts.join " " +  root = exports ? window  root.DomUtils = DomUtils | 
