From 51fa63a5e97167b015acf7b80d673d081c2b91da Mon Sep 17 00:00:00 2001
From: mrmr1993
Date: Tue, 24 Oct 2017 18:36:23 +0100
Subject: Move NormalMode to its own content script
---
content_scripts/mode_normal.coffee | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 content_scripts/mode_normal.coffee
(limited to 'content_scripts/mode_normal.coffee')
diff --git a/content_scripts/mode_normal.coffee b/content_scripts/mode_normal.coffee
new file mode 100644
index 00000000..3e1b1ee3
--- /dev/null
+++ b/content_scripts/mode_normal.coffee
@@ -0,0 +1,38 @@
+class NormalMode extends KeyHandlerMode
+ constructor: (options = {}) ->
+ defaults =
+ name: "normal"
+ indicator: false # There is normally no mode indicator in normal mode.
+ commandHandler: @commandHandler.bind this
+
+ super extend defaults, options
+
+ chrome.storage.local.get "normalModeKeyStateMapping", (items) =>
+ @setKeyMapping items.normalModeKeyStateMapping
+
+ chrome.storage.onChanged.addListener (changes, area) =>
+ if area == "local" and changes.normalModeKeyStateMapping?.newValue
+ @setKeyMapping changes.normalModeKeyStateMapping.newValue
+
+ commandHandler: ({command: registryEntry, count}) ->
+ count *= registryEntry.options.count ? 1
+ count = 1 if registryEntry.noRepeat
+
+ if registryEntry.repeatLimit? and registryEntry.repeatLimit < count
+ return unless confirm """
+ You have asked Vimium to perform #{count} repetitions of the command: #{registryEntry.description}.\n
+ Are you sure you want to continue?"""
+
+ if registryEntry.topFrame
+ # We never return to a UI-component frame (e.g. the help dialog), it might have lost the focus.
+ sourceFrameId = if window.isVimiumUIComponent then 0 else frameId
+ chrome.runtime.sendMessage
+ handler: "sendMessageToFrames", message: {name: "runInTopFrame", sourceFrameId, registryEntry}
+ else if registryEntry.background
+ chrome.runtime.sendMessage {handler: "runBackgroundCommand", registryEntry, count}
+ else
+ Utils.invokeCommandString registryEntry.command, count, {registryEntry}
+
+root = exports ? (window.root ?= {})
+root.NormalMode = NormalMode
+extend window, root unless exports?
--
cgit v1.2.3
From 0b24e966c6a64864204c7f489063b29e05b2ca34 Mon Sep 17 00:00:00 2001
From: mrmr1993
Date: Tue, 24 Oct 2017 19:03:38 +0100
Subject: Move self-contained normal mode commands to normal mode file
---
content_scripts/mode_normal.coffee | 69 ++++++++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
(limited to 'content_scripts/mode_normal.coffee')
diff --git a/content_scripts/mode_normal.coffee b/content_scripts/mode_normal.coffee
index 3e1b1ee3..a7a8a8b6 100644
--- a/content_scripts/mode_normal.coffee
+++ b/content_scripts/mode_normal.coffee
@@ -33,6 +33,75 @@ class NormalMode extends KeyHandlerMode
else
Utils.invokeCommandString registryEntry.command, count, {registryEntry}
+NormalModeCommands =
+ # Scrolling.
+ scrollToBottom: ->
+ Marks.setPreviousPosition()
+ Scroller.scrollTo "y", "max"
+ scrollToTop: (count) ->
+ Marks.setPreviousPosition()
+ Scroller.scrollTo "y", (count - 1) * Settings.get("scrollStepSize")
+ scrollToLeft: -> Scroller.scrollTo "x", 0
+ scrollToRight: -> Scroller.scrollTo "x", "max"
+ scrollUp: (count) -> Scroller.scrollBy "y", -1 * Settings.get("scrollStepSize") * count
+ scrollDown: (count) -> Scroller.scrollBy "y", Settings.get("scrollStepSize") * count
+ scrollPageUp: (count) -> Scroller.scrollBy "y", "viewSize", -1/2 * count
+ scrollPageDown: (count) -> Scroller.scrollBy "y", "viewSize", 1/2 * count
+ scrollFullPageUp: (count) -> Scroller.scrollBy "y", "viewSize", -1 * count
+ scrollFullPageDown: (count) -> Scroller.scrollBy "y", "viewSize", 1 * count
+ scrollLeft: (count) -> Scroller.scrollBy "x", -1 * Settings.get("scrollStepSize") * count
+ scrollRight: (count) -> Scroller.scrollBy "x", Settings.get("scrollStepSize") * count
+
+ # Page state.
+ reload: (count, options) ->
+ hard = options.registryEntry.options.hard ? false
+ window.location.reload(hard)
+ goBack: (count) -> history.go(-count)
+ goForward: (count) -> history.go(count)
+
+ # Url manipulation.
+ goUp: (count) ->
+ url = window.location.href
+ if (url[url.length - 1] == "/")
+ url = url.substring(0, url.length - 1)
+
+ urlsplit = url.split("/")
+ # make sure we haven't hit the base domain yet
+ if (urlsplit.length > 3)
+ urlsplit = urlsplit.slice(0, Math.max(3, urlsplit.length - count))
+ window.location.href = urlsplit.join('/')
+
+ goToRoot: ->
+ window.location.href = window.location.origin
+
+ toggleViewSource: ->
+ chrome.runtime.sendMessage { handler: "getCurrentTabUrl" }, (url) ->
+ if (url.substr(0, 12) == "view-source:")
+ url = url.substr(12, url.length - 12)
+ else
+ url = "view-source:" + url
+ chrome.runtime.sendMessage {handler: "openUrlInNewTab", url}
+
+ copyCurrentUrl: ->
+ chrome.runtime.sendMessage { handler: "getCurrentTabUrl" }, (url) ->
+ chrome.runtime.sendMessage { handler: "copyToClipboard", data: url }
+ url = url[0..25] + "...." if 28 < url.length
+ HUD.showForDuration("Yanked #{url}", 2000)
+
+ # Mode changes.
+ enterInsertMode: ->
+ # If a focusable element receives the focus, then we exit and leave the permanently-installed insert-mode
+ # instance to take over.
+ new InsertMode global: true, exitOnFocus: true
+
+ enterVisualMode: ->
+ new VisualMode userLaunchedMode: true
+
+ enterVisualLineMode: ->
+ new VisualLineMode userLaunchedMode: true
+
root = exports ? (window.root ?= {})
root.NormalMode = NormalMode
+root.NormalModeCommands = NormalModeCommands
+extend root, NormalModeCommands
extend window, root unless exports?
--
cgit v1.2.3
From 6fcfde0b561e43955ef35ea3a91ed483cedfff4f Mon Sep 17 00:00:00 2001
From: mrmr1993
Date: Tue, 24 Oct 2017 19:30:02 +0100
Subject: Move normal mode find commands into normal mode file
---
content_scripts/mode_normal.coffee | 8 ++++++++
1 file changed, 8 insertions(+)
(limited to 'content_scripts/mode_normal.coffee')
diff --git a/content_scripts/mode_normal.coffee b/content_scripts/mode_normal.coffee
index a7a8a8b6..652adc3c 100644
--- a/content_scripts/mode_normal.coffee
+++ b/content_scripts/mode_normal.coffee
@@ -100,6 +100,14 @@ NormalModeCommands =
enterVisualLineMode: ->
new VisualLineMode userLaunchedMode: true
+ enterFindMode: ->
+ Marks.setPreviousPosition()
+ new FindMode()
+
+ # Find.
+ performFind: (count) -> FindMode.findNext false for [0...count] by 1
+ performBackwardsFind: (count) -> FindMode.findNext true for [0...count] by 1
+
root = exports ? (window.root ?= {})
root.NormalMode = NormalMode
root.NormalModeCommands = NormalModeCommands
--
cgit v1.2.3
From ee95cb38bbd24fec444e0af3f593f470cce60d22 Mon Sep 17 00:00:00 2001
From: mrmr1993
Date: Tue, 24 Oct 2017 19:34:20 +0100
Subject: Move mainFrame and showHelp to normal mode file
---
content_scripts/mode_normal.coffee | 4 ++++
1 file changed, 4 insertions(+)
(limited to 'content_scripts/mode_normal.coffee')
diff --git a/content_scripts/mode_normal.coffee b/content_scripts/mode_normal.coffee
index 652adc3c..6ae82fe6 100644
--- a/content_scripts/mode_normal.coffee
+++ b/content_scripts/mode_normal.coffee
@@ -108,6 +108,10 @@ NormalModeCommands =
performFind: (count) -> FindMode.findNext false for [0...count] by 1
performBackwardsFind: (count) -> FindMode.findNext true for [0...count] by 1
+ # Misc.
+ mainFrame: -> focusThisFrame highlight: true, forceFocusThisFrame: true
+ showHelp: (sourceFrameId) -> HelpDialog.toggle {sourceFrameId, showAllCommandDetails: false}
+
root = exports ? (window.root ?= {})
root.NormalMode = NormalMode
root.NormalModeCommands = NormalModeCommands
--
cgit v1.2.3
From fe2255f4de5e17d6ab1a9168191bfbfaa488d62d Mon Sep 17 00:00:00 2001
From: mrmr1993
Date: Tue, 24 Oct 2017 19:51:25 +0100
Subject: Move passNextKey to normal mode file
---
content_scripts/mode_normal.coffee | 13 +++++++++++++
1 file changed, 13 insertions(+)
(limited to 'content_scripts/mode_normal.coffee')
diff --git a/content_scripts/mode_normal.coffee b/content_scripts/mode_normal.coffee
index 6ae82fe6..9a53ce76 100644
--- a/content_scripts/mode_normal.coffee
+++ b/content_scripts/mode_normal.coffee
@@ -33,6 +33,13 @@ class NormalMode extends KeyHandlerMode
else
Utils.invokeCommandString registryEntry.command, count, {registryEntry}
+enterNormalMode = (count) ->
+ new NormalMode
+ indicator: "Normal mode (pass keys disabled)"
+ exitOnEscape: true
+ singleton: "enterNormalMode"
+ count: count
+
NormalModeCommands =
# Scrolling.
scrollToBottom: ->
@@ -112,6 +119,12 @@ NormalModeCommands =
mainFrame: -> focusThisFrame highlight: true, forceFocusThisFrame: true
showHelp: (sourceFrameId) -> HelpDialog.toggle {sourceFrameId, showAllCommandDetails: false}
+ passNextKey: (count, options) ->
+ if options.registryEntry.options.normal
+ enterNormalMode count
+ else
+ new PassNextKeyMode count
+
root = exports ? (window.root ?= {})
root.NormalMode = NormalMode
root.NormalModeCommands = NormalModeCommands
--
cgit v1.2.3
From d8f8015f4cd71cf3681506a5ec16f00f8ab46f46 Mon Sep 17 00:00:00 2001
From: mrmr1993
Date: Wed, 25 Oct 2017 00:34:43 +0100
Subject: Split focusInput, move the main part into the normal mode file
---
content_scripts/mode_normal.coffee | 57 ++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
(limited to 'content_scripts/mode_normal.coffee')
diff --git a/content_scripts/mode_normal.coffee b/content_scripts/mode_normal.coffee
index 9a53ce76..2408e4aa 100644
--- a/content_scripts/mode_normal.coffee
+++ b/content_scripts/mode_normal.coffee
@@ -125,6 +125,63 @@ NormalModeCommands =
else
new PassNextKeyMode count
+ focusInput: (count) ->
+ # Focus the first input element on the page, and create overlays to highlight all the input elements, with
+ # the currently-focused element highlighted specially. Tabbing will shift focus to the next input element.
+ # Pressing any other key will remove the overlays and the special tab behavior.
+ resultSet = DomUtils.evaluateXPath textInputXPath, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE
+ visibleInputs =
+ for i in [0...resultSet.snapshotLength] by 1
+ element = resultSet.snapshotItem i
+ continue unless DomUtils.getVisibleClientRect element, true
+ { element, rect: Rect.copy element.getBoundingClientRect() }
+
+ if visibleInputs.length == 0
+ HUD.showForDuration("There are no inputs to focus.", 1000)
+ return
+
+ # This is a hack to improve usability on the Vimium options page. We prime the recently-focused input
+ # to be the key-mappings input. Arguably, this is the input that the user is most likely to use.
+ recentlyFocusedElement = lastFocusedInput()
+ recentlyFocusedElement ?= document.getElementById "keyMappings" if window.isVimiumOptionsPage
+
+ selectedInputIndex =
+ if count == 1
+ # As the starting index, we pick that of the most recently focused input element (or 0).
+ elements = visibleInputs.map (visibleInput) -> visibleInput.element
+ Math.max 0, elements.indexOf recentlyFocusedElement
+ else
+ Math.min(count, visibleInputs.length) - 1
+
+ hints = for tuple in visibleInputs
+ hint = DomUtils.createElement "div"
+ hint.className = "vimiumReset internalVimiumInputHint vimiumInputHint"
+
+ # minus 1 for the border
+ hint.style.left = (tuple.rect.left - 1) + window.scrollX + "px"
+ hint.style.top = (tuple.rect.top - 1) + window.scrollY + "px"
+ hint.style.width = tuple.rect.width + "px"
+ hint.style.height = tuple.rect.height + "px"
+
+ hint
+
+ new FocusSelector hints, visibleInputs, selectedInputIndex
+
+# The types in that we consider for focusInput command. Right now this is recalculated in
+# each content script. Alternatively we could calculate it once in the background page and use a request to
+# fetch it each time.
+# Should we include the HTML5 date pickers here?
+
+# The corresponding XPath for such elements.
+textInputXPath = (->
+ textInputTypes = [ "text", "search", "email", "url", "number", "password", "date", "tel" ]
+ inputElements = ["input[" +
+ "(" + textInputTypes.map((type) -> '@type="' + type + '"').join(" or ") + "or not(@type))" +
+ " and not(@disabled or @readonly)]",
+ "textarea", "*[@contenteditable='' or translate(@contenteditable, 'TRUE', 'true')='true']"]
+ DomUtils.makeXPath(inputElements)
+)()
+
root = exports ? (window.root ?= {})
root.NormalMode = NormalMode
root.NormalModeCommands = NormalModeCommands
--
cgit v1.2.3
From b06ed7bd5cc82ec3307aeee945bcf6bf8f9264ce Mon Sep 17 00:00:00 2001
From: mrmr1993
Date: Wed, 25 Oct 2017 01:00:18 +0100
Subject: Include LinkHints, Vomnibar and Marks commands in normal mode file
---
content_scripts/mode_normal.coffee | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
(limited to 'content_scripts/mode_normal.coffee')
diff --git a/content_scripts/mode_normal.coffee b/content_scripts/mode_normal.coffee
index 2408e4aa..3ddbf294 100644
--- a/content_scripts/mode_normal.coffee
+++ b/content_scripts/mode_normal.coffee
@@ -167,6 +167,31 @@ NormalModeCommands =
new FocusSelector hints, visibleInputs, selectedInputIndex
+if LinkHints?
+ extend NormalModeCommands,
+ "LinkHints.activateMode": LinkHints.activateMode
+ "LinkHints.activateModeToOpenInNewTab": LinkHints.activateModeToOpenInNewTab
+ "LinkHints.activateModeToOpenInNewForegroundTab": LinkHints.activateModeToOpenInNewForegroundTab
+ "LinkHints.activateModeWithQueue": LinkHints.activateModeWithQueue
+ "LinkHints.activateModeToOpenIncognito": LinkHints.activateModeToOpenIncognito
+ "LinkHints.activateModeToDownloadLink": LinkHints.activateModeToDownloadLink
+ "LinkHints.activateModeToCopyLinkUrl": LinkHints.activateModeToCopyLinkUrl
+
+if Vomnibar?
+ extend NormalModeCommands,
+ "Vomnibar.activate": Vomnibar.activate
+ "Vomnibar.activateInNewTab": Vomnibar.activateInNewTab
+ "Vomnibar.activateTabSelection": Vomnibar.activateTabSelection
+ "Vomnibar.activateBookmarks": Vomnibar.activateBookmarks
+ "Vomnibar.activateBookmarksInNewTab": Vomnibar.activateBookmarksInNewTab
+ "Vomnibar.activateEditUrl": Vomnibar.activateEditUrl
+ "Vomnibar.activateEditUrlInNewTab": Vomnibar.activateEditUrlInNewTab
+
+if Marks?
+ extend NormalModeCommands,
+ "Marks.activateCreateMode": Marks.activateCreateMode
+ "Marks.activateGotoMode": Marks.activateGotoMode
+
# The types in that we consider for focusInput command. Right now this is recalculated in
# each content script. Alternatively we could calculate it once in the background page and use a request to
# fetch it each time.
--
cgit v1.2.3
From 6cb8a82b7cf7d6930b669fae74e1751a1e87567d Mon Sep 17 00:00:00 2001
From: mrmr1993
Date: Wed, 25 Oct 2017 01:04:58 +0100
Subject: Move goPrevious and goNext to normal mode file
---
content_scripts/mode_normal.coffee | 10 ++++++++++
1 file changed, 10 insertions(+)
(limited to 'content_scripts/mode_normal.coffee')
diff --git a/content_scripts/mode_normal.coffee b/content_scripts/mode_normal.coffee
index 3ddbf294..8547c9e5 100644
--- a/content_scripts/mode_normal.coffee
+++ b/content_scripts/mode_normal.coffee
@@ -125,6 +125,16 @@ NormalModeCommands =
else
new PassNextKeyMode count
+ goPrevious: ->
+ previousPatterns = Settings.get("previousPatterns") || ""
+ previousStrings = previousPatterns.split(",").filter( (s) -> s.trim().length )
+ findAndFollowRel("prev") || findAndFollowLink(previousStrings)
+
+ goNext: ->
+ nextPatterns = Settings.get("nextPatterns") || ""
+ nextStrings = nextPatterns.split(",").filter( (s) -> s.trim().length )
+ findAndFollowRel("next") || findAndFollowLink(nextStrings)
+
focusInput: (count) ->
# Focus the first input element on the page, and create overlays to highlight all the input elements, with
# the currently-focused element highlighted specially. Tabbing will shift focus to the next input element.
--
cgit v1.2.3
From 5c4aab3d4488e5d8d64aba122791f86fc9766b99 Mon Sep 17 00:00:00 2001
From: mrmr1993
Date: Sat, 28 Oct 2017 17:02:12 +0100
Subject: Bind LinkHints, Vomnibar and Marks commands appropriately
---
content_scripts/mode_normal.coffee | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
(limited to 'content_scripts/mode_normal.coffee')
diff --git a/content_scripts/mode_normal.coffee b/content_scripts/mode_normal.coffee
index 8547c9e5..6db42948 100644
--- a/content_scripts/mode_normal.coffee
+++ b/content_scripts/mode_normal.coffee
@@ -179,28 +179,28 @@ NormalModeCommands =
if LinkHints?
extend NormalModeCommands,
- "LinkHints.activateMode": LinkHints.activateMode
- "LinkHints.activateModeToOpenInNewTab": LinkHints.activateModeToOpenInNewTab
- "LinkHints.activateModeToOpenInNewForegroundTab": LinkHints.activateModeToOpenInNewForegroundTab
- "LinkHints.activateModeWithQueue": LinkHints.activateModeWithQueue
- "LinkHints.activateModeToOpenIncognito": LinkHints.activateModeToOpenIncognito
- "LinkHints.activateModeToDownloadLink": LinkHints.activateModeToDownloadLink
- "LinkHints.activateModeToCopyLinkUrl": LinkHints.activateModeToCopyLinkUrl
+ "LinkHints.activateMode": LinkHints.activateMode.bind LinkHints
+ "LinkHints.activateModeToOpenInNewTab": LinkHints.activateModeToOpenInNewTab.bind LinkHints
+ "LinkHints.activateModeToOpenInNewForegroundTab": LinkHints.activateModeToOpenInNewForegroundTab.bind LinkHints
+ "LinkHints.activateModeWithQueue": LinkHints.activateModeWithQueue.bind LinkHints
+ "LinkHints.activateModeToOpenIncognito": LinkHints.activateModeToOpenIncognito.bind LinkHints
+ "LinkHints.activateModeToDownloadLink": LinkHints.activateModeToDownloadLink.bind LinkHints
+ "LinkHints.activateModeToCopyLinkUrl": LinkHints.activateModeToCopyLinkUrl.bind LinkHints
if Vomnibar?
extend NormalModeCommands,
- "Vomnibar.activate": Vomnibar.activate
- "Vomnibar.activateInNewTab": Vomnibar.activateInNewTab
- "Vomnibar.activateTabSelection": Vomnibar.activateTabSelection
- "Vomnibar.activateBookmarks": Vomnibar.activateBookmarks
- "Vomnibar.activateBookmarksInNewTab": Vomnibar.activateBookmarksInNewTab
- "Vomnibar.activateEditUrl": Vomnibar.activateEditUrl
- "Vomnibar.activateEditUrlInNewTab": Vomnibar.activateEditUrlInNewTab
+ "Vomnibar.activate": Vomnibar.activate.bind Vomnibar
+ "Vomnibar.activateInNewTab": Vomnibar.activateInNewTab.bind Vomnibar
+ "Vomnibar.activateTabSelection": Vomnibar.activateTabSelection.bind Vomnibar
+ "Vomnibar.activateBookmarks": Vomnibar.activateBookmarks.bind Vomnibar
+ "Vomnibar.activateBookmarksInNewTab": Vomnibar.activateBookmarksInNewTab.bind Vomnibar
+ "Vomnibar.activateEditUrl": Vomnibar.activateEditUrl.bind Vomnibar
+ "Vomnibar.activateEditUrlInNewTab": Vomnibar.activateEditUrlInNewTab.bind Vomnibar
if Marks?
extend NormalModeCommands,
- "Marks.activateCreateMode": Marks.activateCreateMode
- "Marks.activateGotoMode": Marks.activateGotoMode
+ "Marks.activateCreateMode": Marks.activateCreateMode.bind Marks
+ "Marks.activateGotoMode": Marks.activateGotoMode.bind Marks
# The types in that we consider for focusInput command. Right now this is recalculated in
# each content script. Alternatively we could calculate it once in the background page and use a request to
--
cgit v1.2.3
From f65720e58e31a0218e0c176a9140520451e5dd7d Mon Sep 17 00:00:00 2001
From: mrmr1993
Date: Sat, 28 Oct 2017 17:04:37 +0100
Subject: Remove invokeCommandString, call NormalModeCommands directly
---
content_scripts/mode_normal.coffee | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'content_scripts/mode_normal.coffee')
diff --git a/content_scripts/mode_normal.coffee b/content_scripts/mode_normal.coffee
index 6db42948..d6f2934e 100644
--- a/content_scripts/mode_normal.coffee
+++ b/content_scripts/mode_normal.coffee
@@ -31,7 +31,7 @@ class NormalMode extends KeyHandlerMode
else if registryEntry.background
chrome.runtime.sendMessage {handler: "runBackgroundCommand", registryEntry, count}
else
- Utils.invokeCommandString registryEntry.command, count, {registryEntry}
+ NormalModeCommands[registryEntry.command] count, {registryEntry}
enterNormalMode = (count) ->
new NormalMode
--
cgit v1.2.3
From 9847144f3493547af7eb419f11552ac18d7e9872 Mon Sep 17 00:00:00 2001
From: mrmr1993
Date: Sat, 28 Oct 2017 17:09:24 +0100
Subject: Remove normal mode commands from global scope
---
content_scripts/mode_normal.coffee | 1 -
1 file changed, 1 deletion(-)
(limited to 'content_scripts/mode_normal.coffee')
diff --git a/content_scripts/mode_normal.coffee b/content_scripts/mode_normal.coffee
index d6f2934e..02681475 100644
--- a/content_scripts/mode_normal.coffee
+++ b/content_scripts/mode_normal.coffee
@@ -220,5 +220,4 @@ textInputXPath = (->
root = exports ? (window.root ?= {})
root.NormalMode = NormalMode
root.NormalModeCommands = NormalModeCommands
-extend root, NormalModeCommands
extend window, root unless exports?
--
cgit v1.2.3
From ad8fa8e850eaa6ca3ef4d45e1903d11aa564cafe Mon Sep 17 00:00:00 2001
From: mrmr1993
Date: Sun, 29 Oct 2017 12:03:43 +0000
Subject: Move FocusSelector to mode_normal.coffee
---
content_scripts/mode_normal.coffee | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
(limited to 'content_scripts/mode_normal.coffee')
diff --git a/content_scripts/mode_normal.coffee b/content_scripts/mode_normal.coffee
index 02681475..9a03e9d0 100644
--- a/content_scripts/mode_normal.coffee
+++ b/content_scripts/mode_normal.coffee
@@ -217,6 +217,44 @@ textInputXPath = (->
DomUtils.makeXPath(inputElements)
)()
+class FocusSelector extends Mode
+ constructor: (hints, visibleInputs, selectedInputIndex) ->
+ super
+ name: "focus-selector"
+ exitOnClick: true
+ keydown: (event) =>
+ if event.key == "Tab"
+ hints[selectedInputIndex].classList.remove 'internalVimiumSelectedInputHint'
+ selectedInputIndex += hints.length + (if event.shiftKey then -1 else 1)
+ selectedInputIndex %= hints.length
+ hints[selectedInputIndex].classList.add 'internalVimiumSelectedInputHint'
+ DomUtils.simulateSelect visibleInputs[selectedInputIndex].element
+ @suppressEvent
+ else unless event.key == "Shift"
+ @exit()
+ # Give the new mode the opportunity to handle the event.
+ @restartBubbling
+
+ @hintContainingDiv = DomUtils.addElementList hints,
+ id: "vimiumInputMarkerContainer"
+ className: "vimiumReset"
+
+ DomUtils.simulateSelect visibleInputs[selectedInputIndex].element
+ if visibleInputs.length == 1
+ @exit()
+ return
+ else
+ hints[selectedInputIndex].classList.add 'internalVimiumSelectedInputHint'
+
+ exit: ->
+ super()
+ DomUtils.removeElement @hintContainingDiv
+ if document.activeElement and DomUtils.isEditable document.activeElement
+ new InsertMode
+ singleton: "post-find-mode/focus-input"
+ targetElement: document.activeElement
+ indicator: false
+
root = exports ? (window.root ?= {})
root.NormalMode = NormalMode
root.NormalModeCommands = NormalModeCommands
--
cgit v1.2.3
From 722ba99720ed946f11e5672c7fbf0f1f34337576 Mon Sep 17 00:00:00 2001
From: mrmr1993
Date: Sun, 29 Oct 2017 12:05:40 +0000
Subject: Move findAndFollow* to mode_normal.coffee
---
content_scripts/mode_normal.coffee | 85 ++++++++++++++++++++++++++++++++++++++
1 file changed, 85 insertions(+)
(limited to 'content_scripts/mode_normal.coffee')
diff --git a/content_scripts/mode_normal.coffee b/content_scripts/mode_normal.coffee
index 9a03e9d0..8dad4b63 100644
--- a/content_scripts/mode_normal.coffee
+++ b/content_scripts/mode_normal.coffee
@@ -217,6 +217,91 @@ textInputXPath = (->
DomUtils.makeXPath(inputElements)
)()
+# used by the findAndFollow* functions.
+followLink = (linkElement) ->
+ if (linkElement.nodeName.toLowerCase() == "link")
+ window.location.href = linkElement.href
+ else
+ # if we can click on it, don't simply set location.href: some next/prev links are meant to trigger AJAX
+ # calls, like the 'more' button on GitHub's newsfeed.
+ linkElement.scrollIntoView()
+ DomUtils.simulateClick(linkElement)
+
+#
+# Find and follow a link which matches any one of a list of strings. If there are multiple such links, they
+# are prioritized for shortness, by their position in :linkStrings, how far down the page they are located,
+# and finally by whether the match is exact. Practically speaking, this means we favor 'next page' over 'the
+# next big thing', and 'more' over 'nextcompany', even if 'next' occurs before 'more' in :linkStrings.
+#
+findAndFollowLink = (linkStrings) ->
+ linksXPath = DomUtils.makeXPath(["a", "*[@onclick or @role='link' or contains(@class, 'button')]"])
+ links = DomUtils.evaluateXPath(linksXPath, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE)
+ candidateLinks = []
+
+ # at the end of this loop, candidateLinks will contain all visible links that match our patterns
+ # links lower in the page are more likely to be the ones we want, so we loop through the snapshot backwards
+ for i in [(links.snapshotLength - 1)..0] by -1
+ link = links.snapshotItem(i)
+
+ # ensure link is visible (we don't mind if it is scrolled offscreen)
+ boundingClientRect = link.getBoundingClientRect()
+ if (boundingClientRect.width == 0 || boundingClientRect.height == 0)
+ continue
+ computedStyle = window.getComputedStyle(link, null)
+ if (computedStyle.getPropertyValue("visibility") != "visible" ||
+ computedStyle.getPropertyValue("display") == "none")
+ continue
+
+ linkMatches = false
+ for linkString in linkStrings
+ if link.innerText.toLowerCase().indexOf(linkString) != -1 ||
+ 0 <= link.value?.indexOf? linkString
+ linkMatches = true
+ break
+ continue unless linkMatches
+
+ candidateLinks.push(link)
+
+ return if (candidateLinks.length == 0)
+
+ for link in candidateLinks
+ link.wordCount = link.innerText.trim().split(/\s+/).length
+
+ # We can use this trick to ensure that Array.sort is stable. We need this property to retain the reverse
+ # in-page order of the links.
+
+ candidateLinks.forEach((a,i) -> a.originalIndex = i)
+
+ # favor shorter links, and ignore those that are more than one word longer than the shortest link
+ candidateLinks =
+ candidateLinks
+ .sort((a, b) ->
+ if (a.wordCount == b.wordCount) then a.originalIndex - b.originalIndex else a.wordCount - b.wordCount
+ )
+ .filter((a) -> a.wordCount <= candidateLinks[0].wordCount + 1)
+
+ for linkString in linkStrings
+ exactWordRegex =
+ if /\b/.test(linkString[0]) or /\b/.test(linkString[linkString.length - 1])
+ new RegExp "\\b" + linkString + "\\b", "i"
+ else
+ new RegExp linkString, "i"
+ for candidateLink in candidateLinks
+ if exactWordRegex.test(candidateLink.innerText) ||
+ (candidateLink.value && exactWordRegex.test(candidateLink.value))
+ followLink(candidateLink)
+ return true
+ false
+
+findAndFollowRel = (value) ->
+ relTags = ["link", "a", "area"]
+ for tag in relTags
+ elements = document.getElementsByTagName(tag)
+ for element in elements
+ if (element.hasAttribute("rel") && element.rel.toLowerCase() == value)
+ followLink(element)
+ return true
+
class FocusSelector extends Mode
constructor: (hints, visibleInputs, selectedInputIndex) ->
super
--
cgit v1.2.3
From 24148c709806d1631f35cd8efd3fdec4f2376f92 Mon Sep 17 00:00:00 2001
From: mrmr1993
Date: Sun, 29 Oct 2017 12:51:53 +0000
Subject: Guard against undefined DomUtils, instead of stubbing in tests
---
content_scripts/mode_normal.coffee | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'content_scripts/mode_normal.coffee')
diff --git a/content_scripts/mode_normal.coffee b/content_scripts/mode_normal.coffee
index 8dad4b63..ee05f4b0 100644
--- a/content_scripts/mode_normal.coffee
+++ b/content_scripts/mode_normal.coffee
@@ -214,7 +214,7 @@ textInputXPath = (->
"(" + textInputTypes.map((type) -> '@type="' + type + '"').join(" or ") + "or not(@type))" +
" and not(@disabled or @readonly)]",
"textarea", "*[@contenteditable='' or translate(@contenteditable, 'TRUE', 'true')='true']"]
- DomUtils.makeXPath(inputElements)
+ DomUtils?.makeXPath(inputElements)
)()
# used by the findAndFollow* functions.
--
cgit v1.2.3