+
+
+function PluginInterface () {
+ // Holder for all the bound listeners by this module
+ this._listeners = {};
+
+ // Event proxies
+ this._parent = null;
+ this._children = [];
+}
+
+
+
+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];
+ }
+ }
+ } 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];
+ }
+ }
+ }
+};
+
+
+
+PluginInterface.prototype.getListeners = function(event_name) {
+ return this._listeners[event_name] || [];
+};
+
+
+
+PluginInterface.prototype.createProxy = function() {
+ var proxy = new PluginInterface();
+ proxy._parent = this._parent || this;
+ proxy._parent._children.push(proxy);
+
+ return proxy;
+};
+
+
+
+PluginInterface.prototype.dispose = function() {
+ this.off();
+
+ if (this._parent) {
+ var idx = this._parent._children.indexOf(this);
+ if (idx > -1) {
+ this._parent._children.splice(idx, 1);
+ }
+ }
+};
+
+
+
+// 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),
+ listeners = [],
+ child_idx;
+
+ // Get each childs event listeners in order of last created
+ for(child_idx=this._children.length-1; child_idx>=0; child_idx--) {
+ listeners = listeners.concat(this._children[child_idx].getListeners(event_name));
+ }
+
+ // Now include any listeners directly on this instance
+ listeners = listeners.concat(this.getListeners(event_name));
+
+ // Once emitted, remove any 'once' bound listeners
+ emitter.then(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;
+};
+
+
+
+// Promise style object to emit events to listeners
+PluginInterface.prototype.EmitCall = function EmitCall (event_name, event_data) {