aboutsummaryrefslogtreecommitdiffstats
path: root/lib/handler_stack.coffee
diff options
context:
space:
mode:
authorStephen Blott2015-01-07 09:57:03 +0000
committerStephen Blott2015-01-07 09:57:03 +0000
commit04ac4c64c9634d9f81035ff7e9db537f39b42f3c (patch)
treec61e1d5893916b0d3fa191e2aaf285ff7ae9629c /lib/handler_stack.coffee
parenta7fcfd9a663e2d81a86e5e49e54162399ccb5e6b (diff)
downloadvimium-04ac4c64c9634d9f81035ff7e9db537f39b42f3c.tar.bz2
Modes; rework Singletons, InsertModeBlocker and HandlerStack.
This begins work on addressing @philc's comments in #1413. That work is nevertheless not yet complete.
Diffstat (limited to 'lib/handler_stack.coffee')
-rw-r--r--lib/handler_stack.coffee32
1 files changed, 18 insertions, 14 deletions
diff --git a/lib/handler_stack.coffee b/lib/handler_stack.coffee
index 0a34087f..9da0bc33 100644
--- a/lib/handler_stack.coffee
+++ b/lib/handler_stack.coffee
@@ -15,8 +15,10 @@ class HandlerStack
@stopBubblingAndFalse = new Object()
# Adds a handler to the stack. Returns a unique ID for that handler that can be used to remove it later.
+ # We use unshift (which is more expensive than push) so that bubbleEvent can just iterate over the stack in
+ # the normal order.
push: (handler) ->
- @stack.push handler
+ @stack.unshift handler
handler.id = ++@counter
# Called whenever we receive a key or other event. Each individual handler has the option to stop the
@@ -25,26 +27,28 @@ class HandlerStack
bubbleEvent: (type, event) ->
# extra is passed to each handler. This allows handlers to pass information down the stack.
extra = {}
- for i in [(@stack.length - 1)..0] by -1
- handler = @stack[i]
- # We need to check for existence of handler because the last function call may have caused the release
- # of more than one handler.
- if handler and handler.id and handler[type]
+ for handler in @stack[..] # Take a copy of @stack, so that concurrent removes do not interfere.
+ # We need to check whether the handler has been removed (handler.id == null).
+ if handler and handler.id
@currentId = handler.id
- passThrough = handler[type].call @, event, extra
- if not passThrough
- DomUtils.suppressEvent(event) if @isChromeEvent event
- return false
- return true if passThrough == @stopBubblingAndTrue
- return false if passThrough == @stopBubblingAndFalse
+ # 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
true
remove: (id = @currentId) ->
# This is more expense than splicing @stack, but better because splicing can interfere with concurrent
# bubbleEvents.
@stack = @stack.filter (handler) ->
- # Mark this handler as removed (to notify any concurrent bubbleEvent call).
- if handler.id == id then handler.id = null
+ # Mark this handler as removed (so concurrent bubbleEvents will know not to invoke it).
+ handler.id = null if handler.id == id
handler?.id?
# The handler stack handles chrome events (which may need to be suppressed) and internal (fake) events.