diff options
Diffstat (limited to 'content_scripts/link_hints.coffee')
| -rw-r--r-- | content_scripts/link_hints.coffee | 98 | 
1 files changed, 79 insertions, 19 deletions
| diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index 2548abb3..77235ef5 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -110,6 +110,7 @@ HintCoordinator =    # The following messages are exchanged between frames while link-hints mode is active.    updateKeyState: (request) -> @linkHintsMode.updateKeyState request +  rotateHints: -> @linkHintsMode.rotateHints()    setOpenLinkMode: ({modeIndex}) -> @linkHintsMode.setOpenLinkMode availableModes[modeIndex], false    activateActiveHintMarker: -> @linkHintsMode.activateLink @linkHintsMode.markerMatcher.activeHintMarker    getLocalHintMarker: (hint) -> if hint.frameId == frameId then @localHints[hint.localIndex] else null @@ -199,26 +200,32 @@ class LinkHintsMode    #    # Creates a link marker for the given link.    # -  createMarkerFor: (desc) -> -    marker = -      if desc.frameId == frameId -        localHintDescriptor = HintCoordinator.getLocalHintMarker desc -        el = DomUtils.createElement "div" -        el.rect = localHintDescriptor.rect -        el.style.left = el.rect.left + "px" -        el.style.top = el.rect.top  + "px" -        extend el, -          className: "vimiumReset internalVimiumHintMarker vimiumHintMarker" -          showLinkText: localHintDescriptor.showLinkText -          localHintDescriptor: localHintDescriptor -      else -        {} +  createMarkerFor: do -> +    # This generates z-index values which are greater than all of the other z-index values used by Vimium. +    baseZIndex = 2140000000 + +    (desc) -> +      marker = +        if desc.frameId == frameId +          localHintDescriptor = HintCoordinator.getLocalHintMarker desc +          el = DomUtils.createElement "div" +          el.rect = localHintDescriptor.rect +          el.style.left = el.rect.left + "px" +          el.style.top = el.rect.top  + "px" +          # Each hint marker is assigned a different z-index. +          el.style.zIndex = baseZIndex += 1 +          extend el, +            className: "vimiumReset internalVimiumHintMarker vimiumHintMarker" +            showLinkText: localHintDescriptor.showLinkText +            localHintDescriptor: localHintDescriptor +        else +          {} -    extend marker, -      hintDescriptor: desc -      isLocalMarker: desc.frameId == frameId -      linkText: desc.linkText -      stableSortCount: ++@stableSortCount +      extend marker, +        hintDescriptor: desc +        isLocalMarker: desc.frameId == frameId +        linkText: desc.linkText +        stableSortCount: ++@stableSortCount    # Handles <Shift> and <Ctrl>.    onKeyDownInMode: (event) -> @@ -274,6 +281,9 @@ class LinkHintsMode        @tabCount = previousTabCount + (if event.shiftKey then -1 else 1)        @updateVisibleMarkers @tabCount +    else if event.keyCode == keyCodes.space and @markerMatcher.shouldRotateHints event +      HintCoordinator.sendMessage "rotateHints" +      else        return @@ -310,6 +320,49 @@ class LinkHintsMode      @setIndicator() +  # Rotate the hints' z-index values so that hidden hints become visible. +  rotateHints: do -> +    markerOverlapsStack = (marker, stack) -> +      for otherMarker in stack +        return true if Rect.rectsOverlap marker.markerRect, otherMarker.markerRect +      false + +    -> +      # Get local, visible hint markers. +      localHintMarkers = @hintMarkers.filter (marker) -> +        marker.isLocalMarker and marker.style.display != "none" + +      # Fill in the markers' rects, if necessary. +      marker.markerRect ?= marker.getClientRects()[0] for marker in localHintMarkers + +      # Calculate the overlapping groups of hints.  This is O(n^2) in the best case and O(n^3) in the worst +      # case. +      stacks = [] +      for marker in localHintMarkers +        stackForThisMarker = null +        stacks = +          for stack in stacks +            if markerOverlapsStack marker, stack +              if stackForThisMarker? +                # Merge stack into stackForThisMarker and discard stack. +                stackForThisMarker.push stack... +                continue +              else +                stack.push marker +                stackForThisMarker = stack +            else +              stack +        stacks.push [marker] unless stackForThisMarker? + +      # Rotate the z-indexes within each stack. +      for stack in stacks +        if 1 < stack.length +          zIndexes = (marker.style.zIndex for marker in stack) +          zIndexes.push zIndexes[0] +          marker.style.zIndex = zIndexes[index + 1] for marker, index in stack + +      null # Prevent Coffeescript from building an unnecessary array. +    # When only one hint remains, activate it in the appropriate way.  The current frame may or may not contain    # the matched link, and may or may not have the focus.  The resulting four cases are accounted for here by    # selectively pushing the appropriate HintCoordinator.onExit handlers. @@ -420,6 +473,9 @@ class AlphabetHints      @hintKeystrokeQueue.push (if @useKeydown then keydownKeyChar else keyChar)    popKeyChar: -> @hintKeystrokeQueue.pop() +  # For alphabet hints, <Space> always rotates the hints, regardless of modifiers. +  shouldRotateHints: -> true +  # Use numbers (usually) for hints, and also filter links by their text.  class FilterHints    constructor: -> @@ -540,6 +596,10 @@ class FilterHints          # them as if their length was 100 (so, quite long).          score / Math.log 1 + (linkMarker.linkText.length || 100) +  # For filtered hints, we require a modifier (because <Space> on its own is a token separator). +  shouldRotateHints: (event) -> +    event.ctrlKey or event.altKey or event.metaKey +  #  # Make each hint character a span, so that we can highlight the typed characters as you type them.  # | 
