index.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. 'use strict';
  2. var d = require('d')
  3. , callable = require('es5-ext/object/valid-callable')
  4. , apply = Function.prototype.apply, call = Function.prototype.call
  5. , create = Object.create, defineProperty = Object.defineProperty
  6. , defineProperties = Object.defineProperties
  7. , hasOwnProperty = Object.prototype.hasOwnProperty
  8. , descriptor = { configurable: true, enumerable: false, writable: true }
  9. , on, once, off, emit, methods, descriptors, base;
  10. on = function (type, listener) {
  11. var data;
  12. callable(listener);
  13. if (!hasOwnProperty.call(this, '__ee__')) {
  14. data = descriptor.value = create(null);
  15. defineProperty(this, '__ee__', descriptor);
  16. descriptor.value = null;
  17. } else {
  18. data = this.__ee__;
  19. }
  20. if (!data[type]) data[type] = listener;
  21. else if (typeof data[type] === 'object') data[type].push(listener);
  22. else data[type] = [data[type], listener];
  23. return this;
  24. };
  25. once = function (type, listener) {
  26. var once, self;
  27. callable(listener);
  28. self = this;
  29. on.call(this, type, once = function () {
  30. off.call(self, type, once);
  31. apply.call(listener, this, arguments);
  32. });
  33. once.__eeOnceListener__ = listener;
  34. return this;
  35. };
  36. off = function (type, listener) {
  37. var data, listeners, candidate, i;
  38. callable(listener);
  39. if (!hasOwnProperty.call(this, '__ee__')) return this;
  40. data = this.__ee__;
  41. if (!data[type]) return this;
  42. listeners = data[type];
  43. if (typeof listeners === 'object') {
  44. for (i = 0; (candidate = listeners[i]); ++i) {
  45. if ((candidate === listener) ||
  46. (candidate.__eeOnceListener__ === listener)) {
  47. if (listeners.length === 2) data[type] = listeners[i ? 0 : 1];
  48. else listeners.splice(i, 1);
  49. }
  50. }
  51. } else {
  52. if ((listeners === listener) ||
  53. (listeners.__eeOnceListener__ === listener)) {
  54. delete data[type];
  55. }
  56. }
  57. return this;
  58. };
  59. emit = function (type) {
  60. var i, l, listener, listeners, args;
  61. if (!hasOwnProperty.call(this, '__ee__')) return;
  62. listeners = this.__ee__[type];
  63. if (!listeners) return;
  64. if (typeof listeners === 'object') {
  65. l = arguments.length;
  66. args = new Array(l - 1);
  67. for (i = 1; i < l; ++i) args[i - 1] = arguments[i];
  68. listeners = listeners.slice();
  69. for (i = 0; (listener = listeners[i]); ++i) {
  70. apply.call(listener, this, args);
  71. }
  72. } else {
  73. switch (arguments.length) {
  74. case 1:
  75. call.call(listeners, this);
  76. break;
  77. case 2:
  78. call.call(listeners, this, arguments[1]);
  79. break;
  80. case 3:
  81. call.call(listeners, this, arguments[1], arguments[2]);
  82. break;
  83. default:
  84. l = arguments.length;
  85. args = new Array(l - 1);
  86. for (i = 1; i < l; ++i) {
  87. args[i - 1] = arguments[i];
  88. }
  89. apply.call(listeners, this, args);
  90. }
  91. }
  92. };
  93. methods = {
  94. on: on,
  95. once: once,
  96. off: off,
  97. emit: emit
  98. };
  99. descriptors = {
  100. on: d(on),
  101. once: d(once),
  102. off: d(off),
  103. emit: d(emit)
  104. };
  105. base = defineProperties({}, descriptors);
  106. module.exports = exports = function (o) {
  107. return (o == null) ? create(base) : defineProperties(Object(o), descriptors);
  108. };
  109. exports.methods = methods;