emitter.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. var _ = require('./util')
  2. /**
  3. * Simple event emitter based on component/emitter.
  4. *
  5. * @constructor
  6. * @param {Object} ctx - the context to call listners with.
  7. */
  8. function Emitter (ctx) {
  9. this._cancelled = false
  10. this._ctx = ctx || null
  11. }
  12. var p = Emitter.prototype
  13. /**
  14. * Listen on the given `event` with `fn`.
  15. *
  16. * @param {String} event
  17. * @param {Function} fn
  18. * @return {Emitter}
  19. */
  20. p.on = function (event, fn) {
  21. this._cbs = this._cbs || {}
  22. ;(this._cbs[event] || (this._cbs[event] = []))
  23. .push(fn)
  24. return this
  25. }
  26. /**
  27. * Adds an `event` listener that will be invoked a single
  28. * time then automatically removed.
  29. *
  30. * @param {String} event
  31. * @param {Function} fn
  32. * @return {Emitter}
  33. */
  34. p.once = function (event, fn) {
  35. var self = this
  36. this._cbs = this._cbs || {}
  37. function on () {
  38. self.off(event, on)
  39. fn.apply(this, arguments)
  40. }
  41. on.fn = fn
  42. this.on(event, on)
  43. return this
  44. }
  45. /**
  46. * Remove the given callback for `event` or all
  47. * registered callbacks.
  48. *
  49. * @param {String} event
  50. * @param {Function} fn
  51. * @return {Emitter}
  52. */
  53. p.off = function (event, fn) {
  54. this._cbs = this._cbs || {}
  55. // all
  56. if (!arguments.length) {
  57. this._cbs = {}
  58. return this
  59. }
  60. // specific event
  61. var callbacks = this._cbs[event]
  62. if (!callbacks) return this
  63. // remove all handlers
  64. if (arguments.length === 1) {
  65. this._cbs[event] = null
  66. return this
  67. }
  68. // remove specific handler
  69. var cb
  70. var i = callbacks.length
  71. while (i--) {
  72. cb = callbacks[i]
  73. if (cb === fn || cb.fn === fn) {
  74. callbacks.splice(i, 1)
  75. break
  76. }
  77. }
  78. return this
  79. }
  80. /**
  81. * The internal, faster emit with fixed amount of arguments
  82. * using Function.call. This emit assumes that callbacks
  83. * triggered will not modify the callback list being
  84. * iterated through.
  85. *
  86. * @param {Object} event
  87. * @return {Emitter}
  88. */
  89. p.emit = function (event, a, b, c, d) {
  90. this._cbs = this._cbs || {}
  91. var callbacks = this._cbs[event]
  92. if (callbacks) {
  93. var ctx = this._ctx
  94. for (var i = 0, l = callbacks.length; i < l; i++) {
  95. callbacks[i].call(ctx, a, b, c, d)
  96. }
  97. }
  98. return this
  99. }
  100. /**
  101. * The external emit using Function.apply, used
  102. * by Vue instance event methods.
  103. *
  104. * @param {Object} event
  105. * @return {Emitter}
  106. */
  107. p.applyEmit = function (event) {
  108. this._cancelled = false
  109. this._cbs = this._cbs || {}
  110. var callbacks = this._cbs[event]
  111. if (callbacks) {
  112. // avoid leaking arguments:
  113. // http://jsperf.com/closure-with-arguments
  114. var i = arguments.length - 1
  115. var args = new Array(i)
  116. while (i--) {
  117. args[i] = arguments[i + 1]
  118. }
  119. callbacks = _.toArray(callbacks)
  120. i = 0
  121. for (var l = callbacks.length; i < l; i++) {
  122. if (callbacks[i].apply(this._ctx, args) === false) {
  123. this._cancelled = true
  124. }
  125. }
  126. }
  127. return this
  128. }
  129. module.exports = Emitter