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