event.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import { mac } from "./browser.js"
  2. import { indexOf } from "./misc.js"
  3. // EVENT HANDLING
  4. // Lightweight event framework. on/off also work on DOM nodes,
  5. // registering native DOM handlers.
  6. const noHandlers = []
  7. export let on = function(emitter, type, f) {
  8. if (emitter.addEventListener) {
  9. emitter.addEventListener(type, f, false)
  10. } else if (emitter.attachEvent) {
  11. emitter.attachEvent("on" + type, f)
  12. } else {
  13. let map = emitter._handlers || (emitter._handlers = {})
  14. map[type] = (map[type] || noHandlers).concat(f)
  15. }
  16. }
  17. export function getHandlers(emitter, type) {
  18. return emitter._handlers && emitter._handlers[type] || noHandlers
  19. }
  20. export function off(emitter, type, f) {
  21. if (emitter.removeEventListener) {
  22. emitter.removeEventListener(type, f, false)
  23. } else if (emitter.detachEvent) {
  24. emitter.detachEvent("on" + type, f)
  25. } else {
  26. let map = emitter._handlers, arr = map && map[type]
  27. if (arr) {
  28. let index = indexOf(arr, f)
  29. if (index > -1)
  30. map[type] = arr.slice(0, index).concat(arr.slice(index + 1))
  31. }
  32. }
  33. }
  34. export function signal(emitter, type /*, values...*/) {
  35. let handlers = getHandlers(emitter, type)
  36. if (!handlers.length) return
  37. let args = Array.prototype.slice.call(arguments, 2)
  38. for (let i = 0; i < handlers.length; ++i) handlers[i].apply(null, args)
  39. }
  40. // The DOM events that CodeMirror handles can be overridden by
  41. // registering a (non-DOM) handler on the editor for the event name,
  42. // and preventDefault-ing the event in that handler.
  43. export function signalDOMEvent(cm, e, override) {
  44. if (typeof e == "string")
  45. e = {type: e, preventDefault: function() { this.defaultPrevented = true }}
  46. signal(cm, override || e.type, cm, e)
  47. return e_defaultPrevented(e) || e.codemirrorIgnore
  48. }
  49. export function signalCursorActivity(cm) {
  50. let arr = cm._handlers && cm._handlers.cursorActivity
  51. if (!arr) return
  52. let set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = [])
  53. for (let i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1)
  54. set.push(arr[i])
  55. }
  56. export function hasHandler(emitter, type) {
  57. return getHandlers(emitter, type).length > 0
  58. }
  59. // Add on and off methods to a constructor's prototype, to make
  60. // registering events on such objects more convenient.
  61. export function eventMixin(ctor) {
  62. ctor.prototype.on = function(type, f) {on(this, type, f)}
  63. ctor.prototype.off = function(type, f) {off(this, type, f)}
  64. }
  65. // Due to the fact that we still support jurassic IE versions, some
  66. // compatibility wrappers are needed.
  67. export function e_preventDefault(e) {
  68. if (e.preventDefault) e.preventDefault()
  69. else e.returnValue = false
  70. }
  71. export function e_stopPropagation(e) {
  72. if (e.stopPropagation) e.stopPropagation()
  73. else e.cancelBubble = true
  74. }
  75. export function e_defaultPrevented(e) {
  76. return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
  77. }
  78. export function e_stop(e) {e_preventDefault(e); e_stopPropagation(e)}
  79. export function e_target(e) {return e.target || e.srcElement}
  80. export function e_button(e) {
  81. let b = e.which
  82. if (b == null) {
  83. if (e.button & 1) b = 1
  84. else if (e.button & 2) b = 3
  85. else if (e.button & 4) b = 2
  86. }
  87. if (mac && e.ctrlKey && b == 1) b = 3
  88. return b
  89. }