aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorStephen Blott2015-01-10 18:53:28 +0000
committerStephen Blott2015-01-10 18:53:28 +0000
commitd1c0a5d9bd1f67f2b32a993cfd62bc0b52c44185 (patch)
tree76eaa3b86be1c6ac130724168d0bf3bbbb6849c5 /lib
parent93de6384632e3e682e02be4cb8cea160997de127 (diff)
parent80ad0bc3087a3bf00d61bdd6c9cf48e971e22480 (diff)
downloadvimium-d1c0a5d9bd1f67f2b32a993cfd62bc0b52c44185.tar.bz2
Merge branch 'modes-dev' into modes
Diffstat (limited to 'lib')
-rw-r--r--lib/dom_utils.coffee1
-rw-r--r--lib/handler_stack.coffee71
-rw-r--r--lib/keyboard_utils.coffee6
3 files changed, 60 insertions, 18 deletions
diff --git a/lib/dom_utils.coffee b/lib/dom_utils.coffee
index 9d7ca867..322188b3 100644
--- a/lib/dom_utils.coffee
+++ b/lib/dom_utils.coffee
@@ -206,6 +206,7 @@ DomUtils =
# Suppress the next keyup event for Escape.
suppressKeyupAfterEscape: (handlerStack) ->
handlerStack.push
+ _name: "dom_utils/suppressKeyupAfterEscape"
keyup: (event) ->
return true unless KeyboardUtils.isEscape event
@remove()
diff --git a/lib/handler_stack.coffee b/lib/handler_stack.coffee
index 97e189c5..22d04941 100644
--- a/lib/handler_stack.coffee
+++ b/lib/handler_stack.coffee
@@ -3,6 +3,8 @@ root = exports ? window
class HandlerStack
constructor: ->
+ @debug = false
+ @eventNumber = 0
@stack = []
@counter = 0
@@ -14,11 +16,18 @@ class HandlerStack
# processing should take place.
@stopBubblingAndFalse = new Object()
+ # A handler should return this value to indicate that bubbling should be restarted. Typically, this is
+ # used when, while bubbling an event, a new mode is pushed onto the stack. See `focusInput` for an
+ # example.
+ @restartBubbling = new Object()
+
# Adds a handler to the top of the stack. Returns a unique ID for that handler that can be used to remove it
# later.
push: (handler) ->
- @stack.push handler
handler.id = ++@counter
+ handler._name ||= "anon-#{@counter}"
+ @stack.push handler
+ handler.id
# Adds a handler to the bottom of the stack. Returns a unique ID for that handler that can be used to remove
# it later.
@@ -30,30 +39,28 @@ class HandlerStack
# event's propagation by returning a falsy value, or stop bubbling by returning @stopBubblingAndFalse or
# @stopBubblingAndTrue.
bubbleEvent: (type, event) ->
- # extra is passed to each handler. This allows handlers to pass information down the stack.
- extra = {}
- # We take a copy of the array, here, in order to avoid interference from concurrent removes (for example,
- # to avoid calling the same handler twice).
+ @eventNumber += 1
+ # We take a copy of the array in order to avoid interference from concurrent removes (for example, to
+ # avoid calling the same handler twice, because elements have been spliced out of the array by remove).
for handler in @stack[..].reverse()
- # A handler may have been removed (handler.id == null).
- if handler and handler.id
+ # A handler may have been removed (handler.id == null), so check.
+ if handler?.id and handler[type]
@currentId = handler.id
- # A handler can register a handler for type "all", which will be invoked on all events. Such an "all"
- # handler will be invoked first.
- for func in [ handler.all, handler[type] ]
- if func
- passThrough = func.call @, event, extra
- if not passThrough
- DomUtils.suppressEvent(event) if @isChromeEvent event
- return false
- return true if passThrough == @stopBubblingAndTrue
- return false if passThrough == @stopBubblingAndFalse
+ result = handler[type].call @, event
+ @logResult type, event, handler, result if @debug
+ if not result
+ DomUtils.suppressEvent(event) if @isChromeEvent event
+ return false
+ return true if result == @stopBubblingAndTrue
+ return false if result == @stopBubblingAndFalse
+ return @bubbleEvent type, event if result == @restartBubbling
true
remove: (id = @currentId) ->
for i in [(@stack.length - 1)..0] by -1
handler = @stack[i]
if handler.id == id
+ # Mark the handler as removed.
handler.id = null
@stack.splice(i, 1)
break
@@ -63,7 +70,9 @@ class HandlerStack
isChromeEvent: (event) ->
event?.preventDefault? or event?.stopImmediatePropagation?
- # Convenience wrappers.
+ # Convenience wrappers. Handlers must return an approriate value. These are wrappers which handlers can
+ # use to always return the same value. This then means that the handler itself can be implemented without
+ # regard to its return value.
alwaysContinueBubbling: (handler) ->
handler()
true
@@ -72,5 +81,31 @@ class HandlerStack
handler()
false
+ # Debugging.
+ debugOn: -> @debug = true
+ debugOff: -> @debug = false
+
+ logResult: (type, event, handler, result) ->
+ # FIXME(smblott). Badge updating is too noisy, so we filter it out. However, we do need to look at how
+ # many badge update events are happening. It seems to be more than necessary.
+ return if type == "updateBadge"
+ label =
+ switch result
+ when @stopBubblingAndTrue then "stop/true"
+ when @stopBubblingAndFalse then "stop/false"
+ when @restartBubbling then "rebubble"
+ when true then "continue"
+ label ||= if result then "continue/truthy" else "suppress"
+ @log @eventNumber, type, handler._name, label
+
+ logRecords: []
+ log: (args...) ->
+ line = args.join " "
+ @logRecords.push line
+ console.log line
+
+ clipLog: ->
+ Clipboard.copy logRecords.join "\n"
+
root.HandlerStack = HandlerStack
root.handlerStack = new HandlerStack
diff --git a/lib/keyboard_utils.coffee b/lib/keyboard_utils.coffee
index d2a843f9..30d99656 100644
--- a/lib/keyboard_utils.coffee
+++ b/lib/keyboard_utils.coffee
@@ -55,6 +55,12 @@ KeyboardUtils =
# c-[ is mapped to ESC in Vim by default.
(event.keyCode == @keyCodes.ESC) || (event.ctrlKey && @getKeyChar(event) == '[')
+ # TODO. This is probably a poor way of detecting printable characters. However, it shouldn't incorrectly
+ # identify any of chrome's own keyboard shortcuts as printable.
+ isPrintable: (event) ->
+ return false if event.metaKey or event.ctrlKey or event.altKey
+ @getKeyChar(event)?.length == 1
+
KeyboardUtils.init()
root = exports ? window