CTCP TIME fix
[KiwiIRC.git] / server / plugininterface.js
CommitLineData
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 */
8function 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
106function PluginInterface () {
107}
108
109
110// Holder for all the bound listeners by this module
111PluginInterface.prototype._listeners = {};
112
113
114
115PluginInterface.prototype.on = function (event_name, fn, scope) {
116 this._listeners[event_name] = this._listeners[event_name] || [];
117 this._listeners[event_name].push(['on', fn, scope]);
118};
119
120
121
122PluginInterface.prototype.once = function (event_name, fn, scope) {
123 this._listeners[event_name] = this._listeners[event_name] || [];
124 this._listeners[event_name].push(['once', fn, scope]);
125};
126
127
128
129PluginInterface.prototype.off = function (event_name, fn, scope) {
130 var idx;
131
132 if (typeof event_name === 'undefined') {
133 // Remove all listeners
134 this._listeners = [];
135
136 } else if (typeof fn === 'undefined') {
137 // Remove all of 1 event type
138 delete this._listeners[event_name];
139
140 } else if (typeof scope === 'undefined') {
141 // Remove a single event type + callback
142 for (idx in (this._listeners[event_name] || [])) {
143 if (this._listeners[event_name][idx][1] === fn) {
144 delete this._listeners[event_name][idx];
145 }
146 }
147 } else {
148 // Remove a single event type + callback + scope
149 for (idx in (this._listeners[event_name] || [])) {
150 if (this._listeners[event_name][idx][1] === fn && this._listeners[event_name][idx][2] === scope) {
151 delete this._listeners[event_name][idx];
152 }
153 }
154 }
155};
156
157
158
159// Call all the listeners for a certain event, passing them some event data that may be changed
160PluginInterface.prototype.emit = function (event_name, event_data) {
161 var emitter = new EmitCall(event_name, event_data);
162 var listeners = this._listeners[event_name] || [];
163
164 // Once emitted, remove any 'once' bound listeners
165 emitter.done(function () {
166 listeners.forEach(function (listener, idx) {
167 if (listener[0] === 'once') {
168 listeners[idx] = undefined;
169 }
170 });
171 });
172
173 // Emit the event to the listeners and return
174 emitter.callListeners(listeners);
175 return emitter;
176};
177
178
179module.exports = PluginInterface;
180
181
182
183/*
184 * Example usage
185 */
186
187
188/*
189var modules = new PluginInterface();
190
191
192
193// A plugin
194modules.on('client:command', function (event, data) {
195 //event.wait = true;
196 setTimeout(event.callback, 2000);
197});
198
199
200
201
202// Core code that is being extended by plugins
203var data = {
204 nick: 'prawnsalald',
205 command: '/dothis'
206};
207
208
209modules.emit('client:command', data).done(function () {
210 console.log('Your command is: ' + data.command);
211});
212*/