aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Blott2016-03-30 13:07:05 +0100
committerStephen Blott2016-03-30 14:58:46 +0100
commit21da3fcafbb29540788037dbcdbdce79ad14e650 (patch)
tree0d4ff357c8cfd25226cb8dd6bf07d398ed3dfb03
parenta2fba970e089254adae2631a5b154e6bd92ec1e2 (diff)
downloadvimium-21da3fcafbb29540788037dbcdbdce79ad14e650.tar.bz2
Rename handlerStack constants.
Problems: - The meanings of some of the Mode/handlerStack constant names is far from obvious. - The same thing is named different things in different places. This changes various constant names such that: - the names used in the handler stack and in the modes are the same. - ditto vis-a-vis DomUtils. Also, break out the core of the handler stacks' `bubbleEvent` method into a switch statements. This makes it more obvious that the cases are mutually exclusive.
-rw-r--r--content_scripts/link_hints.coffee1
-rw-r--r--content_scripts/mode.coffee36
-rw-r--r--content_scripts/mode_insert.coffee8
-rw-r--r--content_scripts/mode_key_handler.coffee10
-rw-r--r--lib/handler_stack.coffee55
-rw-r--r--tests/unit_tests/handler_stack_test.coffee9
6 files changed, 66 insertions, 53 deletions
diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee
index 59649e5d..254d9811 100644
--- a/content_scripts/link_hints.coffee
+++ b/content_scripts/link_hints.coffee
@@ -750,7 +750,6 @@ class WaitForEnter extends Mode
else if KeyboardUtils.isEscape event
@exit()
callback false # false -> isSuccess.
- DomUtils.suppressEvent event
root = exports ? window
root.LinkHints = LinkHints
diff --git a/content_scripts/mode.coffee b/content_scripts/mode.coffee
index 317fbc86..37321660 100644
--- a/content_scripts/mode.coffee
+++ b/content_scripts/mode.coffee
@@ -31,12 +31,15 @@ class Mode
@modes: []
# Constants; short, readable names for the return values expected by handlerStack.bubbleEvent.
- continueBubbling: true
- suppressEvent: false
- stopBubblingAndTrue: handlerStack.stopBubblingAndTrue
- stopBubblingAndFalse: handlerStack.stopBubblingAndFalse
+ continueBubbling: handlerStack.continueBubbling
+ suppressEvent: handlerStack.suppressEvent
+ passEventToPage: handlerStack.passEventToPage
+ suppressPropagation: handlerStack.suppressPropagation
restartBubbling: handlerStack.restartBubbling
+ alwaysContinueBubbling: handlerStack.alwaysContinueBubbling
+ alwaysSuppressPropagation: handlerStack.alwaysSuppressPropagation
+
constructor: (@options = {}) ->
@handlers = []
@exitHandlers = []
@@ -53,7 +56,8 @@ class Mode
# or 2) to worry about event suppression and event-handler return values.
if @options.suppressAllKeyboardEvents
for type in [ "keydown", "keypress", "keyup" ]
- @options[type] = @alwaysSuppressEvent @options[type]
+ do (handler = @options[type]) =>
+ @options[type] = (event) => @alwaysSuppressPropagation => handler? event
@push
keydown: @options.keydown || null
@@ -67,7 +71,7 @@ class Mode
if @options.indicator?
if HUD?.isReady()
if @options.indicator then HUD.show @options.indicator else HUD.hide true, false
- @stopBubblingAndTrue
+ @passEventToPage
else @continueBubbling
# If @options.exitOnEscape is truthy, then the mode will exit when the escape key is pressed.
@@ -126,7 +130,7 @@ class Mode
_name: "mode-#{@id}/passInitialKeyupEvents"
keydown: => @alwaysContinueBubbling -> handlerStack.remove()
keyup: (event) =>
- if KeyboardUtils.isPrintable event then @stopBubblingAndFalse else @stopBubblingAndTrue
+ if KeyboardUtils.isPrintable event then @suppressPropagation else @passEventToPage
# if @options.suppressTrailingKeyEvents is set, then -- on exit -- we suppress all key events until a
# subsquent (non-repeat) keydown or keypress. In particular, the intention is to catch keyup events for
@@ -136,16 +140,16 @@ class Mode
@onExit ->
handler = (event) ->
if event.repeat
- false # Suppress event.
+ handlerStack.suppressEvent
else
keyEventSuppressor.exit()
- true # Do not suppress event.
+ handlerStack.continueBubbling
keyEventSuppressor = new Mode
name: "suppress-trailing-key-events"
keydown: handler
keypress: handler
- keyup: -> handlerStack.stopBubblingAndFalse
+ keyup: -> handlerStack.suppressPropagation
Mode.modes.push this
@setIndicator()
@@ -181,18 +185,6 @@ class Mode
@modeIsActive = false
@setIndicator()
- # Shorthand for an otherwise long name. This wraps a handler with an arbitrary return value, and always
- # yields @continueBubbling instead. This simplifies handlers if they always continue bubbling (a common
- # case), because they do not need to be concerned with the value they yield.
- alwaysContinueBubbling: handlerStack.alwaysContinueBubbling
-
- # Shorthand for an event handler which always suppresses event propagation.
- alwaysSuppressEvent: (handler = null) ->
- (event) =>
- handler? event
- DomUtils.suppressPropagation event
- @stopBubblingAndFalse
-
# Debugging routines.
logModes: ->
if Mode.debug
diff --git a/content_scripts/mode_insert.coffee b/content_scripts/mode_insert.coffee
index f86038d6..9cab52e1 100644
--- a/content_scripts/mode_insert.coffee
+++ b/content_scripts/mode_insert.coffee
@@ -16,7 +16,7 @@ class InsertMode extends Mode
new PassNextKeyMode
return false
- return @stopBubblingAndTrue unless event.type == 'keydown' and KeyboardUtils.isEscape event
+ return @passEventToPage unless event.type == 'keydown' and KeyboardUtils.isEscape event
DomUtils.suppressKeyupAfterEscape handlerStack
target = event.srcElement
if target and DomUtils.isFocusable target
@@ -115,19 +115,19 @@ class PassNextKeyMode extends Mode
# We exit on blur because, once we lose the focus, we can no longer track key events.
exitOnBlur: window
keypress: =>
- @stopBubblingAndTrue
+ @passEventToPage
keydown: =>
seenKeyDown = true
keyDownCount += 1
- @stopBubblingAndTrue
+ @passEventToPage
keyup: =>
if seenKeyDown
unless 0 < --keyDownCount
unless 0 < --count
@exit()
- @stopBubblingAndTrue
+ @passEventToPage
root = exports ? window
root.InsertMode = InsertMode
diff --git a/content_scripts/mode_key_handler.coffee b/content_scripts/mode_key_handler.coffee
index 96792306..ca20be46 100644
--- a/content_scripts/mode_key_handler.coffee
+++ b/content_scripts/mode_key_handler.coffee
@@ -40,12 +40,12 @@ class KeyHandlerMode extends Mode
if isEscape and (@countPrefix != 0 or @keyState.length != 1)
@keydownEvents[event.keyCode] = true
@reset()
- false # Suppress event.
+ @suppressEvent
# If the help dialog loses the focus, then Escape should hide it; see point 2 in #2045.
else if isEscape and HelpDialog?.showing
@keydownEvents[event.keyCode] = true
HelpDialog.hide()
- false # Suppress event.
+ @suppressEvent
else if isEscape
@continueBubbling
else if @isMappedKey keyChar
@@ -57,7 +57,7 @@ class KeyHandlerMode extends Mode
# prevent triggering page event listeners (e.g. Google instant Search).
@keydownEvents[event.keyCode] = true
DomUtils.suppressPropagation event
- @stopBubblingAndTrue
+ @passEventToPage
else
@continueBubbling
@@ -68,7 +68,7 @@ class KeyHandlerMode extends Mode
else if @isCountKey keyChar
digit = parseInt keyChar
@reset if @keyState.length == 1 then @countPrefix * 10 + digit else digit
- false # Suppress event.
+ @suppressEvent
else
@reset()
@continueBubbling
@@ -77,7 +77,7 @@ class KeyHandlerMode extends Mode
return @continueBubbling unless event.keyCode of @keydownEvents
delete @keydownEvents[event.keyCode]
DomUtils.suppressPropagation event
- @stopBubblingAndTrue
+ @passEventToPage
# This tests whether there is a mapping of keyChar in the current key state (and accounts for pass keys).
isMappedKey: (keyChar) ->
diff --git a/lib/handler_stack.coffee b/lib/handler_stack.coffee
index 2a44d26b..c97c5da0 100644
--- a/lib/handler_stack.coffee
+++ b/lib/handler_stack.coffee
@@ -9,16 +9,22 @@ class HandlerStack
# A handler should return this value to immediately discontinue bubbling and pass the event on to the
# underlying page.
- @stopBubblingAndTrue = new Object()
+ @passEventToPage = new Object()
# A handler should return this value to indicate that the event has been consumed, and no further
# processing should take place. The event does not propagate to the underlying page.
- @stopBubblingAndFalse = new Object()
+ @suppressPropagation = 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.
@restartBubbling = new Object()
+ # A handler should return this value to continue bubbling the event.
+ @continueBubbling = true
+
+ # A handler should return this value to suppress an event.
+ @suppressEvent = false
+
# 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) ->
@@ -34,8 +40,8 @@ class HandlerStack
handler.id = ++@counter
# Called whenever we receive a key or other event. Each individual handler has the option to stop the
- # event's propagation by returning a falsy value, or stop bubbling by returning @stopBubblingAndFalse or
- # @stopBubblingAndTrue.
+ # event's propagation by returning a falsy value, or stop bubbling by returning @suppressPropagation or
+ # @passEventToPage.
bubbleEvent: (type, event) ->
@eventNumber += 1
eventNumber = @eventNumber
@@ -47,12 +53,27 @@ class HandlerStack
@currentId = handler.id
result = handler[type].call this, event
@logResult eventNumber, type, event, handler, result if @debug
- if not result
+ if result
+ switch result
+ when @passEventToPage
+ return true
+ when @suppressPropagation
+ DomUtils.suppressPropagation event
+ return false
+ when @restartBubbling
+ return @bubbleEvent type, event
+ when @continueBubbling
+ true # Do nothing, continue bubbling.
+ else
+ # Any other truthy value also means continue bubbling.
+ if @debug
+ console.log "Unknown truthy return value in handler stack: #{eventNumber}, #{type}, #{result}"
+ else
+ if @debug and result != false
+ console.log "Unknown falsy return value in handler stack: #{eventNumber}, #{type}, #{result}"
+ # Any falsy value means suppress event.
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
else
@logResult eventNumber, type, event, handler, "skip" if @debug
true
@@ -74,21 +95,21 @@ class HandlerStack
# 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
+ alwaysContinueBubbling: (handler = null) ->
+ handler?()
+ @continueBubbling
- neverContinueBubbling: (handler) ->
- handler()
- false
+ alwaysSuppressPropagation: (handler = null) ->
+ handler?()
+ @suppressPropagation
# Debugging.
logResult: (eventNumber, type, event, handler, result) ->
label =
switch result
- when @stopBubblingAndTrue then "stop/true"
- when @stopBubblingAndFalse then "stop/false"
- when @restartBubbling then "rebubble"
+ when @passEventToPage then "passEventToPage"
+ when @suppressPropagation then "suppressPropagation"
+ when @restartBubbling then "restartBubbling"
when "skip" then "skip"
when true then "continue"
label ||= if result then "continue/truthy" else "suppress"
diff --git a/tests/unit_tests/handler_stack_test.coffee b/tests/unit_tests/handler_stack_test.coffee
index 629fc3ed..7b62af07 100644
--- a/tests/unit_tests/handler_stack_test.coffee
+++ b/tests/unit_tests/handler_stack_test.coffee
@@ -5,6 +5,7 @@ context "handlerStack",
setup ->
stub global, "DomUtils", {}
stub DomUtils, "suppressEvent", ->
+ stub DomUtils, "suppressPropagation", ->
@handlerStack = new HandlerStack
@handler1Called = false
@handler2Called = false
@@ -23,16 +24,16 @@ context "handlerStack",
assert.isTrue @handler2Called
assert.isFalse @handler1Called
- should "terminate bubbling on stopBubblingAndTrue, and be true", ->
+ should "terminate bubbling on passEventToPage, and be true", ->
@handlerStack.push { keydown: => @handler1Called = true }
- @handlerStack.push { keydown: => @handler2Called = true; @handlerStack.stopBubblingAndTrue }
+ @handlerStack.push { keydown: => @handler2Called = true; @handlerStack.passEventToPage }
assert.isTrue @handlerStack.bubbleEvent 'keydown', {}
assert.isTrue @handler2Called
assert.isFalse @handler1Called
- should "terminate bubbling on stopBubblingAndTrue, and be false", ->
+ should "terminate bubbling on passEventToPage, and be false", ->
@handlerStack.push { keydown: => @handler1Called = true }
- @handlerStack.push { keydown: => @handler2Called = true; @handlerStack.stopBubblingAndFalse }
+ @handlerStack.push { keydown: => @handler2Called = true; @handlerStack.suppressPropagation }
assert.isFalse @handlerStack.bubbleEvent 'keydown', {}
assert.isTrue @handler2Called
assert.isFalse @handler1Called