From 291e7fd67de9e1c4bd0bc5048ab7344424f19b30 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Wed, 3 Jun 2015 15:27:45 +0100 Subject: Re-implement Marks, incl `` binding. --- background_scripts/commands.coffee | 2 +- content_scripts/marks.coffee | 94 +++++++++++++++++++++------------- content_scripts/mode.coffee | 2 +- content_scripts/vimium_frontend.coffee | 17 ++++-- 4 files changed, 72 insertions(+), 43 deletions(-) diff --git a/background_scripts/commands.coffee b/background_scripts/commands.coffee index 64ec36be..b9ab274c 100644 --- a/background_scripts/commands.coffee +++ b/background_scripts/commands.coffee @@ -30,7 +30,7 @@ Commands = return options ?= [] - @keyToCommandRegistry[key] = extend { command, options }, @availableCommands[command] + @keyToCommandRegistry[key] = extend { command, options, key }, @availableCommands[command] # Lower-case the appropriate portions of named keys. # diff --git a/content_scripts/marks.coffee b/content_scripts/marks.coffee index 8ba45fd4..fab509a7 100644 --- a/content_scripts/marks.coffee +++ b/content_scripts/marks.coffee @@ -1,57 +1,77 @@ -exit = (mode, continuation = null) -> - mode.exit() - continuation?() - Marks = + mode: null + previousPosition: null + + exit: (continuation = null) -> + @mode?.exit() + @mode = null + continuation?() + + # This returns the key which is used for storing mark locations in localStorage. + getLocationKey: (keyChar) -> + "vimiumMark|#{window.location.href.split('#')[0]}|#{keyChar}" + + showMessage: (message, keyChar) -> + HUD.showForDuration "#{message} \"#{keyChar}\".", 1000 + activateCreateMode: -> - mode = new Mode + @mode = new Mode name: "create-mark" - indicator: "Create mark?" + indicator: "Create mark..." suppressAllKeyboardEvents: true - keydown: (event) -> - keyChar = KeyboardUtils.getKeyChar(event) - if /[A-Z]/.test keyChar - exit mode, -> + keypress: (event) => + keyChar = String.fromCharCode event.charCode + # If is depressed, then it's a global mark, otherwise it's a local mark. This is consistent + # vim's [A-Z] for global marks, [a-z] for local marks. However, it also admits other non-Latin + # characters. + if event.shiftKey + @exit => chrome.runtime.sendMessage handler: 'createMark' markName: keyChar scrollX: window.scrollX scrollY: window.scrollY - , -> HUD.showForDuration "Created global mark '#{keyChar}'.", 1000 - else if /[a-z]/.test keyChar - [baseLocation, sep, hash] = window.location.href.split '#' - localStorage["vimiumMark|#{baseLocation}|#{keyChar}"] = JSON.stringify - scrollX: window.scrollX, - scrollY: window.scrollY - exit mode, -> HUD.showForDuration "Created local mark '#{keyChar}'.", 1000 - else if not event.shiftKey - exit mode - - activateGotoMode: -> - mode = new Mode + , => @showMessage "Created global mark", keyChar + else + @exit => @markPosition keyChar + + markPosition: (keyChar = null) -> + markString = JSON.stringify scrollX: window.scrollX, scrollY: window.scrollY + if keyChar? + localStorage[@getLocationKey keyChar] = markString + @showMessage "Created local mark", keyChar + else + @previousPosition = markString + + activateGotoMode: (registryEntry) -> + # We pick off the last character of the key sequence used to launch this command. Usually this is just "`". + # We then use that character, so together usually the sequence "``", to jump back to the previous + # position. The "previous position" is recorded below, and is registered via @markPosition() elsewhere + # for various other jump-like commands. + previousPositionKey = registryEntry.key[registryEntry.key.length-1..] + @mode = new Mode name: "goto-mark" - indicator: "Go to mark?" + indicator: "Go to mark..." suppressAllKeyboardEvents: true - keydown: (event) -> - keyChar = KeyboardUtils.getKeyChar(event) - if /[A-Z]/.test keyChar - exit mode, -> + keypress: (event) => + keyChar = String.fromCharCode event.charCode + if event.shiftKey + @exit -> chrome.runtime.sendMessage handler: 'gotoMark' markName: keyChar - else if /[a-z]/.test keyChar - [baseLocation, sep, hash] = window.location.href.split '#' - markString = localStorage["vimiumMark|#{baseLocation}|#{keyChar}"] - exit mode, -> + else + markString = + if keyChar == previousPositionKey then @previousPosition else localStorage[@getLocationKey keyChar] + @exit => if markString? - mark = JSON.parse markString - window.scrollTo mark.scrollX, mark.scrollY - HUD.showForDuration "Jumped to local mark '#{keyChar}'", 1000 + @markPosition() + position = JSON.parse markString + window.scrollTo position.scrollX, position.scrollY + @showMessage "Jumped to local mark", keyChar else - HUD.showForDuration "Local mark not set: '#{keyChar}'.", 1000 - else if not event.shiftKey - exit mode + @showMessage "Local mark not set", keyChar root = exports ? window root.Marks = Marks diff --git a/content_scripts/mode.coffee b/content_scripts/mode.coffee index cbcc15f7..22b6120f 100644 --- a/content_scripts/mode.coffee +++ b/content_scripts/mode.coffee @@ -54,7 +54,7 @@ class Mode for type in [ "keydown", "keypress", "keyup" ] do (type) => handler = @options[type] - @options[type] = (event) -> handler? event; false + @options[type] = (event) => handler? event; @stopBubblingAndFalse @push keydown: @options.keydown || null diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index 7ad75514..9ff9b6db 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -241,9 +241,10 @@ unregisterFrame = -> tab_is_closing: DomUtils.isTopFrame() executePageCommand = (request) -> + commandType = request.command.split(".")[0] # Vomnibar commands are handled in the tab's main/top frame. They are handled even if Vimium is otherwise # disabled in the frame. - if request.command.split(".")[0] == "Vomnibar" + if commandType == "Vomnibar" if DomUtils.isTopFrame() # We pass the frameId from request. That's the frame which originated the request, so that's the frame # which should receive the focus when the vomnibar closes. @@ -254,7 +255,9 @@ executePageCommand = (request) -> # All other commands are handled in their frame (but only if Vimium is enabled). return unless frameId == request.frameId and isEnabledForUrl - if request.registryEntry.passCountToFunction + if commandType == "Marks" + Utils.invokeCommandString request.command, [request.registryEntry] + else if request.registryEntry.passCountToFunction Utils.invokeCommandString(request.command, [request.count]) else Utils.invokeCommandString(request.command) for i in [0...request.count] @@ -299,8 +302,12 @@ window.focusThisFrame = do -> setTimeout (-> highlightedFrameElement.remove()), 200 extend window, - scrollToBottom: -> Scroller.scrollTo "y", "max" - scrollToTop: -> Scroller.scrollTo "y", 0 + scrollToBottom: -> + Marks.markPosition() + Scroller.scrollTo "y", "max" + scrollToTop: -> + Marks.markPosition() + Scroller.scrollTo "y", 0 scrollToLeft: -> Scroller.scrollTo "x", 0 scrollToRight: -> Scroller.scrollTo "x", "max" scrollUp: -> Scroller.scrollBy "y", -1 * Settings.get("scrollStepSize") @@ -861,6 +868,7 @@ window.getFindModeQuery = (backwards) -> findModeQuery.parsedQuery findAndFocus = (backwards) -> + Marks.markPosition() query = getFindModeQuery backwards findModeQueryHasResults = @@ -1007,6 +1015,7 @@ findModeRestoreSelection = (range = findModeInitialRange) -> # Enters find mode. Returns the new find-mode instance. window.enterFindMode = (options = {}) -> + Marks.markPosition() # Save the selection, so performFindInPlace can restore it. findModeSaveSelection() findModeQuery = rawQuery: "" -- cgit v1.2.3