From: Jack Allnutt <jack@allnutt.eu> Date: Thu, 21 Aug 2014 11:22:32 +0000 (+0100) Subject: Use promise version of PluginInterface on the client X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=060391b1c47f6aed7bb64ca2e4896617aaf0f9c2;p=KiwiIRC.git Use promise version of PluginInterface on the client --- diff --git a/client/assets/plugins/textstyle.html b/client/assets/plugins/textstyle.html index 1097b52..3567d4d 100644 --- a/client/assets/plugins/textstyle.html +++ b/client/assets/plugins/textstyle.html @@ -140,6 +140,8 @@ if (data.params[1]) { data.params[1] = style_codes + ' ' + data.params[1]; } + + event.callback(); }); diff --git a/client/src/helpers/plugininterface.js b/client/src/helpers/plugininterface.js index 16d3d96..ee025d9 100644 --- a/client/src/helpers/plugininterface.js +++ b/client/src/helpers/plugininterface.js @@ -1,243 +1,133 @@ -/* - * The same functionality as EventEmitter but with the inclusion of callbacks - */ - - - -function PluginInterface () { - // Holder for all the bound listeners by this module - this._listeners = {}; +function PluginInterface() { + this.listeners = []; } +PluginInterface.prototype.on = PluginInterface.prototype.addListener = function addListener(type, listener) { + if (typeof listener !== 'function') { + throw new TypeError('listener must be a function'); + } - -PluginInterface.prototype.on = function (event_name, fn, scope) { - this._listeners[event_name] = this._listeners[event_name] || []; - this._listeners[event_name].push(['on', fn, scope]); -}; - - - -PluginInterface.prototype.once = function (event_name, fn, scope) { - this._listeners[event_name] = this._listeners[event_name] || []; - this._listeners[event_name].push(['once', fn, scope]); -}; - - - -PluginInterface.prototype.off = function (event_name, fn, scope) { - var idx; - - if (typeof event_name === 'undefined') { - // Remove all listeners - this._listeners = {}; - - } else if (typeof fn === 'undefined') { - // Remove all of 1 event type - delete this._listeners[event_name]; - - } else if (typeof scope === 'undefined') { - // Remove a single event type + callback - for (idx in (this._listeners[event_name] || [])) { - if (this._listeners[event_name][idx][1] === fn) { - delete this._listeners[event_name][idx]; - } + if (this.listeners[type]) { + if (!_.contains(this.listeners[type], listener)) { + this.listeners[type].push(listener); } } else { - // Remove a single event type + callback + scope - for (idx in (this._listeners[event_name] || [])) { - if (this._listeners[event_name][idx][1] === fn && this._listeners[event_name][idx][2] === scope) { - delete this._listeners[event_name][idx]; - } - } + this.listeners[type] = [listener]; } -}; - - -// Call all the listeners for a certain event, passing them some event data that may be changed -PluginInterface.prototype.emit = function (event_name, event_data) { - var emitter = new this.EmitCall(event_name, event_data); - var listeners = this._listeners[event_name] || []; - - // Once emitted, remove any 'once' bound listeners - emitter.done(function () { - var len = listeners.length, - idx; - - for(idx = 0; idx < len; idx++) { - if (listeners[idx][0] === 'once') { - listeners[idx] = undefined; - } - } - }); - - // Emit the event to the listeners and return - emitter.callListeners(listeners); - return emitter; + return this; }; - - -// Promise style object to emit events to listeners -PluginInterface.prototype.EmitCall = function EmitCall (event_name, event_data) { - var that = this, - completed = false, - completed_fn = [], - - // Has event.preventDefault() been called - prevented = false, - prevented_fn = []; - - - // Emit this event to an array of listeners - function callListeners(listeners) { - var current_event_idx = -1; - - // Make sure we have some data to pass to the listeners - event_data = event_data || undefined; - - // If no bound listeners for this event, leave now - if (listeners.length === 0) { - emitComplete(); - return; - } - - - // Call the next listener in our array - function nextListener() { - var listener, event_obj; - - // We want the next listener - current_event_idx++; - - // If we've ran out of listeners end this emit call - if (!listeners[current_event_idx]) { - emitComplete(); - return; - } - - // Object the listener ammends to tell us what it's going to do - event_obj = { - // If changed to true, expect this listener is going to callback - wait: false, - - // If wait is true, this callback must be called to continue running listeners - callback: function () { - // Invalidate this callback incase a listener decides to call it again - event_obj.callback = undefined; - - nextListener.apply(that); - }, - - // Prevents the default 'done' functions from executing - preventDefault: function () { - prevented = true; - } - }; - - - listener = listeners[current_event_idx]; - listener[1].call(listener[2] || that, event_obj, event_data); - - // If the listener hasn't signalled it's going to wait, proceed to next listener - if (!event_obj.wait) { - // Invalidate the callback just incase a listener decides to call it anyway - event_obj.callback = undefined; - - nextListener(); - } - } - - nextListener(); +PluginInterface.prototype.once = function once(type, listener) { + if (typeof listener !== 'function') { + throw new TypeError('listener must be a function'); } + var fired = false; + function g() { + this.removeListener(type, g); - function emitComplete() { - completed = true; - - var funcs = prevented ? prevented_fn : completed_fn; - funcs = funcs || []; - - // Call the completed/prevented functions - for (var idx = 0; idx < funcs.length; idx++) { - if (typeof funcs[idx] === 'function') funcs[idx](); + if (!fired) { + fired = true; + listener.apply(this, arguments); } } + g.listener = listener; + this.on(type, g); + return this; +}; - function addCompletedFunc(fn) { - // Only accept functions - if (typeof fn !== 'function') return false; - - completed_fn.push(fn); - - // If we have already completed the emits, call this now - if (completed && !prevented) fn(); - +PluginInterface.prototype.off = PluginInterface.prototype.removeListener = function removeListener(type, listener) { + if (!this.listeners[type]) { return this; } + this.listeners[type] = _.without(this.listeners[type], listener); + return this; +}; - function addPreventedFunc(fn) { - // Only accept functions - if (typeof fn !== 'function') return false; - - prevented_fn.push(fn); - - // If we have already completed the emits, call this now - if (completed && prevented) fn(); - - return this; - } +PluginInterface.prototype.emit = function emit(type, data) { + var that = this; + return new Promise(function (emit_resolve, emit_reject) { + var rejected = false, + rejected_reasons = []; + if (!that.listeners[type]) { + return emit_resolve(data); + } - return { - callListeners: callListeners, - done: addCompletedFunc, - prevented: addPreventedFunc - }; + (that.listeners[type].reduce(function (listener_promise, listener) { + return listener_promise.then(function (data) { + return new Promise(function (resolve) { + listener({ + callback: function () { + resolve(data); + }, + preventDefault: function (reason) { + rejected = true; + if (reason) { + rejected_reasons.push(reason); + } + } + }, data); + }); + }); + }, Promise.resolve(data))).then(function (data) { + if (rejected) { + emit_reject({data: data, reasons: rejected_reasons}); + } else { + emit_resolve(data); + } + }); + }); }; - - // If running a node module, set the exports if (typeof module === 'object' && typeof module.exports !== 'undefined') { module.exports = PluginInterface; } +/* Test cases - -/* - * Example usage - */ - - -/* -var modules = new PluginInterface(); - - - -// A plugin -modules.on('client:command', function (event, data) { - //event.wait = true; - setTimeout(event.callback, 2000); +var p = new PluginInterface(); +p.on('test', function (event, data) { + data.a += '!'; + event.callback(); }); +p.emit('test', {a: 'hello world'}).then(function (data) { + if (data.a === 'hello world!') { + console.log('Test passed'); + } else { + console.error('Test failed!'); + } +}, function (err) { + console.error('Test failed!'); +}); - -// Core code that is being extended by plugins -var data = { - nick: 'prawnsalald', - command: '/dothis' -}; - - -modules.emit('client:command', data).done(function () { - console.log('Your command is: ' + data.command); +var p = new PluginInterface(); +p.on('test', function (event, data) { + data.a += '!'; + event.callback(); }); -*/ \ No newline at end of file +p.on('test', function (event) { + event.preventDefault('testing'); + event.callback(); +}) + +p.emit('test', {a:'hello world'}).then(function (){ + console.error('Test failed!'); +}, function (data, reasons) { + if ((data.data.a === 'hello world!') && (data.reasons.length === 1 && data.reasons[0] === 'testing')) { + console.log('Test passed'); + } else { + console.error('Test failed!'); + } +}); + +*/ diff --git a/client/src/models/network.js b/client/src/models/network.js index df8ac53..1bd3c32 100644 --- a/client/src/models/network.js +++ b/client/src/models/network.js @@ -431,7 +431,7 @@ function onMessage(event) { _kiwi.global.events.emit('message:new', {network: this, message: event}) - .done(_.bind(function() { + .then(_.bind(function() { var panel, is_pm = ((event.target || '').toLowerCase() == this.get('nick').toLowerCase()); diff --git a/client/src/views/channel.js b/client/src/views/channel.js index f3d1ac9..7961fa5 100644 --- a/client/src/views/channel.js +++ b/client/src/views/channel.js @@ -61,7 +61,7 @@ _kiwi.view.Channel = _kiwi.view.Panel.extend({ msg = this.generateMessageDisplayObj(msg); _kiwi.global.events.emit('message:display', {panel: this.model, message: msg}) - .done(_.bind(function() { + .then(_.bind(function() { var line_msg; // Format the nick to the config defined format diff --git a/client/src/views/controlbox.js b/client/src/views/controlbox.js index 4fbedf8..29792e7 100644 --- a/client/src/views/controlbox.js +++ b/client/src/views/controlbox.js @@ -284,7 +284,7 @@ _kiwi.view.ControlBox = Backbone.View.extend({ events_data = {command: command, params: params}; _kiwi.global.events.emit('command', events_data) - .done(function() { + .then(function() { // Trigger the command events that.trigger('command', {command: events_data.command, params: events_data.params}); that.trigger('command:' + events_data.command, {command: events_data.command, params: events_data.params}); diff --git a/client/src/views/memberlist.js b/client/src/views/memberlist.js index a582087..8a05152 100644 --- a/client/src/views/memberlist.js +++ b/client/src/views/memberlist.js @@ -52,7 +52,7 @@ _kiwi.view.MemberList = Backbone.View.extend({ menu.showFooter(false); _kiwi.global.events.emit('usermenu:created', {menu: menu, userbox: userbox}) - .done(_.bind(function() { + .then(_.bind(function() { menu.show(); var t = event.pageY,