diff options
| author | Stephen Blott | 2015-01-21 19:35:24 +0000 |
|---|---|---|
| committer | Stephen Blott | 2015-01-21 22:24:31 +0000 |
| commit | c4735264f46fdc62020c81bd8ff6f67ebd1dad9a (patch) | |
| tree | 98b6d4a3e01a2b7a71eacec3e2acacb843a8ea60 | |
| parent | 0ec38c1050b00845abaa2faa9f56d04c9d2b8992 (diff) | |
| download | vimium-c4735264f46fdc62020c81bd8ff6f67ebd1dad9a.tar.bz2 | |
Edit mode: first working visual mode.
| -rw-r--r-- | content_scripts/mode_edit.coffee | 12 | ||||
| -rw-r--r-- | content_scripts/mode_movement.coffee | 50 | ||||
| -rw-r--r-- | content_scripts/mode_visual.coffee | 45 | ||||
| -rw-r--r-- | lib/utils.coffee | 14 | ||||
| -rw-r--r-- | manifest.json | 1 |
5 files changed, 108 insertions, 14 deletions
diff --git a/content_scripts/mode_edit.coffee b/content_scripts/mode_edit.coffee index 32f2e796..0b17044a 100644 --- a/content_scripts/mode_edit.coffee +++ b/content_scripts/mode_edit.coffee @@ -1,11 +1,12 @@ -class EditMode extends Mode +class EditMode extends Movement @activeElements = [] constructor: (options = {}) -> defaults = name: "edit" exitOnEscape: true + alterMethod: "move" keydown: (event) => if @isActive() then @handleKeydown event else @continueBubbling keypress: (event) => if @isActive() then @handleKeypress event else @continueBubbling keyup: (event) => if @isActive() then @handleKeyup event else @continueBubbling @@ -14,9 +15,12 @@ class EditMode extends Mode if @element and DomUtils.isEditable @element super extend defaults, options - handleKeydown: (event) -> @suppressEvent - handleKeypress: (event) -> @suppressEvent - handleKeyup: (event) -> @suppressEvent + handleKeydown: (event) -> + @stopBubblingAndTrue + handleKeypress: (event) -> + @suppressEvent + handleKeyup: (event) -> + @stopBubblingAndTrue isActive: -> document.activeElement and DomUtils.isDOMDescendant @element, document.activeElement diff --git a/content_scripts/mode_movement.coffee b/content_scripts/mode_movement.coffee new file mode 100644 index 00000000..c81b698a --- /dev/null +++ b/content_scripts/mode_movement.coffee @@ -0,0 +1,50 @@ + +class Movement extends Mode + movements: + h: "backward character" + l: "forward character" + k: "backward line" + j: "forward line" + b: "backward word" + e: "forward word" + + constructor: (options) -> + @countPrefix = "" + @alterMethod = options.alterMethod + super options + + isNumberKey = (keyChar) -> + keyChar.length == 1 and "0" <= keyChar <= "9" + + @push + keydown: (event) => @alwaysContinueBubbling => + unless event.metaKey or event.ctrlKey or event.altKey + keyChar = KeyboardUtils.getKeyChar event + @countPrefix += keyChar if isNumberKey keyChar + keyup: (event) => @alwaysContinueBubbling => + # FIXME(smblott). Need to revisit these test. They do not cover all cases correctly. + unless event.metaKey or event.ctrlKey or event.altKey or event.keyCode == keyCodes.shiftKey + keyChar = KeyboardUtils.getKeyChar event + if keyChar and not isNumberKey keyChar + @countPrefix = "" + + move: (keyChar) -> + if @movements[keyChar] + Utils.suppressor.suppress Movement, => + countPrefix = if 0 < @countPrefix.length then parseInt @countPrefix else 1 + @countPrefix = "" + for [0...countPrefix] + if "string" == typeof @movements[keyChar] + window.getSelection().modify @alterMethod, @movements[keyChar].split(/\s+/)... + else if "function" == typeof @movements[keyChar] + @movements[keyChar]() + Utils.suppressor.unlessSuppressed Movement, => @postMove?() + + isMoveChar: (event, keyChar) -> + return false if event.metaKey or event.ctrlKey or event.altKey + @movements[keyChar] + +# setTimeout (-> new Movement {}), 500 + +root = exports ? window +root.Movement = Movement diff --git a/content_scripts/mode_visual.coffee b/content_scripts/mode_visual.coffee index 2580106d..36501f3e 100644 --- a/content_scripts/mode_visual.coffee +++ b/content_scripts/mode_visual.coffee @@ -1,20 +1,45 @@ -class VisualMode extends Mode - constructor: (element=null) -> - super +class VisualMode extends Movement + constructor: (options = {}) -> + defaults = name: "visual" badge: "V" exitOnEscape: true - exitOnBlur: element - - keydown: (event) => - return @suppressEvent + exitOnBlur: options.targetElement + alterMethod: "extend" + keydown: (event) => @handleKeyEvent event, KeyboardUtils.getKeyChar event + keyup: (event) => @handleKeyEvent event, KeyboardUtils.getKeyChar event keypress: (event) => - return @suppressEvent + keyChar = String.fromCharCode event.charCode + @handleKeyEvent event, keyChar, => @move keyChar + + super extend defaults, options + + handleKeyEvent: (event, keyChar, func = ->) -> + if event.metaKey or event.ctrlKey or event.altKey + @stopBubblingAndTrue + else if event.type == "keypress" and @isMoveChar event, keyChar + func keyChar + @suppressEvent + else if @handleVisualModeKey(keyChar) or @isMoveChar event, keyChar + DomUtils.suppressPropagation + @stopBubblingAndTrue + else if KeyboardUtils.isPrintable event + @suppressEvent + else + @stopBubblingAndTrue - keyup: (event) => - return @suppressEvent + handleVisualModeKey: (keyChar) -> + switch keyChar + when "y" + chrome.runtime.sendMessage + handler: "copyToClipboard" + data: window.getSelection().toString() + @exit() + true + else + false root = exports ? window root.VisualMode = VisualMode diff --git a/lib/utils.coffee b/lib/utils.coffee index 661f7e84..f8eb5457 100644 --- a/lib/utils.coffee +++ b/lib/utils.coffee @@ -152,6 +152,20 @@ Utils = # locale-sensitive uppercase detection hasUpperCase: (s) -> s.toLowerCase() != s + # Allow a function call to be suppressed. Use Utils.suppress.unlessSuppressed to call a function, unless it + # is suppressed via the given key. Use Utils.suppressor.suppress to call a function while suppressing the + # given key. + suppressor: do -> + suppressed = {} + + suppress: (key, func) -> + suppressed[key] = if suppressed[key]? then suppressed[key] + 1 else 1 + func() + suppressed[key] -= 1 + + unlessSuppressed: (key, func) -> + func() unless suppressed[key]? and 0 < suppressed[key] + # This creates a new function out of an existing function, where the new function takes fewer arguments. This # allows us to pass around functions instead of functions + a partial list of arguments. Function::curry = -> diff --git a/manifest.json b/manifest.json index e8b0f8ee..23c9c1e3 100644 --- a/manifest.json +++ b/manifest.json @@ -47,6 +47,7 @@ "content_scripts/mode_insert.js", "content_scripts/mode_passkeys.js", "content_scripts/mode_find.js", + "content_scripts/mode_movement.js", "content_scripts/mode_visual.js", "content_scripts/mode_edit.js", "content_scripts/vimium_frontend.js" |
