From 20038e470c84a722c61c7afb5f634e9890f6eaf3 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Fri, 5 Jun 2015 06:13:56 +0100 Subject: Use keypress (instead of keydown) for link hint characters. This should make link hints usable on non-Latin keyboards (e.g. Russian keyboards). Fixes #1387. (Maybe - because it's not clear from the discussion there exactly what users want.) --- content_scripts/link_hints.coffee | 45 +++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index 2bcc7508..1e172710 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -68,10 +68,12 @@ LinkHints = name: "hint/#{mode.name}" indicator: false passInitialKeyupEvents: true - keydown: @onKeyDownInMode.bind this, hintMarkers - # Trap all other key events. - keypress: -> false - keyup: -> false + suppressAllKeyboardEvents: true + exitOnEscape: true + keypress: @onKeyDownInMode.bind this, hintMarkers + + @hintMode.onExit => + @deactivateMode() if @isActive @setOpenLinkMode mode @@ -285,11 +287,7 @@ LinkHints = @setOpenLinkMode previousMode if @isActive true - # TODO(philc): Ignore keys that have modifiers. - if (KeyboardUtils.isEscape(event)) - DomUtils.suppressKeyupAfterEscape handlerStack - @deactivateMode() - else if (event.keyCode != keyCodes.shiftKey and event.keyCode != keyCodes.ctrlKey) + if (event.keyCode != keyCodes.shiftKey and event.keyCode != keyCodes.ctrlKey) keyResult = @getMarkerMatcher().matchHintsByKey(hintMarkers, event) linksMatched = keyResult.linksMatched delay = keyResult.delay ? 0 @@ -340,10 +338,8 @@ LinkHints = hideMarker: (linkMarker) -> linkMarker.style.display = "none" - # - # If called without arguments, it executes immediately. Othewise, it - # executes after 'delay' and invokes 'callback' when it is finished. - # + # If called without arguments, it executes immediately. Othewise, it executes after 'delay' and invokes + # 'callback' when it is finished. deactivateMode: (delay, callback) -> deactivate = => if (LinkHints.getMarkerMatcher().deactivate) @@ -351,21 +347,20 @@ LinkHints = if (LinkHints.hintMarkerContainingDiv) DomUtils.removeElement LinkHints.hintMarkerContainingDiv LinkHints.hintMarkerContainingDiv = null + @isActive = false @hintMode.exit() @onExit?() @onExit = null - @isActive = false - # we invoke the deactivate() function directly instead of using setTimeout(callback, 0) so that - # deactivateMode can be tested synchronously - if (!delay) - deactivate() - callback() if (callback) - else - setTimeout(-> + if delay + Utils.setTimeout delay, -> deactivate() - callback() if callback - delay) + callback?() + else + # We invoke deactivate() directly (instead of setting a timeout of 0) so that deactivateMode() can be + # tested synchronously. + deactivate() + callback?() alphabetHints = hintKeystrokeQueue: [] @@ -421,7 +416,7 @@ alphabetHints = matchHintsByKey: (hintMarkers, event) -> # If a shifted-character is typed, treat it as lowerase for the purposes of matching hints. - keyChar = KeyboardUtils.getKeyChar(event).toLowerCase() + keyChar = String.fromCharCode(event.charCode).toLowerCase() if (event.keyCode == keyCodes.backspace || event.keyCode == keyCodes.deleteKey) if (!@hintKeystrokeQueue.pop()) @@ -499,7 +494,7 @@ filterHints = hintMarkers matchHintsByKey: (hintMarkers, event) -> - keyChar = KeyboardUtils.getKeyChar(event) + keyChar = String.fromCharCode event.charCode delay = 0 userIsTypingLinkText = false -- cgit v1.2.3 From 59daec7b9914729b60e1d783bb1143499421fae6 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sun, 7 Jun 2015 10:53:25 +0100 Subject: Exit link-hint mode on click or scroll. Exit on click because, if the user is clicking stuff, then they're probably no longer interested in selecting links. Exit on scroll because, if the user is scrolling, then the link hints can all go out of the viewport. --- content_scripts/link_hints.coffee | 2 ++ content_scripts/mode.coffee | 6 ++++++ content_scripts/vimium_frontend.coffee | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index 1e172710..04853c22 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -70,6 +70,8 @@ LinkHints = passInitialKeyupEvents: true suppressAllKeyboardEvents: true exitOnEscape: true + exitOnClick: true + exitOnScroll: true keypress: @onKeyDownInMode.bind this, hintMarkers @hintMode.onExit => diff --git a/content_scripts/mode.coffee b/content_scripts/mode.coffee index ffabc111..508b1b2c 100644 --- a/content_scripts/mode.coffee +++ b/content_scripts/mode.coffee @@ -101,6 +101,12 @@ class Mode "focus": (event) => @alwaysContinueBubbling => @exit event if DomUtils.isFocusable event.target + # If @options.exitOnScroll is truthy, then the mode will exit on any scroll event. + if @options.exitOnScroll + @push + _name: "mode-#{@id}/exitOnScroll" + "scroll": (event) => @alwaysContinueBubbling => @exit event + # Some modes are singletons: there may be at most one instance active at any time. A mode is a singleton # if @options.singleton is truthy. The value of @options.singleton should be the key which is intended to # be unique. New instances deactivate existing instances with the same key. diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index 3055ecea..8c28b4e6 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -192,7 +192,7 @@ window.installListeners = -> unless installedListeners # Key event handlers fire on window before they do on document. Prefer window for key events so the page # can't set handlers to grab the keys before us. - for type in [ "keydown", "keypress", "keyup", "click", "focus", "blur", "mousedown" ] + for type in [ "keydown", "keypress", "keyup", "click", "focus", "blur", "mousedown", "scroll" ] do (type) -> installListener window, type, (event) -> handlerStack.bubbleEvent type, event installListener document, "DOMActivate", (event) -> handlerStack.bubbleEvent 'DOMActivate', event installedListeners = true -- cgit v1.2.3 From 44e4d7062d2f07895820178418001e5e1bf5ead7 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sun, 7 Jun 2015 11:04:25 +0100 Subject: Note keypress bahaviour for link hints in README. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 06e42567..3bc629ac 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,7 @@ Release Notes - Bug fixes, including: - Bookmarklets accessed from the vomnibar. - Global marks on non-Windows platforms. + - Link-hints for non-Latin keyboards. 1.51 (2015-05-02) -- cgit v1.2.3 From 3b22320266328d18f7ee606bcd6b2a2dfa5090b7 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sun, 7 Jun 2015 17:10:41 +0100 Subject: Refactor to keydown, as required. --- content_scripts/link_hints.coffee | 225 ++++++++++++++++++-------------------- 1 file changed, 107 insertions(+), 118 deletions(-) diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index 04853c22..87da34d6 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -20,18 +20,16 @@ DOWNLOAD_LINK_URL = name: "download" LinkHints = hintMarkerContainingDiv: null - # one of the enums listed at the top of this file + # One of the enums listed at the top of this file. mode: undefined - # function that does the appropriate action on the selected link + # Function that does the appropriate action on the selected link. linkActivator: undefined # While in delayMode, all keypresses have no effect. delayMode: false - # Handle the link hinting marker generation and matching. Must be initialized after Settings have been - # loaded, so that we can retrieve the option setting. - getMarkerMatcher: -> - if Settings.get("filterLinkHints") then filterHints else alphabetHints - # lock to ensure only one instance runs at a time + # Lock to ensure only one instance runs at a time. isActive: false + # The link-hints "mode" (in the key-handler, indicator sense). + hintMode: null # Call this function on exit (if defined). onExit: null @@ -62,7 +60,8 @@ LinkHints = length = (el) -> el.element.innerHTML?.length ? 0 elements.sort (a,b) -> length(a) - length b hintMarkers = (@createMarkerFor(el) for el in elements) - @getMarkerMatcher().fillInMarkers(hintMarkers) + @markerMatcher = if Settings.get("filterLinkHints") then filterHints else alphabetHints + @markerMatcher.fillInMarkers(hintMarkers) @hintMode = new Mode name: "hint/#{mode.name}" @@ -72,7 +71,8 @@ LinkHints = exitOnEscape: true exitOnClick: true exitOnScroll: true - keypress: @onKeyDownInMode.bind this, hintMarkers + keydown: @onKeyDownInMode.bind this, hintMarkers + keypress: @onKeyPressInMode.bind this, hintMarkers @hintMode.onExit => @deactivateMode() if @isActive @@ -261,48 +261,67 @@ LinkHints = nonOverlappingElements - # - # Handles shift and esc keys. The other keys are passed to getMarkerMatcher().matchHintsByKey. - # + # Handles and . onKeyDownInMode: (hintMarkers, event) -> return if @delayMode or event.repeat - if ((event.keyCode == keyCodes.shiftKey or event.keyCode == keyCodes.ctrlKey) and - (@mode == OPEN_IN_CURRENT_TAB or - @mode == OPEN_WITH_QUEUE or - @mode == OPEN_IN_NEW_BG_TAB or - @mode == OPEN_IN_NEW_FG_TAB)) - # Toggle whether to open the link in a new or current tab. - previousMode = @mode - keyCode = event.keyCode - - switch keyCode - when keyCodes.shiftKey - @setOpenLinkMode(if @mode is OPEN_IN_CURRENT_TAB then OPEN_IN_NEW_BG_TAB else OPEN_IN_CURRENT_TAB) - when keyCodes.ctrlKey - @setOpenLinkMode(if @mode is OPEN_IN_NEW_FG_TAB then OPEN_IN_NEW_BG_TAB else OPEN_IN_NEW_FG_TAB) - - handlerStack.push - keyup: (event) => - if event.keyCode == keyCode - handlerStack.remove() - @setOpenLinkMode previousMode if @isActive - true - - if (event.keyCode != keyCodes.shiftKey and event.keyCode != keyCodes.ctrlKey) - keyResult = @getMarkerMatcher().matchHintsByKey(hintMarkers, event) - linksMatched = keyResult.linksMatched - delay = keyResult.delay ? 0 - if (linksMatched.length == 0) - @deactivateMode() - else if (linksMatched.length == 1) - @activateLink(linksMatched[0], delay) + if event.keyCode in [ keyCodes.shiftKey, keyCodes.ctrlKey ] and + @mode in [ OPEN_IN_CURRENT_TAB, OPEN_WITH_QUEUE, OPEN_IN_NEW_BG_TAB, OPEN_IN_NEW_FG_TAB ] + # Toggle whether to open the link in a new or current tab. + previousMode = @mode + keyCode = event.keyCode + + switch keyCode + when keyCodes.shiftKey + @setOpenLinkMode(if @mode is OPEN_IN_CURRENT_TAB then OPEN_IN_NEW_BG_TAB else OPEN_IN_CURRENT_TAB) + when keyCodes.ctrlKey + @setOpenLinkMode(if @mode is OPEN_IN_NEW_FG_TAB then OPEN_IN_NEW_BG_TAB else OPEN_IN_NEW_FG_TAB) + + handlerStack.push + keyup: (event) => + if event.keyCode == keyCode + handlerStack.remove() + @setOpenLinkMode previousMode if @isActive + + else if event.keyCode in [ keyCodes.backspace, keyCodes.deleteKey ] + if @markerMatcher.popKeyChar() + @updateVisibleMarkers hintMarkers else - for marker in hintMarkers - @hideMarker(marker) - for matched in linksMatched - @showMarker(matched, @getMarkerMatcher().hintKeystrokeQueue.length) - false # We've handled this key, so prevent propagation. + @deactivateMode() + + else if @markerMatcher.activateOnEnter and event.keyCode == keyCodes.enter + # Activate the lowest-numbered link hint that matches the current state. + @updateVisibleMarkers hintMarkers, true + + else + return + + # We've handled the event, so suppress it. + DomUtils.suppressEvent event + + # Handles normal input. + onKeyPressInMode: (hintMarkers, event) -> + return if @delayMode or event.repeat + + keyChar = String.fromCharCode(event.charCode).toLowerCase() + if keyChar + @markerMatcher.pushKeyChar keyChar + @updateVisibleMarkers hintMarkers + + updateVisibleMarkers: (hintMarkers, activateFirst = false) -> + keyResult = @markerMatcher.getMatchingHints hintMarkers + linksMatched = keyResult.linksMatched + if (linksMatched.length == 0) + @deactivateMode() + else if activateFirst + @activateLink(linksMatched[0], 0) + else if (linksMatched.length == 1) + @activateLink(linksMatched[0], keyResult.delay ? 0) + else + for marker in hintMarkers + @hideMarker(marker) + for matched in linksMatched + @showMarker(matched, @markerMatcher.hintKeystrokeQueue.length) # # When only one link hint remains, this function activates it in the appropriate way. @@ -340,17 +359,16 @@ LinkHints = hideMarker: (linkMarker) -> linkMarker.style.display = "none" - # If called without arguments, it executes immediately. Othewise, it executes after 'delay' and invokes - # 'callback' when it is finished. + # If called without arguments, this exits immediately. Othewise, it exits after 'delay'. After exiting, + # 'callback' is invoked (if it is provided). deactivateMode: (delay, callback) -> deactivate = => - if (LinkHints.getMarkerMatcher().deactivate) - LinkHints.getMarkerMatcher().deactivate() - if (LinkHints.hintMarkerContainingDiv) - DomUtils.removeElement LinkHints.hintMarkerContainingDiv - LinkHints.hintMarkerContainingDiv = null + @markerMatcher?.deactivate?() + DomUtils.removeElement @hintMarkerContainingDiv if @hintMarkerContainingDiv + @hintMarkerContainingDiv = null @isActive = false - @hintMode.exit() + @hintMode?.exit() + @hintMode = null @onExit?() @onExit = null @@ -365,6 +383,7 @@ LinkHints = callback?() alphabetHints = + activateOnEnter: false hintKeystrokeQueue: [] logXOfBase: (x, base) -> Math.log(x) / Math.log(base) @@ -416,23 +435,17 @@ alphabetHints = result = result.concat(bucket) result - matchHintsByKey: (hintMarkers, event) -> - # If a shifted-character is typed, treat it as lowerase for the purposes of matching hints. - keyChar = String.fromCharCode(event.charCode).toLowerCase() - - if (event.keyCode == keyCodes.backspace || event.keyCode == keyCodes.deleteKey) - if (!@hintKeystrokeQueue.pop()) - return { linksMatched: [] } - else if keyChar - @hintKeystrokeQueue.push(keyChar) + getMatchingHints: (hintMarkers) -> + matchString = @hintKeystrokeQueue.join "" + linksMatched: hintMarkers.filter (linkMarker) -> linkMarker.hintString.startsWith matchString - matchString = @hintKeystrokeQueue.join("") - linksMatched = hintMarkers.filter((linkMarker) -> linkMarker.hintString.indexOf(matchString) == 0) - { linksMatched: linksMatched } + pushKeyChar: (keyChar) -> @hintKeystrokeQueue.push keyChar + popKeyChar: -> @hintKeystrokeQueue.pop() deactivate: -> @hintKeystrokeQueue = [] filterHints = + activateOnEnter: true hintKeystrokeQueue: [] linkTextKeystrokeQueue: [] labelMap: {} @@ -495,67 +508,43 @@ filterHints = hintMarkers - matchHintsByKey: (hintMarkers, event) -> - keyChar = String.fromCharCode event.charCode + getMatchingHints: (hintMarkers) -> delay = 0 - userIsTypingLinkText = false - if (event.keyCode == keyCodes.enter) - # activate the lowest-numbered link hint that is visible - for marker in hintMarkers - if (marker.style.display != "none") - return { linksMatched: [ marker ] } - else if (event.keyCode == keyCodes.backspace || event.keyCode == keyCodes.deleteKey) - # backspace clears hint key queue first, then acts on link text key queue. - # if both queues are empty. exit hinting mode - if (!@hintKeystrokeQueue.pop() && !@linkTextKeystrokeQueue.pop()) - return { linksMatched: [] } - else if (keyChar) - if (Settings.get("linkHintNumbers").indexOf(keyChar) >= 0) - @hintKeystrokeQueue.push(keyChar) - else - # since we might renumber the hints, the current hintKeyStrokeQueue - # should be rendered invalid (i.e. reset). - @hintKeystrokeQueue = [] - @linkTextKeystrokeQueue.push(keyChar) - userIsTypingLinkText = true - - # at this point, linkTextKeystrokeQueue and hintKeystrokeQueue have been updated to reflect the latest + # At this point, linkTextKeystrokeQueue and hintKeystrokeQueue have been updated to reflect the latest # input. use them to filter the link hints accordingly. - linksMatched = @filterLinkHints(hintMarkers) - matchString = @hintKeystrokeQueue.join("") - linksMatched = linksMatched.filter((linkMarker) -> - !linkMarker.filtered && linkMarker.hintString.indexOf(matchString) == 0) - - if (linksMatched.length == 1 && userIsTypingLinkText) - # In filter mode, people tend to type out words past the point - # needed for a unique match. Hence we should avoid passing - # control back to command mode immediately after a match is found. + matchString = @hintKeystrokeQueue.join "" + linksMatched = @filterLinkHints hintMarkers + linksMatched = linksMatched.filter (linkMarker) -> linkMarker.hintString.startsWith matchString + + if linksMatched.length == 1 && @hintKeystrokeQueue.length == 0 and 0 < @linkTextKeystrokeQueue.length + # In filter mode, people tend to type out words past the point needed for a unique match. Hence we + # should avoid passing control back to command mode immediately after a match is found. delay = 200 { linksMatched: linksMatched, delay: delay } - # - # Marks the links that do not match the linkText search string with the 'filtered' DOM property. Renumbers - # the remainder if necessary. - # - filterLinkHints: (hintMarkers) -> - linksMatched = [] - linkSearchString = @linkTextKeystrokeQueue.join("") + pushKeyChar: (keyChar) -> + if 0 <= Settings.get("linkHintNumbers").indexOf keyChar + @hintKeystrokeQueue.push keyChar + else + # Since we might renumber the hints, we should reset the current hintKeyStrokeQueue. + @hintKeystrokeQueue = [] + @linkTextKeystrokeQueue.push keyChar - for linkMarker in hintMarkers - matchedLink = linkMarker.linkText.toLowerCase().indexOf(linkSearchString.toLowerCase()) >= 0 + popKeyChar: -> + @hintKeystrokeQueue.pop() or @linkTextKeystrokeQueue.pop() - if (!matchedLink) - linkMarker.filtered = true - else - linkMarker.filtered = false - oldHintString = linkMarker.hintString - linkMarker.hintString = @generateHintString(linksMatched.length) - @renderMarker(linkMarker) if (linkMarker.hintString != oldHintString) - linksMatched.push(linkMarker) + # Filter link hints by search string, renumbering the hints as necessary. + filterLinkHints: (hintMarkers) -> + idx = 0 + linkSearchString = @linkTextKeystrokeQueue.join("").toLowerCase() - linksMatched + for linkMarker in hintMarkers + continue unless 0 <= linkMarker.linkText.toLowerCase().indexOf linkSearchString + linkMarker.hintString = @generateHintString idx++ + @renderMarker linkMarker + linkMarker deactivate: (delay, callback) -> @hintKeystrokeQueue = [] -- cgit v1.2.3 From 5662f69a71b28b107724d63f33fe9e9d8718a95e Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Mon, 8 Jun 2015 07:35:04 +0100 Subject: Make hint filters classes. --- content_scripts/link_hints.coffee | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index 87da34d6..fbd78b1d 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -60,8 +60,8 @@ LinkHints = length = (el) -> el.element.innerHTML?.length ? 0 elements.sort (a,b) -> length(a) - length b hintMarkers = (@createMarkerFor(el) for el in elements) - @markerMatcher = if Settings.get("filterLinkHints") then filterHints else alphabetHints - @markerMatcher.fillInMarkers(hintMarkers) + @markerMatcher = new (if Settings.get "filterLinkHints" then FilterHints else AlphabetHints) + @markerMatcher.fillInMarkers hintMarkers @hintMode = new Mode name: "hint/#{mode.name}" @@ -308,6 +308,9 @@ LinkHints = @markerMatcher.pushKeyChar keyChar @updateVisibleMarkers hintMarkers + # We've handled the event, so suppress it. + DomUtils.suppressEvent event + updateVisibleMarkers: (hintMarkers, activateFirst = false) -> keyResult = @markerMatcher.getMatchingHints hintMarkers linksMatched = keyResult.linksMatched @@ -350,7 +353,6 @@ LinkHints = # showMarker: (linkMarker, matchingCharCount) -> linkMarker.style.display = "" - # TODO(philc): for j in [0...linkMarker.childNodes.length] if (j < matchingCharCount) linkMarker.childNodes[j].classList.add("matchingCharacter") @@ -363,9 +365,9 @@ LinkHints = # 'callback' is invoked (if it is provided). deactivateMode: (delay, callback) -> deactivate = => - @markerMatcher?.deactivate?() DomUtils.removeElement @hintMarkerContainingDiv if @hintMarkerContainingDiv @hintMarkerContainingDiv = null + @markerMatcher = null @isActive = false @hintMode?.exit() @hintMode = null @@ -382,11 +384,14 @@ LinkHints = deactivate() callback?() -alphabetHints = - activateOnEnter: false - hintKeystrokeQueue: [] +# Use characters for hints, and do not filter links by their text. +class AlphabetHints logXOfBase: (x, base) -> Math.log(x) / Math.log(base) + constructor: -> + @activateOnEnter = false + @hintKeystrokeQueue = [] + fillInMarkers: (hintMarkers) -> hintStrings = @hintStrings(hintMarkers.length) for marker, idx in hintMarkers @@ -442,13 +447,13 @@ alphabetHints = pushKeyChar: (keyChar) -> @hintKeystrokeQueue.push keyChar popKeyChar: -> @hintKeystrokeQueue.pop() - deactivate: -> @hintKeystrokeQueue = [] - -filterHints = - activateOnEnter: true - hintKeystrokeQueue: [] - linkTextKeystrokeQueue: [] - labelMap: {} +# Use numbers (usually) for hints, and also filter links by their text. +class FilterHints + constructor: -> + @activateOnEnter = true + @hintKeystrokeQueue = [] + @linkTextKeystrokeQueue = [] + @labelMap = {} # # Generate a map of input element => label @@ -546,11 +551,6 @@ filterHints = @renderMarker linkMarker linkMarker - deactivate: (delay, callback) -> - @hintKeystrokeQueue = [] - @linkTextKeystrokeQueue = [] - @labelMap = {} - # # Make each hint character a span, so that we can highlight the typed characters as you type them. # -- cgit v1.2.3 From 6b29f4bb9fec6c61054c2037289d7ca6c0249c10 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Tue, 9 Jun 2015 06:01:22 +0100 Subject: Alphabet hints, use keydown for defaults. See #1722. When Settings.get("linkHintCharacters") is its default value, this preserves the legacy behaviour of using the keyChar from keydown events for link-hint matching. This admits users using either Latin or non-Latin characters for link hints. --- content_scripts/link_hints.coffee | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index fbd78b1d..469c2990 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -264,6 +264,7 @@ LinkHints = # Handles and . onKeyDownInMode: (hintMarkers, event) -> return if @delayMode or event.repeat + @keydownKeyChar = KeyboardUtils.getKeyChar(event).toLowerCase() if event.keyCode in [ keyCodes.shiftKey, keyCodes.ctrlKey ] and @mode in [ OPEN_IN_CURRENT_TAB, OPEN_WITH_QUEUE, OPEN_IN_NEW_BG_TAB, OPEN_IN_NEW_FG_TAB ] @@ -305,7 +306,7 @@ LinkHints = keyChar = String.fromCharCode(event.charCode).toLowerCase() if keyChar - @markerMatcher.pushKeyChar keyChar + @markerMatcher.pushKeyChar keyChar, @keydownKeyChar @updateVisibleMarkers hintMarkers # We've handled the event, so suppress it. @@ -389,6 +390,11 @@ class AlphabetHints logXOfBase: (x, base) -> Math.log(x) / Math.log(base) constructor: -> + @linkHintCharacters = Settings.get "linkHintCharacters" + # We use the keyChar from keydown if the link-hint characters are all "a-z". This is the default, and + # preserves the legacy behavior (which always used keydown) for users which are familiar with that + # behavior. Otherwise, we use keyChar from keypress, which admits non-Latin characters. See #1722. + @useKeydown = /^[a-z]*$/.test @linkHintCharacters @activateOnEnter = false @hintKeystrokeQueue = [] @@ -405,27 +411,26 @@ class AlphabetHints # may be of different lengths. # hintStrings: (linkCount) -> - linkHintCharacters = Settings.get("linkHintCharacters") # Determine how many digits the link hints will require in the worst case. Usually we do not need # all of these digits for every link single hint, so we can show shorter hints for a few of the links. - digitsNeeded = Math.ceil(@logXOfBase(linkCount, linkHintCharacters.length)) + digitsNeeded = Math.ceil(@logXOfBase(linkCount, @linkHintCharacters.length)) # Short hints are the number of hints we can possibly show which are (digitsNeeded - 1) digits in length. shortHintCount = Math.floor( - (Math.pow(linkHintCharacters.length, digitsNeeded) - linkCount) / - linkHintCharacters.length) + (Math.pow(@linkHintCharacters.length, digitsNeeded) - linkCount) / + @linkHintCharacters.length) longHintCount = linkCount - shortHintCount hintStrings = [] if (digitsNeeded > 1) for i in [0...shortHintCount] - hintStrings.push(numberToHintString(i, linkHintCharacters, digitsNeeded - 1)) + hintStrings.push(numberToHintString(i, @linkHintCharacters, digitsNeeded - 1)) - start = shortHintCount * linkHintCharacters.length + start = shortHintCount * @linkHintCharacters.length for i in [start...(start + longHintCount)] - hintStrings.push(numberToHintString(i, linkHintCharacters, digitsNeeded)) + hintStrings.push(numberToHintString(i, @linkHintCharacters, digitsNeeded)) - @shuffleHints(hintStrings, linkHintCharacters.length) + @shuffleHints(hintStrings, @linkHintCharacters.length) # # This shuffles the given set of hints so that they're scattered -- hints starting with the same character @@ -444,7 +449,8 @@ class AlphabetHints matchString = @hintKeystrokeQueue.join "" linksMatched: hintMarkers.filter (linkMarker) -> linkMarker.hintString.startsWith matchString - pushKeyChar: (keyChar) -> @hintKeystrokeQueue.push keyChar + pushKeyChar: (keyChar, keydownKeyChar) -> + @hintKeystrokeQueue.push (if @useKeydown then keydownKeyChar else keyChar) popKeyChar: -> @hintKeystrokeQueue.pop() # Use numbers (usually) for hints, and also filter links by their text. @@ -529,7 +535,7 @@ class FilterHints { linksMatched: linksMatched, delay: delay } - pushKeyChar: (keyChar) -> + pushKeyChar: (keyChar, keydownKeyChar) -> if 0 <= Settings.get("linkHintNumbers").indexOf keyChar @hintKeystrokeQueue.push keyChar else -- cgit v1.2.3 From e422af43a075f52d0f2f4bf69243a699b99ba33b Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Tue, 9 Jun 2015 06:10:04 +0100 Subject: Only look up linkHintNumbers once. --- content_scripts/link_hints.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index 469c2990..02d61f3c 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -456,6 +456,7 @@ class AlphabetHints # Use numbers (usually) for hints, and also filter links by their text. class FilterHints constructor: -> + @linkHintNumbers = Settings.get "linkHintNumbers" @activateOnEnter = true @hintKeystrokeQueue = [] @linkTextKeystrokeQueue = [] @@ -476,7 +477,7 @@ class FilterHints @labelMap[forElement] = labelText generateHintString: (linkHintNumber) -> - (numberToHintString linkHintNumber + 1, Settings.get "linkHintNumbers").toUpperCase() + numberToHintString linkHintNumber + 1, @linkHintNumbers.toUpperCase() generateLinkText: (element) -> linkText = "" @@ -536,7 +537,7 @@ class FilterHints { linksMatched: linksMatched, delay: delay } pushKeyChar: (keyChar, keydownKeyChar) -> - if 0 <= Settings.get("linkHintNumbers").indexOf keyChar + if 0 <= @linkHintNumbers.indexOf keyChar @hintKeystrokeQueue.push keyChar else # Since we might renumber the hints, we should reset the current hintKeyStrokeQueue. -- cgit v1.2.3 From 054bda0d1d3c5131361fc62aeca4b40ece9f233b Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Tue, 9 Jun 2015 10:55:59 +0100 Subject: Tweak comments re. keydown versus keypress. --- content_scripts/link_hints.coffee | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index 02d61f3c..ca104dd6 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -391,10 +391,11 @@ class AlphabetHints constructor: -> @linkHintCharacters = Settings.get "linkHintCharacters" - # We use the keyChar from keydown if the link-hint characters are all "a-z". This is the default, and - # preserves the legacy behavior (which always used keydown) for users which are familiar with that - # behavior. Otherwise, we use keyChar from keypress, which admits non-Latin characters. See #1722. - @useKeydown = /^[a-z]*$/.test @linkHintCharacters + # We use the keyChar from keydown if the link-hint characters are all "a-z0-9". This is the default + # settings value, and preserves the legacy behavior (which always used keydown) for users which are + # familiar with that behavior. Otherwise, we use keyChar from keypress, which admits non-Latin + # characters. See #1722. + @useKeydown = /^[a-z0-9]*$/.test @linkHintCharacters @activateOnEnter = false @hintKeystrokeQueue = [] @@ -537,6 +538,9 @@ class FilterHints { linksMatched: linksMatched, delay: delay } pushKeyChar: (keyChar, keydownKeyChar) -> + # For filtered hints, we *always* use the keyChar value from keypress, because there is no obvious and + # easy-to-understand meaning for choosing one of keyChar or keydownKeyChar (as there is for alphabet + # hints). if 0 <= @linkHintNumbers.indexOf keyChar @hintKeystrokeQueue.push keyChar else -- cgit v1.2.3 From a7712e6ed48c89417846c0f516754551cf2d5d53 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Tue, 9 Jun 2015 14:21:05 +0100 Subject: Use tab to select filetered link hints. --- README.md | 1 + content_scripts/link_hints.coffee | 35 +++++++++++++++++++++++++++++------ content_scripts/vimium.css | 4 ++++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 3bc629ac..dc161ca6 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,7 @@ Release Notes - A much improved interface for custom search engines. - Added \`\` to jump back to the previous position after selected jump-like movements. - Global marks are now persistent (across tab closes and browser sessions) and synced. +- For filtered link hints (not the default), you can now use `Tab` to select hints. - Bug fixes, including: - Bookmarklets accessed from the vomnibar. - Global marks on non-Windows platforms. diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index ca104dd6..31cdcfdf 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -32,6 +32,8 @@ LinkHints = hintMode: null # Call this function on exit (if defined). onExit: null + # A count of the number of Tab presses since the last non-Tab keyboard event. + tabCount: 0 # We need this as a top-level function because our command system doesn't yet support arguments. activateModeToOpenInNewTab: -> @activateMode(OPEN_IN_NEW_BG_TAB) @@ -266,8 +268,12 @@ LinkHints = return if @delayMode or event.repeat @keydownKeyChar = KeyboardUtils.getKeyChar(event).toLowerCase() + previousTabCount = @tabCount + @tabCount = 0 + if event.keyCode in [ keyCodes.shiftKey, keyCodes.ctrlKey ] and @mode in [ OPEN_IN_CURRENT_TAB, OPEN_WITH_QUEUE, OPEN_IN_NEW_BG_TAB, OPEN_IN_NEW_FG_TAB ] + @tabCount = previousTabCount # Toggle whether to open the link in a new or current tab. previousMode = @mode keyCode = event.keyCode @@ -292,7 +298,11 @@ LinkHints = else if @markerMatcher.activateOnEnter and event.keyCode == keyCodes.enter # Activate the lowest-numbered link hint that matches the current state. - @updateVisibleMarkers hintMarkers, true + @updateVisibleMarkers hintMarkers, true, previousTabCount + + else if event.keyCode == keyCodes.tab + @tabCount = previousTabCount + (if event.shiftKey then -1 else 1) + @updateVisibleMarkers hintMarkers, false, @tabCount else return @@ -312,13 +322,14 @@ LinkHints = # We've handled the event, so suppress it. DomUtils.suppressEvent event - updateVisibleMarkers: (hintMarkers, activateFirst = false) -> - keyResult = @markerMatcher.getMatchingHints hintMarkers + updateVisibleMarkers: (hintMarkers, activateActiveHint = false, tabCount = 0) -> + keyResult = @markerMatcher.getMatchingHints hintMarkers, tabCount linksMatched = keyResult.linksMatched if (linksMatched.length == 0) @deactivateMode() - else if activateFirst - @activateLink(linksMatched[0], 0) + else if activateActiveHint + tabCount = ((linksMatched.length * Math.abs tabCount) + tabCount) % linksMatched.length + @activateLink(linksMatched[tabCount], 0) else if (linksMatched.length == 1) @activateLink(linksMatched[0], keyResult.delay ? 0) else @@ -374,6 +385,7 @@ LinkHints = @hintMode = null @onExit?() @onExit = null + @tabCount = 0 if delay Utils.setTimeout delay, -> @@ -462,6 +474,7 @@ class FilterHints @hintKeystrokeQueue = [] @linkTextKeystrokeQueue = [] @labelMap = {} + @previousActiveHintMarker = null # # Generate a map of input element => label @@ -519,9 +532,12 @@ class FilterHints marker.showLinkText = linkTextObject.show @renderMarker(marker) + @previousActiveHintMarker = hintMarkers[0] + @previousActiveHintMarker?.classList.add "vimiumActiveHintMarker" + hintMarkers - getMatchingHints: (hintMarkers) -> + getMatchingHints: (hintMarkers, tabCount = 0) -> delay = 0 # At this point, linkTextKeystrokeQueue and hintKeystrokeQueue have been updated to reflect the latest @@ -535,6 +551,13 @@ class FilterHints # should avoid passing control back to command mode immediately after a match is found. delay = 200 + # Visually highlight of the active hint (that is, the one that will be activated if the user + # types ). + tabCount = ((linksMatched.length * Math.abs tabCount) + tabCount) % linksMatched.length + @previousActiveHintMarker?.classList.remove "vimiumActiveHintMarker" + @previousActiveHintMarker = linksMatched[tabCount] + @previousActiveHintMarker?.classList.add "vimiumActiveHintMarker" + { linksMatched: linksMatched, delay: delay } pushKeyChar: (keyChar, keydownKeyChar) -> diff --git a/content_scripts/vimium.css b/content_scripts/vimium.css index b4bce776..38a968fc 100644 --- a/content_scripts/vimium.css +++ b/content_scripts/vimium.css @@ -90,6 +90,10 @@ div.internalVimiumHintMarker > .matchingCharacter { color: #D4AC3A; } +div > .vimiumActiveHintMarker span { + color: #A07555 !important; +} + /* Input hints CSS */ div.internalVimiumInputHint { -- cgit v1.2.3 From 98a3f4c96e8b189ca142f7cccbc1ef995c158b9d Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Tue, 9 Jun 2015 14:47:39 +0100 Subject: Make LinkHints a class (LinkHintsMode). Functionality wise, this is a no-op. However, since we now create a new LinkHintsMode object on every "f", we don't need to be so careful about resetting the state on exit. --- content_scripts/link_hints.coffee | 20 +++++++++++--------- tests/dom_tests/dom_tests.coffee | 32 ++++++++++++++++---------------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index 31cdcfdf..81a5912e 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -19,6 +19,16 @@ OPEN_INCOGNITO = name: "incognito" DOWNLOAD_LINK_URL = name: "download" LinkHints = + activateMode: (mode = OPEN_IN_CURRENT_TAB) -> new LinkHintsMode mode + + activateModeToOpenInNewTab: -> @activateMode OPEN_IN_NEW_BG_TAB + activateModeToOpenInNewForegroundTab: -> @activateMode OPEN_IN_NEW_FG_TAB + activateModeToCopyLinkUrl: -> @activateMode COPY_LINK_URL + activateModeWithQueue: -> @activateMode OPEN_WITH_QUEUE + activateModeToOpenIncognito: -> @activateMode OPEN_INCOGNITO + activateModeToDownloadLink: -> @activateMode DOWNLOAD_LINK_URL + +class LinkHintsMode hintMarkerContainingDiv: null # One of the enums listed at the top of this file. mode: undefined @@ -35,15 +45,7 @@ LinkHints = # A count of the number of Tab presses since the last non-Tab keyboard event. tabCount: 0 - # We need this as a top-level function because our command system doesn't yet support arguments. - activateModeToOpenInNewTab: -> @activateMode(OPEN_IN_NEW_BG_TAB) - activateModeToOpenInNewForegroundTab: -> @activateMode(OPEN_IN_NEW_FG_TAB) - activateModeToCopyLinkUrl: -> @activateMode(COPY_LINK_URL) - activateModeWithQueue: -> @activateMode(OPEN_WITH_QUEUE) - activateModeToOpenIncognito: -> @activateMode(OPEN_INCOGNITO) - activateModeToDownloadLink: -> @activateMode(DOWNLOAD_LINK_URL) - - activateMode: (mode = OPEN_IN_CURRENT_TAB) -> + constructor: (mode = OPEN_IN_CURRENT_TAB) -> # we need documentElement to be ready in order to append links return unless document.documentElement diff --git a/tests/dom_tests/dom_tests.coffee b/tests/dom_tests/dom_tests.coffee index 8f293075..dd2f5a5d 100644 --- a/tests/dom_tests/dom_tests.coffee +++ b/tests/dom_tests/dom_tests.coffee @@ -67,27 +67,27 @@ createGeneralHintTests = (isFilteredMode) -> document.getElementById("test-div").innerHTML = "" should "create hints when activated, discard them when deactivated", -> - LinkHints.activateMode() - assert.isFalse not LinkHints.hintMarkerContainingDiv? - LinkHints.deactivateMode() - assert.isTrue not LinkHints.hintMarkerContainingDiv? + linkHints = LinkHints.activateMode() + assert.isFalse not linkHints.hintMarkerContainingDiv? + linkHints.deactivateMode() + assert.isTrue not linkHints.hintMarkerContainingDiv? should "position items correctly", -> assertStartPosition = (element1, element2) -> assert.equal element1.getClientRects()[0].left, element2.getClientRects()[0].left assert.equal element1.getClientRects()[0].top, element2.getClientRects()[0].top stub document.body, "style", "static" - LinkHints.activateMode() + linkHints = LinkHints.activateMode() hintMarkers = getHintMarkers() assertStartPosition document.getElementsByTagName("a")[0], hintMarkers[0] assertStartPosition document.getElementsByTagName("a")[1], hintMarkers[1] - LinkHints.deactivateMode() + linkHints.deactivateMode() stub document.body.style, "position", "relative" - LinkHints.activateMode() + linkHints = LinkHints.activateMode() hintMarkers = getHintMarkers() assertStartPosition document.getElementsByTagName("a")[0], hintMarkers[0] assertStartPosition document.getElementsByTagName("a")[1], hintMarkers[1] - LinkHints.deactivateMode() + linkHints.deactivateMode() createGeneralHintTests false createGeneralHintTests true @@ -142,10 +142,10 @@ context "Alphabetical link hints", # Three hints will trigger double hint chars. createLinks 3 - LinkHints.activateMode() + @linkHints = LinkHints.activateMode() tearDown -> - LinkHints.deactivateMode() + @linkHints.deactivateMode() document.getElementById("test-div").innerHTML = "" should "label the hints correctly", -> @@ -177,11 +177,11 @@ context "Filtered link hints", initializeModeState() testContent = "test" + "tress" + "trait" + "trackalt text" document.getElementById("test-div").innerHTML = testContent - LinkHints.activateMode() + @linkHints = LinkHints.activateMode() tearDown -> document.getElementById("test-div").innerHTML = "" - LinkHints.deactivateMode() + @linkHints.deactivateMode() should "label the hints", -> hintMarkers = getHintMarkers() @@ -205,11 +205,11 @@ context "Filtered link hints", testContent = "alt textalt text " + "" document.getElementById("test-div").innerHTML = testContent - LinkHints.activateMode() + @linkHints = LinkHints.activateMode() tearDown -> document.getElementById("test-div").innerHTML = "" - LinkHints.deactivateMode() + @linkHints.deactivateMode() should "label the images", -> hintMarkers = getHintMarkers() @@ -227,11 +227,11 @@ context "Filtered link hints", " document.getElementById("test-div").innerHTML = testContent - LinkHints.activateMode() + @linkHints = LinkHints.activateMode() tearDown -> document.getElementById("test-div").innerHTML = "" - LinkHints.deactivateMode() + @linkHints.deactivateMode() should "label the input elements", -> hintMarkers = getHintMarkers() -- cgit v1.2.3 From c9d2000fcd23de49d7bb8245572c963689f565ea Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Tue, 9 Jun 2015 14:56:08 +0100 Subject: Minor touch ups. --- content_scripts/link_hints.coffee | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index 81a5912e..d4cf863b 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -48,9 +48,6 @@ class LinkHintsMode constructor: (mode = OPEN_IN_CURRENT_TAB) -> # we need documentElement to be ready in order to append links return unless document.documentElement - - if @isActive - return @isActive = true elements = @getVisibleClickableElements() @@ -84,10 +81,9 @@ class LinkHintsMode @setOpenLinkMode mode # Note(philc): Append these markers as top level children instead of as child nodes to the link itself, - # because some clickable elements cannot contain children, e.g. submit buttons. This has the caveat - # that if you scroll the page and the link has position=fixed, the marker will not stay fixed. - @hintMarkerContainingDiv = DomUtils.addElementList(hintMarkers, - { id: "vimiumHintMarkerContainer", className: "vimiumReset" }) + # because some clickable elements cannot contain children, e.g. submit buttons. + @hintMarkerContainingDiv = DomUtils.addElementList hintMarkers, + id: "vimiumHintMarkerContainer", className: "vimiumReset" setOpenLinkMode: (@mode) -> if @mode is OPEN_IN_NEW_BG_TAB or @mode is OPEN_IN_NEW_FG_TAB or @mode is OPEN_WITH_QUEUE @@ -327,18 +323,16 @@ class LinkHintsMode updateVisibleMarkers: (hintMarkers, activateActiveHint = false, tabCount = 0) -> keyResult = @markerMatcher.getMatchingHints hintMarkers, tabCount linksMatched = keyResult.linksMatched - if (linksMatched.length == 0) + if linksMatched.length == 0 @deactivateMode() else if activateActiveHint tabCount = ((linksMatched.length * Math.abs tabCount) + tabCount) % linksMatched.length - @activateLink(linksMatched[tabCount], 0) - else if (linksMatched.length == 1) - @activateLink(linksMatched[0], keyResult.delay ? 0) + @activateLink linksMatched[tabCount], 0 + else if linksMatched.length == 1 + @activateLink linksMatched[0], keyResult.delay ? 0 else - for marker in hintMarkers - @hideMarker(marker) - for matched in linksMatched - @showMarker(matched, @markerMatcher.hintKeystrokeQueue.length) + @hideMarker marker for marker in hintMarkers + @showMarker matched, @markerMatcher.hintKeystrokeQueue.length for matched in linksMatched # # When only one link hint remains, this function activates it in the appropriate way. -- cgit v1.2.3 From cfc7f800a594f9daccf3364ea5cdb233550e88e8 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Wed, 10 Jun 2015 07:09:50 +0100 Subject: Simplify activate-on-enter logic. --- content_scripts/link_hints.coffee | 43 +++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index d4cf863b..cf54b7a4 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -88,11 +88,11 @@ class LinkHintsMode setOpenLinkMode: (@mode) -> if @mode is OPEN_IN_NEW_BG_TAB or @mode is OPEN_IN_NEW_FG_TAB or @mode is OPEN_WITH_QUEUE if @mode is OPEN_IN_NEW_BG_TAB - @hintMode.setIndicator "Open link in new tab" + @hintMode.setIndicator "Open link in new tab." else if @mode is OPEN_IN_NEW_FG_TAB - @hintMode.setIndicator "Open link in new tab and switch to it" + @hintMode.setIndicator "Open link in new tab and switch to it." else - @hintMode.setIndicator "Open multiple links in a new tab" + @hintMode.setIndicator "Open multiple links in new tabs." @linkActivator = (link) -> # When "clicking" on a link, dispatch the event with the appropriate meta key (CMD on Mac, CTRL on # windows) to open it in a new tab if necessary. @@ -102,7 +102,7 @@ class LinkHintsMode ctrlKey: KeyboardUtils.platform != "Mac" altKey: false else if @mode is COPY_LINK_URL - @hintMode.setIndicator "Copy link URL to Clipboard" + @hintMode.setIndicator "Copy link URL to Clipboard." @linkActivator = (link) => if link.href? chrome.runtime.sendMessage handler: "copyToClipboard", data: link.href @@ -112,15 +112,15 @@ class LinkHintsMode else @onExit = -> HUD.showForDuration "No link to yank.", 2000 else if @mode is OPEN_INCOGNITO - @hintMode.setIndicator "Open link in incognito window" + @hintMode.setIndicator "Open link in incognito window." @linkActivator = (link) -> chrome.runtime.sendMessage handler: 'openUrlInIncognito', url: link.href else if @mode is DOWNLOAD_LINK_URL - @hintMode.setIndicator "Download link URL" + @hintMode.setIndicator "Download link URL." @linkActivator = (link) -> DomUtils.simulateClick link, altKey: true, ctrlKey: false, metaKey: false else # OPEN_IN_CURRENT_TAB - @hintMode.setIndicator "Open link in current tab" + @hintMode.setIndicator "Open link in current tab." @linkActivator = (link) -> DomUtils.simulateClick.bind(DomUtils, link)() # @@ -294,13 +294,13 @@ class LinkHintsMode else @deactivateMode() - else if @markerMatcher.activateOnEnter and event.keyCode == keyCodes.enter - # Activate the lowest-numbered link hint that matches the current state. - @updateVisibleMarkers hintMarkers, true, previousTabCount + else if event.keyCode == keyCodes.enter + # Activate the active hint, if there is one. Only FilterHints uses an active hint. + @activateLink @markerMatcher.activeHintMarker if @markerMatcher.activeHintMarker else if event.keyCode == keyCodes.tab @tabCount = previousTabCount + (if event.shiftKey then -1 else 1) - @updateVisibleMarkers hintMarkers, false, @tabCount + @updateVisibleMarkers hintMarkers, @tabCount else return @@ -320,14 +320,11 @@ class LinkHintsMode # We've handled the event, so suppress it. DomUtils.suppressEvent event - updateVisibleMarkers: (hintMarkers, activateActiveHint = false, tabCount = 0) -> + updateVisibleMarkers: (hintMarkers, tabCount = 0) -> keyResult = @markerMatcher.getMatchingHints hintMarkers, tabCount linksMatched = keyResult.linksMatched if linksMatched.length == 0 @deactivateMode() - else if activateActiveHint - tabCount = ((linksMatched.length * Math.abs tabCount) + tabCount) % linksMatched.length - @activateLink linksMatched[tabCount], 0 else if linksMatched.length == 1 @activateLink linksMatched[0], keyResult.delay ? 0 else @@ -337,7 +334,7 @@ class LinkHintsMode # # When only one link hint remains, this function activates it in the appropriate way. # - activateLink: (matchedLink, delay) -> + activateLink: (matchedLink, delay = 0) -> @delayMode = true clickEl = matchedLink.clickableItem if (DomUtils.isSelectable(clickEl)) @@ -404,7 +401,6 @@ class AlphabetHints # familiar with that behavior. Otherwise, we use keyChar from keypress, which admits non-Latin # characters. See #1722. @useKeydown = /^[a-z0-9]*$/.test @linkHintCharacters - @activateOnEnter = false @hintKeystrokeQueue = [] fillInMarkers: (hintMarkers) -> @@ -466,11 +462,10 @@ class AlphabetHints class FilterHints constructor: -> @linkHintNumbers = Settings.get "linkHintNumbers" - @activateOnEnter = true @hintKeystrokeQueue = [] @linkTextKeystrokeQueue = [] @labelMap = {} - @previousActiveHintMarker = null + @activeHintMarker = null # # Generate a map of input element => label @@ -528,8 +523,8 @@ class FilterHints marker.showLinkText = linkTextObject.show @renderMarker(marker) - @previousActiveHintMarker = hintMarkers[0] - @previousActiveHintMarker?.classList.add "vimiumActiveHintMarker" + @activeHintMarker = hintMarkers[0] + @activeHintMarker?.classList.add "vimiumActiveHintMarker" hintMarkers @@ -550,9 +545,9 @@ class FilterHints # Visually highlight of the active hint (that is, the one that will be activated if the user # types ). tabCount = ((linksMatched.length * Math.abs tabCount) + tabCount) % linksMatched.length - @previousActiveHintMarker?.classList.remove "vimiumActiveHintMarker" - @previousActiveHintMarker = linksMatched[tabCount] - @previousActiveHintMarker?.classList.add "vimiumActiveHintMarker" + @activeHintMarker?.classList.remove "vimiumActiveHintMarker" + @activeHintMarker = linksMatched[tabCount] + @activeHintMarker?.classList.add "vimiumActiveHintMarker" { linksMatched: linksMatched, delay: delay } -- cgit v1.2.3 From 76ce186850296070cd2a0a5672282bab986eca8b Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Wed, 10 Jun 2015 07:25:53 +0100 Subject: Remove legacy (broken and unnecessary) calls. --- content_scripts/link_hints.coffee | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee index cf54b7a4..107a292e 100644 --- a/content_scripts/link_hints.coffee +++ b/content_scripts/link_hints.coffee @@ -339,7 +339,7 @@ class LinkHintsMode clickEl = matchedLink.clickableItem if (DomUtils.isSelectable(clickEl)) DomUtils.simulateSelect(clickEl) - @deactivateMode(delay, -> LinkHints.delayMode = false) + @deactivateMode delay else # TODO figure out which other input elements should not receive focus if (clickEl.nodeName.toLowerCase() == "input" and clickEl.type not in ["button", "submit"]) @@ -347,11 +347,9 @@ class LinkHintsMode DomUtils.flashRect(matchedLink.rect) @linkActivator(clickEl) if @mode is OPEN_WITH_QUEUE - @deactivateMode delay, -> - LinkHints.delayMode = false - LinkHints.activateModeWithQueue() + @deactivateMode delay, -> LinkHints.activateModeWithQueue() else - @deactivateMode(delay, -> LinkHints.delayMode = false) + @deactivateMode delay # # Shows the marker, highlighting matchingCharCount characters. @@ -366,9 +364,7 @@ class LinkHintsMode hideMarker: (linkMarker) -> linkMarker.style.display = "none" - # If called without arguments, this exits immediately. Othewise, it exits after 'delay'. After exiting, - # 'callback' is invoked (if it is provided). - deactivateMode: (delay, callback) -> + deactivateMode: (delay = 0, callback = null) -> deactivate = => DomUtils.removeElement @hintMarkerContainingDiv if @hintMarkerContainingDiv @hintMarkerContainingDiv = null -- cgit v1.2.3