diff options
Diffstat (limited to 'content_scripts/mode.coffee')
| -rw-r--r-- | content_scripts/mode.coffee | 87 |
1 files changed, 67 insertions, 20 deletions
diff --git a/content_scripts/mode.coffee b/content_scripts/mode.coffee index 8e37ee36..0fcab675 100644 --- a/content_scripts/mode.coffee +++ b/content_scripts/mode.coffee @@ -38,18 +38,21 @@ # myMode.exit() # externally triggered. # -# For debug only; to be stripped out. +# For debug only. count = 0 class Mode - # If this is true, then we generate a trace of modes being activated and deactivated on the console. - @debug = true + # If Mode.debug is true, then we generate a trace of modes being activated and deactivated on the console, along + # with a list of the currently active modes. + debug: true + @modes: [] - # Constants; readable shortcuts for event-handler return values. + # Constants; short, readable names for handlerStack event-handler return values. continueBubbling: true suppressEvent: false stopBubblingAndTrue: handlerStack.stopBubblingAndTrue stopBubblingAndFalse: handlerStack.stopBubblingAndFalse + restartBubbling: handlerStack.restartBubbling constructor: (@options={}) -> @handlers = [] @@ -59,7 +62,8 @@ class Mode @name = @options.name || "anonymous" @count = ++count - console.log @count, "create:", @name if Mode.debug + @id = "#{@name}-#{@count}" + @logger "activate:", @id if @debug @push keydown: @options.keydown || null @@ -79,6 +83,7 @@ class Mode # Note. This handler ends up above the mode's own key handlers on the handler stack, so it takes # priority. @push + _name: "mode-#{@id}/exitOnEscape" "keydown": (event) => return @continueBubbling unless KeyboardUtils.isEscape event @exit event @@ -89,6 +94,7 @@ class Mode # loses the focus. if @options.exitOnBlur @push + _name: "mode-#{@id}/exitOnBlur" "blur": (event) => @alwaysContinueBubbling => @exit() if event.srcElement == @options.exitOnBlur # If @options.trackState is truthy, then the mode mainatins the current state in @enabled and @passKeys, @@ -97,6 +103,7 @@ class Mode @enabled = false @passKeys = "" @push + _name: "mode-#{@id}/registerStateChange" "registerStateChange": ({ enabled: enabled, passKeys: passKeys }) => @alwaysContinueBubbling => if enabled != @enabled or passKeys != @passKeys @@ -104,35 +111,43 @@ class Mode @passKeys = passKeys @registerStateChange?() - # If @options.trapAllKeyboardEvents is truthy, then it should be an element. All keyboard events on that - # element are suppressed *after* bubbling the event down the handler stack. This prevents such events - # from propagating to other extensions or the host page. - if @options.trapAllKeyboardEvents - @unshift - keydown: (event) => @alwaysContinueBubbling => - DomUtils.suppressPropagation event if event.srcElement == @options.trapAllKeyboardEvents - keypress: (event) => @alwaysContinueBubbling => - DomUtils.suppressEvent event if event.srcElement == @options.trapAllKeyboardEvents - keyup: (event) => @alwaysContinueBubbling => - DomUtils.suppressPropagation event if event.srcElement == @options.trapAllKeyboardEvents + # If @options.suppressPrintableEvents is truthy, then it should be an element. All printable keypress + # events on that element are suppressed, if necessary. They are suppressed *after* bubbling down the + # handler stack and finding no handler. This is used by PostFindMode to protect active, editable + # elements. + if @options.suppressPrintableEvents + @push + _name: "mode-#{@id}/suppressPrintableEvents" + keypress: (event) => + @alwaysContinueBubbling => + if event.srcElement == @options.suppressPrintableEvents + if KeyboardUtils.isPrintable(event) + event.vimium_suppress_event = true Mode.updateBadge() if @badge - # End of Mode.constructor(). + Mode.modes.push @ + @log() if @debug + # handlerStack.debugOn() + # End of Mode constructor. push: (handlers) -> + handlers._name ||= "mode-#{@id}" @handlers.push handlerStack.push handlers unshift: (handlers) -> - @handlers.unshift handlerStack.push handlers + handlers._name ||= "mode-#{@id}" + handlers._name += "/unshifted" + @handlers.push handlerStack.unshift handlers onExit: (handler) -> @exitHandlers.push handler exit: -> if @modeIsActive - console.log @count, "exit:", @name if Mode.debug + @logger "deactivate:", @id if @debug handler() for handler in @exitHandlers handlerStack.remove handlerId for handlerId in @handlers + Mode.modes = Mode.modes.filter (mode) => mode != @ Mode.updateBadge() @modeIsActive = false @@ -175,11 +190,25 @@ class Mode # suppress badge updates while exiting any existing active singleton. This prevents the badge from # flickering in some cases. Mode.badgeSuppressor.runSuppresed => - singletons[key].exit() if singletons[key] + if singletons[key] + @logger "singleton:", "deactivating #{singletons[key].id}" if @debug + singletons[key].exit() singletons[key] = @ @onExit => delete singletons[key] if singletons[key] == @ + # Debugging routines. + log: -> + if Mode.modes.length == 0 + @logger "It looks like debugging is not enabled in modes.coffee." + else + @logger "active modes (top to bottom), current: #{@id}" + for mode in Mode.modes[..].reverse() + @logger " ", mode.id + + logger: (args...) -> + handlerStack.log args... + # BadgeMode is a pseudo mode for triggering badge updates on focus changes and state updates. It sits at the # bottom of the handler stack, and so it receives state changes *after* all other modes, and can override the # badge choice of the other active modes. @@ -190,7 +219,11 @@ new class BadgeMode extends Mode name: "badge" trackState: true + # FIXME(smblott) BadgeMode is currently triggering and updateBadge event on every focus event. That's a + # lot, considerably more than is necessary. Really, it only needs to trigger when we change frame, or + # when we change tab. @push + _name: "mode-#{@id}/focus" "focus": => @alwaysContinueBubbling -> Mode.updateBadge() chooseBadge: (badge) -> @@ -200,5 +233,19 @@ new class BadgeMode extends Mode registerStateChange: -> Mode.updateBadge() +# KeySuppressor is a pseudo mode (near the bottom of the stack) which suppresses keyboard events tagged with +# the "vimium_suppress_event" property. This allows modes higher up in the stack to tag events for +# suppression, but only after verifying that no other mode (notably, normal mode) wants to handle the event. +# Note. We also create the the one-and-only instance, here. +new class KeySuppressor extends Mode + constructor: -> + super + name: "key-suppressor" + keydown: (event) => @handle event + keypress: (event) => @handle event + keyup: (event) => @handle event + + handle: (event) -> if event.vimium_suppress_event then @suppressEvent else @continueBubbling + root = exports ? window root.Mode = Mode |
