Commit | Line | Data |
---|---|---|
4a4c1049 D |
1 | /* |
2 | * The same functionality as EventEmitter but with the inclusion of callbacks | |
3 | */ | |
4 | ||
5 | /* | |
6 | * Promise style object to emit events to listeners | |
7 | */ | |
8 | function EmitCall (event_name, event_data) { | |
9 | var that = this, | |
10 | completed = false, | |
11 | completed_fn = []; | |
12 | ||
13 | ||
14 | // Emit this event to an array of listeners | |
15 | function callListeners(listeners) { | |
16 | var current_event_idx = -1; | |
17 | ||
18 | // Make sure we have some data to pass to the listeners | |
19 | event_data = event_data || undefined; | |
20 | ||
21 | // If no bound listeners for this event, leave now | |
22 | if (listeners.length === 0) { | |
23 | emitComplete(); | |
24 | return; | |
25 | } | |
26 | ||
27 | ||
28 | // Call the next listener in our array | |
29 | function nextListener() { | |
30 | var listener, event_obj; | |
31 | ||
32 | // We want the next listener | |
33 | current_event_idx++; | |
34 | ||
35 | // If we've ran out of listeners end this emit call | |
36 | if (!listeners[current_event_idx]) { | |
37 | emitComplete(); | |
38 | return; | |
39 | } | |
40 | ||
41 | // Object the listener ammends to tell us what it's going to do | |
42 | event_obj = { | |
43 | // If changed to true, expect this listener is going to callback | |
44 | wait: false, | |
45 | ||
46 | // If wait is true, this callback must be called to continue running listeners | |
47 | callback: function () { | |
48 | // Invalidate this callback incase a listener decides to call it again | |
49 | callback = undefined; | |
50 | ||
51 | nextListener.apply(that); | |
52 | } | |
53 | }; | |
54 | ||
55 | ||
56 | listener = listeners[current_event_idx]; | |
57 | listener[1].call(listener[2] || that, event_obj, event_data); | |
58 | ||
59 | // If the listener hasn't signalled it's going to wait, proceed to next listener | |
60 | if (!event_obj.wait) { | |
61 | // Invalidate the callback just incase a listener decides to call it anyway | |
62 | event_obj.callback = undefined; | |
63 | ||
64 | nextListener(); | |
65 | } | |
66 | } | |
67 | ||
68 | nextListener(); | |
69 | } | |
70 | ||
71 | ||
72 | ||
73 | function emitComplete() { | |
74 | completed = true; | |
75 | ||
76 | // Call the completed functions | |
77 | (completed_fn || []).forEach(function (fn) { | |
78 | if (typeof fn === 'function') fn(); | |
79 | }); | |
80 | } | |
81 | ||
82 | ||
83 | ||
84 | function done(fn) { | |
85 | // Only accept functions | |
86 | if (typeof fn !== 'function') return false; | |
87 | ||
88 | completed_fn.push(fn); | |
89 | ||
90 | // If we have already completed the emits, call this now | |
91 | if (completed) fn(); | |
92 | } | |
93 | ||
94 | ||
95 | return { | |
96 | callListeners: callListeners, | |
97 | done: done | |
98 | }; | |
99 | } | |
100 | ||
101 | ||
102 | ||
103 | ||
104 | ||
105 | ||
106 | function PluginInterface () { | |
1378cef6 D |
107 | // Holder for all the bound listeners by this module |
108 | this._listeners = {}; | |
4a4c1049 D |
109 | } |
110 | ||
111 | ||
4a4c1049 D |
112 | PluginInterface.prototype.on = function (event_name, fn, scope) { |
113 | this._listeners[event_name] = this._listeners[event_name] || []; | |
114 | this._listeners[event_name].push(['on', fn, scope]); | |
115 | }; | |
116 | ||
117 | ||
118 | ||
119 | PluginInterface.prototype.once = function (event_name, fn, scope) { | |
120 | this._listeners[event_name] = this._listeners[event_name] || []; | |
121 | this._listeners[event_name].push(['once', fn, scope]); | |
122 | }; | |
123 | ||
124 | ||
125 | ||
126 | PluginInterface.prototype.off = function (event_name, fn, scope) { | |
127 | var idx; | |
128 | ||
129 | if (typeof event_name === 'undefined') { | |
130 | // Remove all listeners | |
1378cef6 | 131 | this._listeners = {}; |
4a4c1049 D |
132 | |
133 | } else if (typeof fn === 'undefined') { | |
134 | // Remove all of 1 event type | |
135 | delete this._listeners[event_name]; | |
136 | ||
137 | } else if (typeof scope === 'undefined') { | |
138 | // Remove a single event type + callback | |
139 | for (idx in (this._listeners[event_name] || [])) { | |
140 | if (this._listeners[event_name][idx][1] === fn) { | |
141 | delete this._listeners[event_name][idx]; | |
142 | } | |
143 | } | |
144 | } else { | |
145 | // Remove a single event type + callback + scope | |
146 | for (idx in (this._listeners[event_name] || [])) { | |
147 | if (this._listeners[event_name][idx][1] === fn && this._listeners[event_name][idx][2] === scope) { | |
148 | delete this._listeners[event_name][idx]; | |
149 | } | |
150 | } | |
151 | } | |
152 | }; | |
153 | ||
154 | ||
155 | ||
156 | // Call all the listeners for a certain event, passing them some event data that may be changed | |
157 | PluginInterface.prototype.emit = function (event_name, event_data) { | |
158 | var emitter = new EmitCall(event_name, event_data); | |
159 | var listeners = this._listeners[event_name] || []; | |
160 | ||
161 | // Once emitted, remove any 'once' bound listeners | |
162 | emitter.done(function () { | |
163 | listeners.forEach(function (listener, idx) { | |
164 | if (listener[0] === 'once') { | |
165 | listeners[idx] = undefined; | |
166 | } | |
167 | }); | |
168 | }); | |
169 | ||
170 | // Emit the event to the listeners and return | |
171 | emitter.callListeners(listeners); | |
172 | return emitter; | |
173 | }; | |
174 | ||
175 | ||
176 | module.exports = PluginInterface; | |
177 | ||
178 | ||
179 | ||
180 | /* | |
181 | * Example usage | |
182 | */ | |
183 | ||
184 | ||
185 | /* | |
186 | var modules = new PluginInterface(); | |
187 | ||
188 | ||
189 | ||
190 | // A plugin | |
191 | modules.on('client:command', function (event, data) { | |
192 | //event.wait = true; | |
193 | setTimeout(event.callback, 2000); | |
194 | }); | |
195 | ||
196 | ||
197 | ||
198 | ||
199 | // Core code that is being extended by plugins | |
200 | var data = { | |
201 | nick: 'prawnsalald', | |
202 | command: '/dothis' | |
203 | }; | |
204 | ||
205 | ||
206 | modules.emit('client:command', data).done(function () { | |
207 | console.log('Your command is: ' + data.command); | |
208 | }); | |
209 | */ |