aboutsummaryrefslogtreecommitdiffstats
path: root/content_scripts/mode.coffee
blob: 82dbf74a50d6ec97e744920717e051a44093f961 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
class Mode
  # Static members.
  @modes: []
  @current: -> Mode.modes[0]

  # Constants. Static.
  @suppressPropagation = false
  @propagate = true

  # 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" or "pass"; the latter are replaced with suitable functions.
  keypress: "suppress" # A function, or "suppress" or "pass"; the latter are replaced with suitable functions.
  keyup: "suppress"    # A function, or "suppress" or "pass"; the latter are replaced with suitable functions.

  constructor: (options) ->
    extend @, options

    @handlerId = handlerStack.push
      keydown: @checkForBuiltInHandler "keydown", @keydown
      keypress: @checkForBuiltInHandler "keypress", @keypress
      keyup: @checkForBuiltInHandler "keyup", @keyup

    Mode.modes.unshift @
    Mode.setBadge()

  # Allow the strings "suppress" and "pass" to be used as proxies for the built-in handlers.
  checkForBuiltInHandler: (type, handler) ->
    switch handler
      when "suppress" then @generateSuppressPropagation type
      when "pass" then @generatePassThrough type
      else handler

  # Generate a default handler which always passes through to the underlying page; except Esc, which pops the
  # current mode.
  generatePassThrough: (type) ->
    (event) =>
      if type == "keydown" and KeyboardUtils.isEscape event
        @exit()
        return Mode.suppressPropagation
      handlerStack.passDirectlyToPage

  # Generate a default handler which always suppresses propagation; except Esc, which pops the current mode.
  generateSuppressPropagation: (type) ->
    handler = @generatePassThrough type
    (event) -> handler(event) and Mode.suppressPropagation # Always falsy.

  exit: ->
    handlerStack.remove @handlerId
    Mode.modes = Mode.modes.filter (mode) => mode != @
    Mode.setBadge()

  # Set the badge on the browser popup to indicate the current mode; static method.
  @setBadge: ->
    chrome.runtime.sendMessage({ handler: "setBadge", badge: Mode.getBadge() })

  # Static convenience methods.
  @is: (mode) -> Mode.current()?.name == mode
  @getBadge: -> Mode.current()?.badge || ""
  @isInsert: -> Mode.is "insert"

root = exports ? window
root.Mode = Mode