/coffee/frontend/modules/key-event.coffee

https://github.com/jinzhu/vrome · CoffeeScript · 156 lines · 112 code · 33 blank · 11 comment · 26 complexity · 10138f87db955e61ef5c3774481bf078 MD5 · raw file

  1. class window.KeyEvent
  2. [disableVrome, passNextKey, currentKeys, keyTimes, bindings] = [false, false, '', 0, {}]
  3. @init: =>
  4. for disabledSite in Option.get('disablesites').split(',') when disabledSite isnt ''
  5. @disable() if new RegExp(disabledSite.trim(), 'i').test(location.href)
  6. document.addEventListener 'keydown', KeyEvent.exec, true
  7. @add: (keys, func, insertMode) ->
  8. bindings[keys] ?= [null, null]
  9. bindings[keys][Number insertMode] = func
  10. @stopPropagation: (e) ->
  11. e.stopPropagation()
  12. e.preventDefault()
  13. @enable: =>
  14. [disableVrome, passNextKey] = [false, false]
  15. Post action: 'Vrome.enable'
  16. @reset()
  17. @disable: ->
  18. if Option.get 'show_disabled_text'
  19. CmdBox.set title: ' -- PASS THROUGH -- ', mouseOverTitle: CmdBox.remove
  20. disableVrome = true
  21. Post action: 'Vrome.disable'
  22. desc @disable, 'Disable Vrome'
  23. @disable.options =
  24. disablesites:
  25. description: "Disable Vrome in those sites. Multiple URLs can be separated with ','"
  26. example: 'set disablesites=mail.google.com,reader.google.com'
  27. enable_vrome_key:
  28. description: 'Key to enable Vrome again'
  29. example: 'set enable_vrome_key=<Esc>'
  30. show_disabled_text:
  31. description: 'Show Vrome Disabled text or not. You could also know this from the Action Icon'
  32. example: 'set show_disable_text=0'
  33. @passNextKey: ->
  34. CmdBox.set title: ' -- PASS THROUGH (next) -- ', timeout: 2000 if Option.get 'show_disabled_text'
  35. passNextKey = true
  36. Post action: 'Vrome.disable'
  37. desc @passNextKey, 'Pass next key'
  38. @reset: ->
  39. currentKeys = ''
  40. keyTimes = 0
  41. @times: (onlyRead) ->
  42. result = keyTimes
  43. keyTimes = 0 unless onlyRead
  44. result
  45. storeLast = ->
  46. Settings.add { currentKeys, times: keyTimes }
  47. @runLast: ->
  48. runCurrentKeys Settings.get('@currentKeys'), Settings.get('@times'), false
  49. desc @runLast, 'Repeat the last command'
  50. filterKey = (key, insertMode) ->
  51. configure = Settings.get '@configure'
  52. mode = if insertMode then 'imap' else 'map'
  53. return key if /^\d$/.test key
  54. configure?[mode]?[key] or key
  55. ignoreKey = (key, insertMode) ->
  56. configure = Settings.get '@configure'
  57. mode = if insertMode then 'iunmap' else 'unmap'
  58. configure?[mode]?[key]?
  59. showStatusLine = ->
  60. if Option.get 'showstatus'
  61. CmdBox.set title: "#{keyTimes or ''}#{currentKeys}", timeout: 500
  62. runCurrentKeys = (keys, times, insertMode, e) =>
  63. return unless keys
  64. key = if e then getKey e else null
  65. stopPropagation = =>
  66. # stopPropagation if Vrome is enabled and any functions executed
  67. @stopPropagation e if e and not (isAcceptKey(key) and
  68. (insertMode or Hint.isHintable(document.activeElement)))
  69. # 0 is a special command: could be used to scroll left, also could be used as run count.
  70. if (keys is '0' and keyTimes is 0) or not /^\d$/.test keys
  71. /^(\d*)(.+)$/.test keys
  72. count = Number RegExp.$1
  73. match = RegExp.$2
  74. bindingFunction = bindings[match]?[Number insertMode]
  75. if bindingFunction?
  76. # Run matched function
  77. # map j 3j
  78. originalKeyTimes = keyTimes
  79. if count > 1 or times > 1
  80. keyTimes = (keyTimes or 1) * times * (count or 1)
  81. try
  82. bindingFunction.call e
  83. catch error
  84. Debug error
  85. keyTimes = originalKeyTimes
  86. if e
  87. # If any function invoked, then store it to last run command.
  88. # (don't do this when running 'repeat last command' or in InsertMode)
  89. do storeLast if key isnt '.' and not insertMode
  90. do stopPropagation
  91. # If some function invoked and a key pressed, reset the count
  92. # but don't reset it if no key pressed, this means the function is invoked by runLast.
  93. keyTimes = 0
  94. currentKeys = ''
  95. else
  96. # Check if there are any bindings that partially match
  97. numberInsertMode = Number insertMode
  98. startsWithKey = (command, key) ->
  99. command is key or
  100. (command.startsWith(key) and not command.startsWith '<')
  101. for command, modes of bindings when modes[numberInsertMode]? and startsWithKey command, keys
  102. someBindingMatched = true
  103. do stopPropagation
  104. do showStatusLine
  105. break
  106. currentKeys = '' if not someBindingMatched
  107. else if not insertMode and /^\d$/.test key
  108. # Set the count time
  109. keyTimes = keyTimes * 10 + Number(key)
  110. currentKeys = ''
  111. do showStatusLine
  112. @exec: (e) =>
  113. key = getKey e
  114. return @stopPropagation e if isModifierKey key
  115. insertMode = isEditableElement e.target
  116. # If Vrome in pass-next or disabled mode and using <C-Esc> to enable it.
  117. if not insertMode and (passNextKey or (disableVrome and isCtrlEscapeKey(key)))
  118. window.CancelKeyFunction()
  119. return @enable()
  120. return if disableVrome
  121. currentKeys = filterKey currentKeys.concat(key), insertMode
  122. return if ignoreKey currentKeys, insertMode
  123. runCurrentKeys currentKeys, 1, insertMode, e