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