diff options
Diffstat (limited to 'content_scripts/mode.coffee')
| -rw-r--r-- | content_scripts/mode.coffee | 86 |
1 files changed, 36 insertions, 50 deletions
diff --git a/content_scripts/mode.coffee b/content_scripts/mode.coffee index 7877d97c..f631b4cd 100644 --- a/content_scripts/mode.coffee +++ b/content_scripts/mode.coffee @@ -6,13 +6,6 @@ # name: # A name for this mode. # -# badge: -# A badge (to appear on the browser popup). -# Optional. Define a badge if the badge is constant; for example, in find mode the badge is always "/". -# Otherwise, do not define a badge, but instead override the updateBadge method; for example, in passkeys -# mode, the badge may be "P" or "", depending on the configuration state. Or, if the mode *never* shows a -# badge, then do neither. -# # keydown: # keypress: # keyup: @@ -48,7 +41,6 @@ class Mode @handlers = [] @exitHandlers = [] @modeIsActive = true - @badge = @options.badge || "" @name = @options.name || "anonymous" @count = ++count @@ -59,7 +51,16 @@ class Mode keydown: @options.keydown || null keypress: @options.keypress || null keyup: @options.keyup || null - updateBadge: (badge) => @alwaysContinueBubbling => @updateBadge badge + indicator: => + # Update the mode indicator. Setting @options.indicator to a string shows a mode indicator in the + # HUD. Setting @options.indicator to 'false' forces no mode indicator. If @options.indicator is + # undefined, then the request propagates to the next mode. + # The active indicator can also be changed with @setIndicator(). + if @options.indicator? + if HUD?.isReady() + if @options.indicator then HUD.show @options.indicator else HUD.hide true, false + @stopBubblingAndTrue + else @continueBubbling # If @options.exitOnEscape is truthy, then the mode will exit when the escape key is pressed. if @options.exitOnEscape @@ -86,6 +87,13 @@ class Mode _name: "mode-#{@id}/exitOnClick" "click": (event) => @alwaysContinueBubbling => @exit event + #If @options.exitOnFocus is truthy, then the mode will exit whenever a focusable element is activated. + if @options.exitOnFocus + @push + _name: "mode-#{@id}/exitOnFocus" + "focus": (event) => @alwaysContinueBubbling => + @exit event if DomUtils.isFocusable event.target + # Some modes are singletons: there may be at most one instance active at any time. A mode is a singleton # if @options.singleton is truthy. The value of @options.singleton should be the key which is intended to # be unique. New instances deactivate existing instances with the same key. @@ -113,11 +121,28 @@ class Mode @registerStateChange?() registerKeyQueue: ({ keyQueue: keyQueue }) => @alwaysContinueBubbling => @keyQueue = keyQueue + # If @options.passInitialKeyupEvents is set, then we pass initial non-printable keyup events to the page + # or to other extensions (because the corresponding keydown events were passed). This is used when + # activating link hints, see #1522. + if @options.passInitialKeyupEvents + @push + _name: "mode-#{@id}/passInitialKeyupEvents" + keydown: => @alwaysContinueBubbling -> handlerStack.remove() + keyup: (event) => + if KeyboardUtils.isPrintable event then @stopBubblingAndFalse else @stopBubblingAndTrue + Mode.modes.push @ - Mode.updateBadge() + @setIndicator() @logModes() # End of Mode constructor. + setIndicator: (indicator = @options.indicator) -> + @options.indicator = indicator + Mode.setIndicator() + + @setIndicator: -> + handlerStack.bubbleEvent "indicator" + push: (handlers) -> handlers._name ||= "mode-#{@id}" @handlers.push handlerStack.push handlers @@ -135,17 +160,12 @@ class Mode handler() for handler in @exitHandlers handlerStack.remove handlerId for handlerId in @handlers Mode.modes = Mode.modes.filter (mode) => mode != @ - Mode.updateBadge() @modeIsActive = false + @setIndicator() deactivateSingleton: (singleton) -> Mode.singletons?[Utils.getIdentity singleton]?.exit() - # The badge is chosen by bubbling an "updateBadge" event down the handler stack allowing each mode the - # opportunity to choose a badge. This is overridden in sub-classes. - updateBadge: (badge) -> - badge.badge ||= @badge - # 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. @@ -157,14 +177,6 @@ class Mode delete @options[key] for key in [ "keydown", "keypress", "keyup" ] new @constructor @options - # Static method. Used externally and internally to initiate bubbling of an updateBadge event and to send - # the resulting badge to the background page. We only update the badge if this document (hence this frame) - # has the focus. - @updateBadge: -> - if document.hasFocus() - handlerStack.bubbleEvent "updateBadge", badge = badge: "" - chrome.runtime.sendMessage { handler: "setBadge", badge: badge.badge }, -> - # Debugging routines. logModes: -> if @debug @@ -183,31 +195,5 @@ class Mode mode.exit() for mode in @modes @modes = [] -# 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 modes. -class BadgeMode extends Mode - constructor: () -> - super - name: "badge" - trackState: true - - # FIXME(smblott) BadgeMode is currently triggering an updateBadge event on every focus event. That's a - # lot, considerably more than 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() - - updateBadge: (badge) -> - # If we're not enabled, then post an empty badge. - badge.badge = "" unless @enabled - - # When the registerStateChange event bubbles to the bottom of the stack, all modes have been notified. So - # it's now time to update the badge. - registerStateChange: -> - Mode.updateBadge() - root = exports ? window root.Mode = Mode -root.BadgeMode = BadgeMode |
