diff options
| -rw-r--r-- | content_scripts/mode_visual_edit.coffee | 144 | ||||
| -rw-r--r-- | lib/keyboard_utils.coffee | 4 | 
2 files changed, 94 insertions, 54 deletions
| diff --git a/content_scripts/mode_visual_edit.coffee b/content_scripts/mode_visual_edit.coffee index f6f6a318..d3d51575 100644 --- a/content_scripts/mode_visual_edit.coffee +++ b/content_scripts/mode_visual_edit.coffee @@ -85,6 +85,13 @@ class Movement extends CountPrefix          @paste (text) =>            func(); @copy text; locked = false +  changeMode: (mode, options = {}) -> +    @exit() +    if @options.parentMode +      @options.parentMode.launchSubMode mode, options +    else +      new mode +    # Return the character following the focus, and leave the selection unchanged.    nextCharacter: ->      beforeText = @selection.toString() @@ -229,7 +236,7 @@ class Movement extends CountPrefix      @movements.W = @movements.w      if @options.immediateMovement -      @handleMovementKeyChar @options.immediateMovement, @getCountPrefix() +      @runMovementKeyChar @options.immediateMovement, @getCountPrefix()        return      @push @@ -251,22 +258,24 @@ class Movement extends CountPrefix                  return @suppressEvent                else if @movements[command] -                @handleMovementKeyChar command, @getCountPrefix() +                @runMovementKeyChar command, @getCountPrefix()                  return @suppressEvent          @continueBubbling +      #      # End of Movement constructor. +  runMovementKeyChar: (args...) -> +    @protectClipboard => @handleMovementKeyChar args... +    handleMovementKeyChar: (keyChar, count = 1) -> -    @protectClipboard => -      switch typeof @movements[keyChar] -        when "string" -          @runMovement @movements[keyChar] for [0...count] -        when "function" -          @movements[keyChar].call @, count -      @scrollIntoView() -      @yank() if @options.oneMovementOnly +    switch typeof @movements[keyChar] +      when "string" +        @runMovement @movements[keyChar] for [0...count] +      when "function" +        @movements[keyChar].call @, count +    @scrollIntoView()    # Yank the selection; always exits; either deletes the selection or collapses it; returns the yanked text.    yank: (args = {}) -> @@ -322,16 +331,6 @@ class VisualMode extends Movement      @selection = window.getSelection()      @alterMethod = "extend" -    switch @selection.type -      when "None" -        unless @establishInitialSelection() -          HUD.showForDuration "Create a selection before entering visual mode.", 2500 -          return -      when "Caret" -        # Try to make the selection visible (unless we're under a parent mode, such as edit mode). -        @extendByOneCharacter(forward) or @extendByOneCharacter backward unless options.parentMode -        @scrollIntoView() if @selection.type == "Range" -      defaults =        name: "visual"        badge: "V" @@ -339,17 +338,27 @@ class VisualMode extends Movement        exitOnEscape: true      super extend defaults, options +    switch @selection.type +      when "None" +        return @changeMode CaretMode +      when "Caret" +        @selection.modify "extend", forward, character + +    # Yank on <Enter>. +    @push +      _name: "#{@id}/enter" +      keypress: (event) => +        if event.keyCode == keyCodes.enter and not (event.metaKey or event.ctrlKey or event.altKey) +          @yank(); @suppressEvent +        else @continueBubbling +      # Visual-mode commands.      unless @options.oneMovementOnly        @commands.y = -> @yank()        @commands.p = -> chrome.runtime.sendMessage handler: "openUrlInCurrentTab", url: @yank()        @commands.P = -> chrome.runtime.sendMessage handler: "openUrlInNewTab", url: @yank() -      @commands.V = -> -        @exit() -        if @options.parentMode -          @options.parentMode.launchSubMode VisualLineMode -        else -          new VisualLineMode +      @commands.V = -> @changeMode VisualLineMode +      @commands.c = -> @changeMode CaretMode      # Additional commands when run under edit mode (except if only for one movement).      if @options.parentMode and not @options.oneMovementOnly @@ -394,6 +403,10 @@ class VisualMode extends Movement        console.log "yank:", @yankedText if @debug        @copy @yankedText, true +  handleMovementKeyChar: (args...) -> +    super args... +    @yank() if @options.oneMovementOnly +    selectLine: (count, collapse) ->      @runMovement backward, "lineboundary"      @collapseSelectionToFocus() if collapse @@ -435,36 +448,11 @@ class VisualMode extends Movement      @movements.n = (count) -> executeFind false      @movements.N = (count) -> executeFind true -  # When visual mode starts and there's no existing selection, we try to establish one.  As a heuristic, we -  # pick the first non-whitespace character of the first visible text node which seems to be long enough to be -  # interesting. -  establishInitialSelection: -> -    nodes = document.createTreeWalker document.body, NodeFilter.SHOW_TEXT -    while node = nodes.nextNode() -      # Don't pick really short texts; they're likely to be part of a banner. -      if node.nodeType == 3 and 50 <= node.data.trim().length -        element = node.parentElement -        if DomUtils.getVisibleClientRect(element) and not DomUtils.isEditable element -          offset = node.data.length - node.data.replace(/^\s+/, "").length -          range = document.createRange() -          range.setStart node, offset -          range.setEnd node, offset + 1 -          @selectRange range -          @scrollIntoView() -          return true -    false -  class VisualLineMode extends VisualMode    constructor: (options = {}) ->      super extend { name: "visual/line" }, options      @extendSelection() - -    @commands.v = -> -      @exit() -      if @options.parentMode -        @options.parentMode.launchSubMode VisualMode -      else -        new VisualMode +    @commands.v = -> @changeMode VisualMode    handleMovementKeyChar: (args...) ->      super args... @@ -476,6 +464,58 @@ class VisualLineMode extends VisualMode        @runMovement direction, "lineboundary"        @reverseSelection() +class CaretMode extends Movement +  constructor: (options = {}) -> +    @alterMethod = "move" + +    defaults = +      name: "caret" +      badge: "C" +      singleton: VisualMode +      exitOnEscape: true +    super extend defaults, options + +    if @selection.type == "None" +      @establishInitialSelection() + +    switch @selection.type +      when "None" +        HUD.showForDuration "Create a selection before entering visual mode.", 2500 +        @exit() +        return +      when "Range" +        @collapseSelectionToFocus() + +    @selection.modify "extend", forward, character +    @scrollIntoView() + +    extend @commands, +      v: -> @changeMode VisualMode +      V: -> @changeMode VisualLineMode + +  handleMovementKeyChar: (args...) -> +    @collapseSelectionToAnchor() +    super args... +    @selection.modify "extend", forward, character + +  # When visual mode starts and there's no existing selection, we launch CaretMode and try to establish a +  # selection.  As a heuristic, we pick the first non-whitespace character of the first visible text node +  # which seems to be long enough to be interesting. +  establishInitialSelection: -> +    nodes = document.createTreeWalker document.body, NodeFilter.SHOW_TEXT +    while node = nodes.nextNode() +      # Don't pick really short texts; they're likely to be part of a banner. +      if node.nodeType == 3 and 50 <= node.data.trim().length +        element = node.parentElement +        if DomUtils.getVisibleClientRect(element) and not DomUtils.isEditable element +          offset = node.data.length - node.data.replace(/^\s+/, "").length +          range = document.createRange() +          range.setStart node, offset +          range.setEnd node, offset+1 +          @selectRange range +          return true +    false +  class EditMode extends Movement    constructor: (options = {}) ->      @element = document.activeElement diff --git a/lib/keyboard_utils.coffee b/lib/keyboard_utils.coffee index 02c26610..cdc66e19 100644 --- a/lib/keyboard_utils.coffee +++ b/lib/keyboard_utils.coffee @@ -1,7 +1,7 @@  KeyboardUtils =    keyCodes: -    { ESC: 27, backspace: 8, deleteKey: 46, enter: 13, space: 32, shiftKey: 16, ctrlKey: 17, f1: 112, -    f12: 123, tab: 9 } +    { ESC: 27, backspace: 8, deleteKey: 46, enter: 13, ctrlEnter: 10, space: 32, shiftKey: 16, ctrlKey: 17, +    f1: 112, f12: 123, tab: 9 }    keyNames:      { 37: "left", 38: "up", 39: "right", 40: "down" } | 
