aboutsummaryrefslogtreecommitdiffstats
path: root/content_scripts/mode.coffee
diff options
context:
space:
mode:
Diffstat (limited to 'content_scripts/mode.coffee')
-rw-r--r--content_scripts/mode.coffee92
1 files changed, 40 insertions, 52 deletions
diff --git a/content_scripts/mode.coffee b/content_scripts/mode.coffee
index 8041f462..9e886a63 100644
--- a/content_scripts/mode.coffee
+++ b/content_scripts/mode.coffee
@@ -11,86 +11,74 @@ class Mode
stopBubblingAndFalse: handlerStack.stopBubblingAndFalse
# Default values.
- name: "" # The name of this mode.
- badge: "" # A badge to display on the popup when this mode is active.
- keydown: "suppress" # A function, or "suppress", "bubble" or "pass"; see checkForBuiltInHandler().
- keypress: "suppress" # A function, or "suppress", "bubble" or "pass"; see checkForBuiltInHandler().
- keyup: "suppress" # A function, or "suppress", "bubble" or "pass"; see checkForBuiltInHandler().
+ name: ""
+ badge: ""
+ keydown: (event) => @continueBubbling
+ keypress: (event) => @continueBubbling
+ keyup: (event) => @continueBubbling
constructor: (options) ->
+ Mode.modes.unshift @
extend @, options
@handlers = []
@handlers.push handlerStack.push
- keydown: @checkForBuiltInHandler "keydown", @keydown
- keypress: @checkForBuiltInHandler "keypress", @keypress
- keyup: @checkForBuiltInHandler "keyup", @keyup
- updateBadgeForMode: (badge) => @updateBadgeForMode badge
-
- Mode.modes.unshift @
-
- # Allow the strings "suppress" and "pass" to be used as proxies for the built-in handlers.
- checkForBuiltInHandler: (type, handler) ->
- switch handler
- when "suppress" then @generateHandler type, @suppressEvent
- when "bubble" then @generateHandler type, @continueBubbling
- when "pass" then @generateHandler type, @stopBubblingAndTrue
- else handler
-
- # Generate a default handler which always always yields the same result; except Esc, which pops the current
- # mode.
- generateHandler: (type, result) ->
- (event) =>
- return result unless type == "keydown" and KeyboardUtils.isEscape event
- @exit()
- @suppressEvent
+ keydown: @keydown
+ keypress: @keypress
+ keyup: @keyup
+ updateBadge: (badge) => handlerStack.alwaysContinueBubbling => @chooseBadge badge
exit: ->
handlerStack.remove handlerId for handlerId in @handlers
Mode.modes = Mode.modes.filter (mode) => mode != @
Mode.updateBadge()
- # Default updateBadgeForMode handler. This is overridden by sub-classes. The default is to install the
- # current mode's badge, unless the bade is already set.
- updateBadgeForMode: (badge) ->
- handlerStack.alwaysContinueBubbling => badge.badge ||= @badge
+ # The badge is chosen by bubbling an "updateBadge" event down the handler stack allowing each mode the
+ # opportunity to choose a badge. chooseBadge, here, is the default: choose the current mode's badge unless
+ # one has already been chosen. This is overridden in sub-classes.
+ chooseBadge: (badge) ->
+ badge.badge ||= @badge
- # Static method. Used externally and internally to initiate bubbling of an updateBadgeForMode event.
- # Do not update the badge:
- # - if this document does not have the focus, or
- # - if the document's body is a frameset
+ # 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 has the focus, and
+ # the document's body isn't a frameset.
@updateBadge: ->
if document.hasFocus()
unless document.body?.tagName.toLowerCase() == "frameset"
badge = {badge: ""}
- handlerStack.bubbleEvent "updateBadgeForMode", badge
- Mode.sendBadge badge.badge
-
- # Static utility to update the browser-popup badge.
- @sendBadge: (badge) ->
- chrome.runtime.sendMessage({ handler: "setBadge", badge: badge })
+ handlerStack.bubbleEvent "updateBadge", badge
+ chrome.runtime.sendMessage({ handler: "setBadge", badge: badge.badge })
- # Install a mode, call a function, and exit the mode again.
+ # Temporarily install a mode.
@runIn: (mode, func) ->
mode = new mode()
func()
mode.exit()
-# A SingletonMode is a Mode of which there may be at most one instance of the same name (@singleton) active at
-# any one time. New instances cancel previous instances on startup.
+# A SingletonMode is a Mode of which there may be at most one instance (of @singleton) active at any one time.
+# New instances cancel previous instances on startup.
class SingletonMode extends Mode
- constructor: (@singleton, options) ->
- @cancel @singleton
- super options
-
@instances: {}
- cancel: (instance) ->
- SingletonMode[instance].exit() if SingletonMode[instance]
-
exit: ->
- delete SingletonMode[@instance]
+ delete SingletonMode[@singleton]
super()
+ constructor: (@singleton, options={}) ->
+ SingletonMode[@singleton].exit() if SingletonMode[@singleton]
+ SingletonMode[@singleton] = @
+ super options
+
+# MultiMode is a collection of modes which are installed or uninstalled together.
+class MultiMode extends Mode
+ constructor: (modes...) ->
+ @modes = (new mode() for mode in modes)
+ super {name: "multimode"}
+
+ exit: ->
+ mode.exit() for mode in modes
+
root = exports ? window
root.Mode = Mode
+root.SingletonMode = SingletonMode
+root.MultiMode = MultiMode