From 18187591faf3c31676d19ae4c748b1c4982baf28 Mon Sep 17 00:00:00 2001 From: tony_shen Date: Tue, 13 Dec 2016 18:14:25 +0800 Subject: [PATCH 01/20] support regex for event type support multi event types for listener --- README.md | 23 +++ lib/eventbus.min.js | 2 +- src/EventBus.js | 381 ++++++++++++++++++++++++++++++++------------ 3 files changed, 306 insertions(+), 100 deletions(-) diff --git a/README.md b/README.md index 7d7eb57..6615538 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,17 @@ var EventBus = require('eventbusjs'); // @callback - function // @scope - the scope where the @callback is defined EventBus.addEventListener(type, callback, scope) +//or +EventBus.on(type,callback,scope) +//or +EventBus.bind(type,callback,scope) +//or +EventBus.once(type,callback,scope) +//or +//support regex and multi event types +EventBus.on(['click','change',/\w_click/],function(event,value) { + +}); ``` ### `removeEventListener` @@ -36,6 +47,10 @@ EventBus.addEventListener(type, callback, scope) // @callback - function // @scope - the scope where the @callback is defined EventBus.removeEventListener(type, callback, scope) +//or +EventBus.off(type,callback,scope) +//or +EventBus.unbind(type,callback,scope) ``` ### `hasEventListener` @@ -45,6 +60,8 @@ EventBus.removeEventListener(type, callback, scope) // @callback - function // @scope - the scope where the @callback is defined EventBus.hasEventListener(type, callback, scope) +//or +EventBus.has(type,calback,scope) ``` ### `dispatch` @@ -54,6 +71,10 @@ EventBus.hasEventListener(type, callback, scope) // @target - the caller // @args - pass as many arguments as you want EventBus.dispatch(type, target, args ...) +//or +EventBus.trigger(type,target,args...) +//or +EventBus.emit(type,target,args...) ``` ### `getEvents` @@ -72,6 +93,8 @@ function myFunction(event) { } EventBus.addEventListener("my_function_event", myFunction); EventBus.dispatch("my_function_event"); +//EventBus.trigger("my_function_event"); +//EventBus.emit("my_function_event"); ``` ## Keeping the scope diff --git a/lib/eventbus.min.js b/lib/eventbus.min.js index 002ea87..a104021 100644 --- a/lib/eventbus.min.js +++ b/lib/eventbus.min.js @@ -1 +1 @@ -(function(root,factory){if(typeof exports==="object"&&typeof module==="object")module.exports=factory();else if(typeof define==="function"&&define.amd)define("EventBus",[],factory);else if(typeof exports==="object")exports["EventBus"]=factory();else root["EventBus"]=factory()})(this,function(){var EventBusClass={};EventBusClass=function(){this.listeners={}};EventBusClass.prototype={addEventListener:function(type,callback,scope){var args=[];var numOfArgs=arguments.length;for(var i=0;i3?args.splice(3,args.length-1):[];if(typeof this.listeners[type]!="undefined"){this.listeners[type].push({scope:scope,callback:callback,args:args})}else{this.listeners[type]=[{scope:scope,callback:callback,args:args}]}},removeEventListener:function(type,callback,scope){if(typeof this.listeners[type]!="undefined"){var numOfCallbacks=this.listeners[type].length;var newArray=[];for(var i=0;i0}for(var i=0;i2?args.splice(2,args.length-1):[];args=[event].concat(args);if(typeof this.listeners[type]!="undefined"){var numOfCallbacks=this.listeners[type].length;for(var i=0;iarray.length)return[];return[].slice.call(array,start==undefined?0:start,end==undefined?array.length:end)||[]}function processMultiTypes(type,callback,args){if(typeof type=="string"||type instanceof Array){var types=type;if(typeof type=="string")types=type.trim().split(/\s|,/);if(types.length>1){var that=this;iterator(types,function(index,type){args[0]=type;callback.apply(that,args)});return that}else{type=types[0]}}return type}var EventBusClass={};EventBusClass=function(){this.listeners={};this.regexListeners=[]};EventBusClass.prototype={on:function(type,callback,scope){type=processMultiTypes.call(this,type,this.on,slice(arguments));if(type==this)return this;var isRegExpType=type instanceof RegExp;var eventType=isRegExpType?type.toString():type;var args=slice(arguments,3);var listener={scope:scope||{},callback:callback,args:args,regExp:type,eventType:eventType};if(!isRegExpType){if(typeof this.listeners[eventType]!="undefined"){this.listeners[eventType].push(listener)}else{this.listeners[eventType]=[listener]}}else this.regexListeners.push(listener);return this},once:function(type,callback,scope){var bus=this;var proxyCallback=function(event){callback.apply(this,slice(arguments));bus.off(type,proxyCallback,scope)};return bus.on(type,proxyCallback,scope)},off:function(type,callback,scope){type=processMultiTypes.call(this,type,this.off,[undefined,callback,scope]);if(type==this)return this;var isRegExpType=type instanceof RegExp;var eventType=isRegExpType?type.toString():type;var newArray=[];if(typeof callback=="object"){scope=callback;callback=undefined}var allCallback=callback==undefined;var allScope=scope==undefined;function isRemove(listener){return(allCallback?true:listener.callback==callback)&&(allScope?true:listener.scope==scope)}if(!isRegExpType){if(typeof this.listeners[eventType]!="undefined"){if(!(allCallback&&allScope))iterator(this.listeners[eventType],function(i,listener){if(!isRemove(listener))newArray.push(listener);else{}});this.listeners[eventType]=newArray}}else{iterator(this.regexListeners,function(index,listener){if(!(listener.eventType==eventType&&isRemove(listener)))newArray.push(listener);else{}});this.regexListeners=newArray}return this},has:function(type,callback,scope){var isRegExpType=type instanceof RegExp;var eventType=isRegExpType?type.toString():type;var listeners=[].concat(this.listeners[eventType]);if(typeof callback=="object"){scope=callback;callback=undefined}if(listeners.length>0&&!isRegExpType){var numOfCallbacks=listeners.length;if(callback===undefined&&scope===undefined){return numOfCallbacks>0}var result=iterator(listeners,function(index,listener,array,iterator){if((scope?listener.scope==scope:true)&&(callback?listener.callback==callback:true)){iterator.stop(true)}});if(result)return true}else if(isRegExpType){listeners=[].concat(this.regexListeners);var result=iterator(listeners,function(index,listener,array,iterator){if(listener.regExp.toString()==eventType&&(scope?listener.scope==scope:true)&&(callback?listener.callback==callback:true)){iterator.stop(true)}});if(result)return true}return false},emit:function(type){type=processMultiTypes.call(this,type,this.emit,slice(arguments));if(type==this)return this;var event={type:type};var args=[event].concat(slice(arguments,1));var listeners=[].concat(typeof this.listeners[type]=="undefined"?[]:this.listeners[type]);function dispatchEvent(listeners){var isStop=false;event.stop=function(){isStop=true};iterator(listeners,function(index,listener,listeners,iterator){if(listener&&listener.callback){var listenerArgs=[].concat(args);event.args=[].concat(listener.args);listener.callback.apply(listener.scope,listenerArgs);if(isStop)iterator.stop()}})}var regexListeners=[].concat(this.regexListeners);iterator(regexListeners,function(i,listener){if(listener.regExp.test(type)){listeners.push(listener)}});dispatchEvent(listeners);return this},getEvents:function(){var str="";for(var type in this.listeners){var numOfCallbacks=this.listeners[type].length;for(var i=0;i 3 ? args.splice(3, args.length-1) : []; - if(typeof this.listeners[type] != "undefined") { - this.listeners[type].push({scope:scope, callback:callback, args:args}); - } else { - this.listeners[type] = [{scope:scope, callback:callback, args:args}]; - } - }, - removeEventListener:function(type, callback, scope) { - if(typeof this.listeners[type] != "undefined") { - var numOfCallbacks = this.listeners[type].length; - var newArray = []; - for(var i=0; i 0; - } - for(var i=0; i 2 ? args.splice(2, args.length-1) : []; - args = [event].concat(args); - if(typeof this.listeners[type] != "undefined") { - var numOfCallbacks = this.listeners[type].length; - for(var i=0; i array.length)return []; + return [].slice.call(array, start == undefined ? 0 : start, end == undefined ? array.length : end) || []; + } + + function processMultiTypes(type, callback, args) { + if (typeof type == "string" || type instanceof Array) { + var types = type; + if (typeof type == "string") types = type.trim().split(/\s|,/); + if (types.length > 1) { + var that = this; + iterator(types, function (index, type) { + args[0] = type; + callback.apply(that, args); + }); + return that; + } else { + type = types[0]; + } + } + return type; + } + + + var EventBusClass = {}; + EventBusClass = function () { + this.listeners = {}; + this.regexListeners = []; + }; + EventBusClass.prototype = { + /** + * EventBus.on("click",callback); + * EventBus.on("click",callback,buttonScope); + * @param type + * @param callback + * @param scope + * @returns {EventBusClass} + */ + on: function (type, callback, scope) { + type = processMultiTypes.call(this, type, this.on, slice(arguments)); + if (type == this)return this; + + var isRegExpType = type instanceof RegExp; + var eventType = isRegExpType ? type.toString() : type; + var args = slice(arguments, 3); + var listener = {//create listener stub + scope: scope || {}, + callback: callback, + args: args, + regExp: type, + eventType: eventType + }; + if (!isRegExpType) { + if (typeof this.listeners[eventType] != "undefined") { + this.listeners[eventType].push(listener); + } else { + this.listeners[eventType] = [listener]; + } + } else + this.regexListeners.push(listener); + return this; + }, + /** + * EventBus.once("click",callback); + * EventBus.once("click",callback,buttonScope); + * @param type + * @param callback + * @param scope + * @returns {EventBusClass} + */ + once: function (type, callback, scope) { + var bus = this; + var proxyCallback = function (event) { + callback.apply(this, slice(arguments)); + bus.off(type, proxyCallback, scope); + }; + return bus.on(type, proxyCallback, scope); + }, + /** + * EventBus.off("click"); //remove all click listeners + * EventBus.off("click",onClick); + * EventBus.off("click",onClick,buttonScope); + * EventBus.off("click",buttonScope); + * EventBus.off("click").off("mousemove"); + * @param type + * @param callback + * @param scope + * @returns {EventBusClass} + */ + off: function (type, callback, scope) { + //support EventBus.off(['click',/click/]); + type = processMultiTypes.call(this, type, this.off, [undefined, callback, scope]); + if (type == this)return this; + + var isRegExpType = type instanceof RegExp; + var eventType = isRegExpType ? type.toString() : type; + var newArray = []; + if (typeof callback == "object") { + scope = callback; + callback = undefined; + } + var allCallback = callback == undefined; + var allScope = scope == undefined; + // console.log("off event type:", type, " all callback:", allCallback, " all scope:", allScope); + // console.log("callback:", callback, " scope:", scope); + function isRemove(listener) { + return (allCallback ? true : listener.callback == callback) && + (allScope ? true : listener.scope == scope) + } + + if (!isRegExpType) { + if (typeof this.listeners[eventType] != "undefined") { + if (!(allCallback && allScope)) + iterator(this.listeners[eventType], function (i, listener) { + if (!isRemove(listener)) newArray.push(listener); + else { + // console.log("remove event listener:", type, listener); + } + }); + this.listeners[eventType] = newArray; + } + } else { + iterator(this.regexListeners, function (index, listener) { + if (!(listener.eventType == eventType && isRemove(listener))) newArray.push(listener); + else { + // console.log("remove listener:", type, listener); + } + }); + this.regexListeners = newArray; + } + return this; + }, + /** + * EventBus.has("click") + * EventBus.has("click",buttonScope); + * EventBus.has("click",callback); + * EventBus.has("click",callback,buttonScope); + * @param type + * @param callback + * @param scope + * @returns {boolean} + */ + has: function (type, callback, scope) { + var isRegExpType = type instanceof RegExp; + var eventType = isRegExpType ? type.toString() : type; + var listeners = [].concat(this.listeners[eventType]); + if (typeof callback == "object") { + scope = callback; + callback = undefined; + } + if (listeners.length > 0 && !isRegExpType) { + + var numOfCallbacks = listeners.length; + if (callback === undefined && scope === undefined) { + return numOfCallbacks > 0; + } + + var result = iterator(listeners, function (index, listener, array, iterator) { + if ((scope ? listener.scope == scope : true) + && (callback ? listener.callback == callback : true)) { + iterator.stop(true); + } + }); + + if (result)return true; + } else if (isRegExpType) { + listeners = [].concat(this.regexListeners); + var result = iterator(listeners, function (index, listener, array, iterator) { + if (listener.regExp.toString() == eventType + && (scope ? listener.scope == scope : true) + && (callback ? listener.callback == callback : true)) { + iterator.stop(true); + } + }); + if (result)return true; + } + return false; + }, + /** + * EventBus.emit("click"); + * EventBus.emit("click",argument1,...); + * @param type + * @returns {EventBusClass} + */ + emit: function (type) { + // console.log("emit arguments:",arguments); + + type = processMultiTypes.call(this, type, this.emit, slice(arguments)); + if (type == this)return this; + + var event = { + type: type + }; + var args = [event].concat(slice(arguments, 1)); + // console.log("emit arguments:",arguments," listener arguments:",args); + var listeners = [].concat(typeof this.listeners[type] == "undefined" ? [] : this.listeners[type]); + + function dispatchEvent(listeners) { + var isStop = false; + event.stop = function () { + isStop = true; + }; + iterator(listeners, function (index, listener, listeners, iterator) { + if (listener && listener.callback) { + var listenerArgs = [].concat(args); + // console.log("event listener call arguments:",listenerArgs); + event.args = [].concat(listener.args); + // console.log("fire event listener:", listener); + listener.callback.apply(listener.scope, listenerArgs); + if (isStop) iterator.stop(); + } + }); + } + + var regexListeners = [].concat(this.regexListeners); + + iterator(regexListeners, function (i, listener) { + if (listener.regExp.test(type)) { + listeners.push(listener); + } + }); + + dispatchEvent(listeners); + return this; + }, + getEvents: function () { + var str = ""; + for (var type in this.listeners) { + var numOfCallbacks = this.listeners[type].length; + for (var i = 0; i < numOfCallbacks; i++) { + var listener = this.listeners[type][i]; + str += listener.scope && listener.scope.className ? listener.scope.className : "anonymous"; + str += " listen for '" + type + "'\n"; + } + } + + iterator([].concat(this.regexListeners), function (index, listener) { + str += listener.scope && listener.scope.className ? listener.scope.className : "anonymous"; + str += " listen for '" + listener.eventType + "'\n"; + }); + + return str; + } + }; + //alis + EventBusClass.prototype.bind = EventBusClass.prototype.addEventListener = EventBusClass.prototype.on; + EventBusClass.prototype.unbind = EventBusClass.prototype.removeEventListener = EventBusClass.prototype.off; + EventBusClass.prototype.trigger = EventBusClass.prototype.dispatch = EventBusClass.prototype.emit; + EventBusClass.prototype.hasEventListener = EventBusClass.prototype.has; + + var EventBus = new EventBusClass(); + return EventBus; +}); From 73f1a1870247499e7998d8a3fef0d588ec1d6816 Mon Sep 17 00:00:00 2001 From: tony_shen Date: Tue, 13 Dec 2016 23:11:15 +0800 Subject: [PATCH 02/20] compatibility with older versions --- README.md | 23 ++++++++++++++++++++--- example/browser/example.html | 8 ++++---- lib/eventbus.min.js | 2 +- src/EventBus.js | 10 ++++++---- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6615538..4e6fba0 100644 --- a/README.md +++ b/README.md @@ -90,11 +90,28 @@ EventBus.getEvents() ```js function myFunction(event) { console.log("myFunction type=" + event.type); + //can stop event + event.stop(); + //can obtain listener arguments + console.log(event.args); + + //can access scope by this + console.log(this); + } -EventBus.addEventListener("my_function_event", myFunction); +var scope ={ + +}; +EventBus.addEventListener("my_function_event", myFunction,scope,1,2,3...); +//or +EventBus.on("my_function_event",myFunction,scope,1,2,3...); + +// dispatch event EventBus.dispatch("my_function_event"); -//EventBus.trigger("my_function_event"); -//EventBus.emit("my_function_event"); +//or +EventBus.trigger("my_function_event"); +//or +EventBus.emit("my_function_event"); ``` ## Keeping the scope diff --git a/example/browser/example.html b/example/browser/example.html index 44aae0b..2984a8b 100644 --- a/example/browser/example.html +++ b/example/browser/example.html @@ -55,7 +55,7 @@ var t1 = new TestClass1(); var t2 = new TestClass2(); - EventBus.addEventListener("custom_event", t1.doSomething, t1); + EventBus.on("custom_event", t1.doSomething, t1); t2.ready(); // ****************************************************************************************** @@ -63,9 +63,9 @@ var winterHandler = function() { console.log("arguments", arguments); } - EventBus.addEventListener("let-it-snow", winterHandler, null, "and happy", "new year"); - EventBus.dispatch("let-it-snow", null, "merry", "christmas"); - EventBus.dispatch("let-it-snow", null, "merry", "christmas"); + EventBus.on("let-it-snow", winterHandler, null, "and happy", "new year"); + EventBus.emit("let-it-snow", null, "merry", "christmas"); + EventBus.trigger("let-it-snow", null, "merry", "christmas"); EventBus.dispatch("let-it-snow", null, "merry", "christmas"); } diff --git a/lib/eventbus.min.js b/lib/eventbus.min.js index a104021..3d6aa60 100644 --- a/lib/eventbus.min.js +++ b/lib/eventbus.min.js @@ -1 +1 @@ -(function(root,factory){if(typeof exports==='object'&&typeof module==='object')module.exports=factory();else if(typeof define==='function'&&define.amd)define("EventBus",[],factory);else if(typeof exports==='object')exports["EventBus"]=factory();else root["EventBus"]=factory()})(this,function(){function iterator(array,callback){array=array||[];var iterator={stop:function(result){this.isStopped=true;this.result=result}};for(var i in array){callback(i,array[i],array,iterator);if(iterator.isStopped)break}if(iterator.isStopped)return iterator.result}function slice(array,start,end){if(start>array.length)return[];return[].slice.call(array,start==undefined?0:start,end==undefined?array.length:end)||[]}function processMultiTypes(type,callback,args){if(typeof type=="string"||type instanceof Array){var types=type;if(typeof type=="string")types=type.trim().split(/\s|,/);if(types.length>1){var that=this;iterator(types,function(index,type){args[0]=type;callback.apply(that,args)});return that}else{type=types[0]}}return type}var EventBusClass={};EventBusClass=function(){this.listeners={};this.regexListeners=[]};EventBusClass.prototype={on:function(type,callback,scope){type=processMultiTypes.call(this,type,this.on,slice(arguments));if(type==this)return this;var isRegExpType=type instanceof RegExp;var eventType=isRegExpType?type.toString():type;var args=slice(arguments,3);var listener={scope:scope||{},callback:callback,args:args,regExp:type,eventType:eventType};if(!isRegExpType){if(typeof this.listeners[eventType]!="undefined"){this.listeners[eventType].push(listener)}else{this.listeners[eventType]=[listener]}}else this.regexListeners.push(listener);return this},once:function(type,callback,scope){var bus=this;var proxyCallback=function(event){callback.apply(this,slice(arguments));bus.off(type,proxyCallback,scope)};return bus.on(type,proxyCallback,scope)},off:function(type,callback,scope){type=processMultiTypes.call(this,type,this.off,[undefined,callback,scope]);if(type==this)return this;var isRegExpType=type instanceof RegExp;var eventType=isRegExpType?type.toString():type;var newArray=[];if(typeof callback=="object"){scope=callback;callback=undefined}var allCallback=callback==undefined;var allScope=scope==undefined;function isRemove(listener){return(allCallback?true:listener.callback==callback)&&(allScope?true:listener.scope==scope)}if(!isRegExpType){if(typeof this.listeners[eventType]!="undefined"){if(!(allCallback&&allScope))iterator(this.listeners[eventType],function(i,listener){if(!isRemove(listener))newArray.push(listener);else{}});this.listeners[eventType]=newArray}}else{iterator(this.regexListeners,function(index,listener){if(!(listener.eventType==eventType&&isRemove(listener)))newArray.push(listener);else{}});this.regexListeners=newArray}return this},has:function(type,callback,scope){var isRegExpType=type instanceof RegExp;var eventType=isRegExpType?type.toString():type;var listeners=[].concat(this.listeners[eventType]);if(typeof callback=="object"){scope=callback;callback=undefined}if(listeners.length>0&&!isRegExpType){var numOfCallbacks=listeners.length;if(callback===undefined&&scope===undefined){return numOfCallbacks>0}var result=iterator(listeners,function(index,listener,array,iterator){if((scope?listener.scope==scope:true)&&(callback?listener.callback==callback:true)){iterator.stop(true)}});if(result)return true}else if(isRegExpType){listeners=[].concat(this.regexListeners);var result=iterator(listeners,function(index,listener,array,iterator){if(listener.regExp.toString()==eventType&&(scope?listener.scope==scope:true)&&(callback?listener.callback==callback:true)){iterator.stop(true)}});if(result)return true}return false},emit:function(type){type=processMultiTypes.call(this,type,this.emit,slice(arguments));if(type==this)return this;var event={type:type};var args=[event].concat(slice(arguments,1));var listeners=[].concat(typeof this.listeners[type]=="undefined"?[]:this.listeners[type]);function dispatchEvent(listeners){var isStop=false;event.stop=function(){isStop=true};iterator(listeners,function(index,listener,listeners,iterator){if(listener&&listener.callback){var listenerArgs=[].concat(args);event.args=[].concat(listener.args);listener.callback.apply(listener.scope,listenerArgs);if(isStop)iterator.stop()}})}var regexListeners=[].concat(this.regexListeners);iterator(regexListeners,function(i,listener){if(listener.regExp.test(type)){listeners.push(listener)}});dispatchEvent(listeners);return this},getEvents:function(){var str="";for(var type in this.listeners){var numOfCallbacks=this.listeners[type].length;for(var i=0;i_9.length){return [];}return [].slice.call(_9,_a==undefined?0:_a,_b==undefined?_9.length:_b)||[];};function _c(_d,_e,_f){if(typeof _d=="string"||_d instanceof Array){var _10=_d;if(typeof _d=="string"){_10=_d.trim().split(/\s|,/);}if(_10.length>1){var _11=this;_3(_10,function(_12,_13){_f[0]=_13;_e.apply(_11,_f);});return _11;}else{_d=_10[0];}}return _d;};var _14={};_14=function(){this.listeners={};this.regexListeners=[];};_14.prototype={on:function(_15,_16,_17){_15=_c.call(this,_15,this.on,_8(arguments));if(_15==this){return this;}var _18=_15 instanceof RegExp;var _19=_18?_15.toString():_15;var _1a=_8(arguments,3);var _1b={scope:_17||{},callback:_16,args:_1a,regExp:_15,eventType:_19};if(!_18){if(typeof this.listeners[_19]!="undefined"){this.listeners[_19].push(_1b);}else{this.listeners[_19]=[_1b];}}else{this.regexListeners.push(_1b);}return this;},once:function(_1c,_1d,_1e){var bus=this;var _1f=function(_20){_1d.apply(this,_8(arguments));bus.off(_1c,_1f,_1e);};return bus.on(_1c,_1f,_1e);},off:function(_21,_22,_23){_21=_c.call(this,_21,this.off,[undefined,_22,_23]);if(_21==this){return this;}var _24=_21 instanceof RegExp;var _25=_24?_21.toString():_21;var _26=[];if(typeof _22=="object"){_23=_22;_22=undefined;}var _27=_22==undefined;var _28=_23==undefined;function _29(_2a){return (_27?true:_2a.callback==_22)&&(_28?true:_2a.scope==_23);};if(!_24){if(typeof this.listeners[_25]!="undefined"){if(!(_27&&_28)){_3(this.listeners[_25],function(i,_2b){if(!_29(_2b)){_26.push(_2b);}else{}});}this.listeners[_25]=_26;}}else{_3(this.regexListeners,function(_2c,_2d){if(!(_2d.eventType==_25&&_29(_2d))){_26.push(_2d);}else{}});this.regexListeners=_26;}return this;},has:function(_2e,_2f,_30){var _31=_2e instanceof RegExp;var _32=_31?_2e.toString():_2e;var _33=[].concat(this.listeners[_32]);if(typeof _2f=="object"){_30=_2f;_2f=undefined;}if(_33.length>0&&!_31){var _34=_33.length;if(_2f===undefined&&_30===undefined){return _34>0;}var _35=_3(_33,function(_36,_37,_38,_39){if((_30?_37.scope==_30:true)&&(_2f?_37.callback==_2f:true)){_39.stop(true);}});if(_35){return true;}}else{if(_31){_33=[].concat(this.regexListeners);var _35=_3(_33,function(_3a,_3b,_3c,_3d){if(_3b.regExp.toString()==_32&&(_30?_3b.scope==_30:true)&&(_2f?_3b.callback==_2f:true)){_3d.stop(true);}});if(_35){return true;}}}return false;},emit:function(_3e){var _3f=_8(arguments);_3e=_c.call(this,_3e,this.emit,_3f);if(_3e==this){return this;}var _40={type:_3e,target:_3f.length>1?_3f[1]:{}};_3f=[_40].concat(_8(arguments,1));var _41=[].concat(typeof this.listeners[_3e]=="undefined"?[]:this.listeners[_3e]);function _42(_43){var _44=false;_40.stop=function(){_44=true;};_3(_43,function(_45,_46,_47,_48){if(_46&&_46.callback){var _49=[].concat(_3f);_40.args=[].concat(_46.args);_46.callback.apply(_46.scope,_49);if(_44){_48.stop();}}});};var _4a=[].concat(this.regexListeners);_3(_4a,function(i,_4b){if(_4b.regExp.test(_3e)){_41.push(_4b);}});_42(_41);return this;},getEvents:function(){var str="";for(var _4c in this.listeners){var _4d=this.listeners[_4c].length;for(var i=0;i<_4d;i++){var _4e=this.listeners[_4c][i];str+=_4e.scope&&_4e.scope.className?_4e.scope.className:"anonymous";str+=" listen for '"+_4c+"'\n";}}_3([].concat(this.regexListeners),function(_4f,_50){str+=_50.scope&&_50.scope.className?_50.scope.className:"anonymous";str+=" listen for '"+_50.eventType+"'\n";});return str;}};_14.prototype.bind=_14.prototype.addEventListener=_14.prototype.on;_14.prototype.unbind=_14.prototype.removeEventListener=_14.prototype.off;_14.prototype.trigger=_14.prototype.dispatch=_14.prototype.emit;_14.prototype.hasEventListener=_14.prototype.has;var _51=new _14();return _51;}); \ No newline at end of file diff --git a/src/EventBus.js b/src/EventBus.js index c2ee1dd..1e5fe75 100644 --- a/src/EventBus.js +++ b/src/EventBus.js @@ -215,13 +215,15 @@ emit: function (type) { // console.log("emit arguments:",arguments); - type = processMultiTypes.call(this, type, this.emit, slice(arguments)); + var args = slice(arguments); + type = processMultiTypes.call(this, type, this.emit, args); if (type == this)return this; var event = { - type: type + type: type, + target: args.length > 1 ? args[1] : {}//compatibility with older versions }; - var args = [event].concat(slice(arguments, 1)); + args = [event].concat(slice(arguments, 1)); // console.log("emit arguments:",arguments," listener arguments:",args); var listeners = [].concat(typeof this.listeners[type] == "undefined" ? [] : this.listeners[type]); @@ -276,7 +278,7 @@ EventBusClass.prototype.bind = EventBusClass.prototype.addEventListener = EventBusClass.prototype.on; EventBusClass.prototype.unbind = EventBusClass.prototype.removeEventListener = EventBusClass.prototype.off; EventBusClass.prototype.trigger = EventBusClass.prototype.dispatch = EventBusClass.prototype.emit; - EventBusClass.prototype.hasEventListener = EventBusClass.prototype.has; + EventBusClass.prototype.hasEventListener = EventBusClass.prototype.has; var EventBus = new EventBusClass(); return EventBus; From b38d6d1b6b521079ae3f5d14ba179663b36ee66f Mon Sep 17 00:00:00 2001 From: tony_shen Date: Wed, 14 Dec 2016 14:38:42 +0800 Subject: [PATCH 03/20] repair EventBus.once lose any parameters. Event object add getArg function. --- lib/eventbus.min.js | 2 +- src/EventBus.js | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/eventbus.min.js b/lib/eventbus.min.js index 3d6aa60..09611c0 100644 --- a/lib/eventbus.min.js +++ b/lib/eventbus.min.js @@ -1 +1 @@ -(function(_1,_2){if(typeof exports==="object"&&typeof module==="object"){module.exports=_2();}else{if(typeof define==="function"&&define.amd){define("EventBus",[],_2);}else{if(typeof exports==="object"){exports["EventBus"]=_2();}else{_1["EventBus"]=_2();}}}})(this,function(){function _3(_4,_5){_4=_4||[];var _6={stop:function(_7){this.isStopped=true;this.result=_7;}};for(var i in _4){_5(i,_4[i],_4,_6);if(_6.isStopped){break;}}if(_6.isStopped){return _6.result;}};function _8(_9,_a,_b){if(_a>_9.length){return [];}return [].slice.call(_9,_a==undefined?0:_a,_b==undefined?_9.length:_b)||[];};function _c(_d,_e,_f){if(typeof _d=="string"||_d instanceof Array){var _10=_d;if(typeof _d=="string"){_10=_d.trim().split(/\s|,/);}if(_10.length>1){var _11=this;_3(_10,function(_12,_13){_f[0]=_13;_e.apply(_11,_f);});return _11;}else{_d=_10[0];}}return _d;};var _14={};_14=function(){this.listeners={};this.regexListeners=[];};_14.prototype={on:function(_15,_16,_17){_15=_c.call(this,_15,this.on,_8(arguments));if(_15==this){return this;}var _18=_15 instanceof RegExp;var _19=_18?_15.toString():_15;var _1a=_8(arguments,3);var _1b={scope:_17||{},callback:_16,args:_1a,regExp:_15,eventType:_19};if(!_18){if(typeof this.listeners[_19]!="undefined"){this.listeners[_19].push(_1b);}else{this.listeners[_19]=[_1b];}}else{this.regexListeners.push(_1b);}return this;},once:function(_1c,_1d,_1e){var bus=this;var _1f=function(_20){_1d.apply(this,_8(arguments));bus.off(_1c,_1f,_1e);};return bus.on(_1c,_1f,_1e);},off:function(_21,_22,_23){_21=_c.call(this,_21,this.off,[undefined,_22,_23]);if(_21==this){return this;}var _24=_21 instanceof RegExp;var _25=_24?_21.toString():_21;var _26=[];if(typeof _22=="object"){_23=_22;_22=undefined;}var _27=_22==undefined;var _28=_23==undefined;function _29(_2a){return (_27?true:_2a.callback==_22)&&(_28?true:_2a.scope==_23);};if(!_24){if(typeof this.listeners[_25]!="undefined"){if(!(_27&&_28)){_3(this.listeners[_25],function(i,_2b){if(!_29(_2b)){_26.push(_2b);}else{}});}this.listeners[_25]=_26;}}else{_3(this.regexListeners,function(_2c,_2d){if(!(_2d.eventType==_25&&_29(_2d))){_26.push(_2d);}else{}});this.regexListeners=_26;}return this;},has:function(_2e,_2f,_30){var _31=_2e instanceof RegExp;var _32=_31?_2e.toString():_2e;var _33=[].concat(this.listeners[_32]);if(typeof _2f=="object"){_30=_2f;_2f=undefined;}if(_33.length>0&&!_31){var _34=_33.length;if(_2f===undefined&&_30===undefined){return _34>0;}var _35=_3(_33,function(_36,_37,_38,_39){if((_30?_37.scope==_30:true)&&(_2f?_37.callback==_2f:true)){_39.stop(true);}});if(_35){return true;}}else{if(_31){_33=[].concat(this.regexListeners);var _35=_3(_33,function(_3a,_3b,_3c,_3d){if(_3b.regExp.toString()==_32&&(_30?_3b.scope==_30:true)&&(_2f?_3b.callback==_2f:true)){_3d.stop(true);}});if(_35){return true;}}}return false;},emit:function(_3e){var _3f=_8(arguments);_3e=_c.call(this,_3e,this.emit,_3f);if(_3e==this){return this;}var _40={type:_3e,target:_3f.length>1?_3f[1]:{}};_3f=[_40].concat(_8(arguments,1));var _41=[].concat(typeof this.listeners[_3e]=="undefined"?[]:this.listeners[_3e]);function _42(_43){var _44=false;_40.stop=function(){_44=true;};_3(_43,function(_45,_46,_47,_48){if(_46&&_46.callback){var _49=[].concat(_3f);_40.args=[].concat(_46.args);_46.callback.apply(_46.scope,_49);if(_44){_48.stop();}}});};var _4a=[].concat(this.regexListeners);_3(_4a,function(i,_4b){if(_4b.regExp.test(_3e)){_41.push(_4b);}});_42(_41);return this;},getEvents:function(){var str="";for(var _4c in this.listeners){var _4d=this.listeners[_4c].length;for(var i=0;i<_4d;i++){var _4e=this.listeners[_4c][i];str+=_4e.scope&&_4e.scope.className?_4e.scope.className:"anonymous";str+=" listen for '"+_4c+"'\n";}}_3([].concat(this.regexListeners),function(_4f,_50){str+=_50.scope&&_50.scope.className?_50.scope.className:"anonymous";str+=" listen for '"+_50.eventType+"'\n";});return str;}};_14.prototype.bind=_14.prototype.addEventListener=_14.prototype.on;_14.prototype.unbind=_14.prototype.removeEventListener=_14.prototype.off;_14.prototype.trigger=_14.prototype.dispatch=_14.prototype.emit;_14.prototype.hasEventListener=_14.prototype.has;var _51=new _14();return _51;}); \ No newline at end of file +(function(_1,_2){if(typeof exports==="object"&&typeof module==="object"){module.exports=_2();}else{if(typeof define==="function"&&define.amd){define("EventBus",[],_2);}else{if(typeof exports==="object"){exports["EventBus"]=_2();}else{_1["EventBus"]=_2();}}}})(this,function(){function _3(_4,_5){_4=_4||[];var _6={stop:function(_7){this.isStopped=true;this.result=_7;}};for(var i in _4){_5(i,_4[i],_4,_6);if(_6.isStopped){break;}}if(_6.isStopped){return _6.result;}};function _8(_9,_a,_b){if(_a>_9.length){return [];}return [].slice.call(_9,_a==undefined?0:_a,_b==undefined?_9.length:_b)||[];};function _c(_d,_e,_f){if(typeof _d=="string"||_d instanceof Array){var _10=_d;if(typeof _d=="string"){_10=_d.trim().split(/\s|,/);}if(_10.length>1){var _11=this;_3(_10,function(_12,_13){_f[0]=_13;_e.apply(_11,_f);});return _11;}else{_d=_10[0];}}return _d;};var _14={};_14=function(){this.listeners={};this.regexListeners=[];};_14.prototype={on:function(_15,_16,_17){_15=_c.call(this,_15,this.on,_8(arguments));if(_15==this){return this;}var _18=_15 instanceof RegExp;var _19=_18?_15.toString():_15;var _1a=_8(arguments);var _1b={scope:_17||{},callback:_16,args:_1a,regExp:_15,eventType:_19};if(!_18){if(typeof this.listeners[_19]!="undefined"){this.listeners[_19].push(_1b);}else{this.listeners[_19]=[_1b];}}else{this.regexListeners.push(_1b);}return this;},once:function(_1c,_1d,_1e){var bus=this;var _1f=function(_20){_1d.apply(this,_8(arguments));bus.off(_1c,_1f,_1e);};var _21=_8(arguments);_21[1]=_1f;return bus.on.apply(bus,_21);},off:function(_22,_23,_24){_22=_c.call(this,_22,this.off,[undefined,_23,_24]);if(_22==this){return this;}var _25=_22 instanceof RegExp;var _26=_25?_22.toString():_22;var _27=[];if(typeof _23=="object"){_24=_23;_23=undefined;}var _28=_23==undefined;var _29=_24==undefined;function _2a(_2b){return (_28?true:_2b.callback==_23)&&(_29?true:_2b.scope==_24);};if(!_25){if(typeof this.listeners[_26]!="undefined"){if(!(_28&&_29)){_3(this.listeners[_26],function(i,_2c){if(!_2a(_2c)){_27.push(_2c);}else{}});}this.listeners[_26]=_27;}}else{_3(this.regexListeners,function(_2d,_2e){if(!(_2e.eventType==_26&&_2a(_2e))){_27.push(_2e);}else{}});this.regexListeners=_27;}return this;},has:function(_2f,_30,_31){var _32=_2f instanceof RegExp;var _33=_32?_2f.toString():_2f;var _34=[].concat(this.listeners[_33]);if(typeof _30=="object"){_31=_30;_30=undefined;}if(_34.length>0&&!_32){var _35=_34.length;if(_30===undefined&&_31===undefined){return _35>0;}var _36=_3(_34,function(_37,_38,_39,_3a){if((_31?_38.scope==_31:true)&&(_30?_38.callback==_30:true)){_3a.stop(true);}});if(_36){return true;}}else{if(_32){_34=[].concat(this.regexListeners);var _36=_3(_34,function(_3b,_3c,_3d,_3e){if(_3c.regExp.toString()==_33&&(_31?_3c.scope==_31:true)&&(_30?_3c.callback==_30:true)){_3e.stop(true);}});if(_36){return true;}}}return false;},emit:function(_3f){var _40=_8(arguments);_3f=_c.call(this,_3f,this.emit,_40);if(_3f==this){return this;}var _41={type:_3f,target:_40.length>1?_40[1]:{}};_40=[_41].concat(_8(arguments,1));var _42=[].concat(typeof this.listeners[_3f]=="undefined"?[]:this.listeners[_3f]);function _43(_44){var _45=false;_41.stop=function(){_45=true;};_41.getArg=function(_46){if(_41.args==undefined||!_41.args instanceof Array||_41.args.length-1<_46){return undefined;}return _41.args[_46];};_3(_44,function(_47,_48,_49,_4a){if(_48&&_48.callback){var _4b=[].concat(_40);_41.args=[].concat(_48.args);_48.callback.apply(_48.scope,_4b);if(_45){_4a.stop();}}});};var _4c=[].concat(this.regexListeners);_3(_4c,function(i,_4d){if(_4d.regExp.test(_3f)){_42.push(_4d);}});_43(_42);return this;},getEvents:function(){var str="";for(var _4e in this.listeners){var _4f=this.listeners[_4e].length;for(var i=0;i<_4f;i++){var _50=this.listeners[_4e][i];str+=_50.scope&&_50.scope.className?_50.scope.className:"anonymous";str+=" listen for '"+_4e+"'\n";}}_3([].concat(this.regexListeners),function(_51,_52){str+=_52.scope&&_52.scope.className?_52.scope.className:"anonymous";str+=" listen for '"+_52.eventType+"'\n";});return str;}};_14.prototype.bind=_14.prototype.addEventListener=_14.prototype.on;_14.prototype.unbind=_14.prototype.removeEventListener=_14.prototype.off;_14.prototype.trigger=_14.prototype.dispatch=_14.prototype.emit;_14.prototype.hasEventListener=_14.prototype.has;var _53=new _14();return _53;}); \ No newline at end of file diff --git a/src/EventBus.js b/src/EventBus.js index 1e5fe75..9551ef2 100644 --- a/src/EventBus.js +++ b/src/EventBus.js @@ -72,7 +72,8 @@ var isRegExpType = type instanceof RegExp; var eventType = isRegExpType ? type.toString() : type; - var args = slice(arguments, 3); + var args = slice(arguments); + // console.log("listener args is ",args); var listener = {//create listener stub scope: scope || {}, callback: callback, @@ -104,7 +105,9 @@ callback.apply(this, slice(arguments)); bus.off(type, proxyCallback, scope); }; - return bus.on(type, proxyCallback, scope); + var args = slice(arguments); + args[1] = proxyCallback; + return bus.on.apply(bus, args); }, /** * EventBus.off("click"); //remove all click listeners @@ -232,6 +235,10 @@ event.stop = function () { isStop = true; }; + event.getArg = function (index) { + if (event.args == undefined || !event.args instanceof Array || event.args.length - 1 < index)return undefined; + return event.args[index]; + }; iterator(listeners, function (index, listener, listeners, iterator) { if (listener && listener.callback) { var listenerArgs = [].concat(args); @@ -282,4 +289,4 @@ var EventBus = new EventBusClass(); return EventBus; -}); +}); \ No newline at end of file From 1a049f837e843c0d89f89b8eed79fe13a9fe1ba1 Mon Sep 17 00:00:00 2001 From: tony_shen Date: Wed, 14 Dec 2016 14:39:32 +0800 Subject: [PATCH 04/20] add Producer/Consumer use case --- example/node/cs-test.js | 76 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 example/node/cs-test.js diff --git a/example/node/cs-test.js b/example/node/cs-test.js new file mode 100644 index 0000000..e8be102 --- /dev/null +++ b/example/node/cs-test.js @@ -0,0 +1,76 @@ +/** + * Created by bona on 2016/12/14. + */ +var EventBus = require('../../lib/eventbus.min'); + +var Order = function (id, name, consumer) { + this.id = id; + this.name = name; + this.consumer = consumer; +}; + +var Producer = function (order) { + this.order = order; +}; + +Producer.prototype = { + + make: function () { + EventBus.emit("make/" + this.order.consumer, this.order); + }, + package: function () { + EventBus.emit("package/" + this.order.consumer, this.order); + }, + send: function () { + EventBus.emit("send/" + this.order.consumer, this.order); + } +}; + +var Consumer = function (name, once) { + this.name = name; + this.init(once); +}; + +Consumer.prototype = { + onMake: function (event, thing) { + console.log(this.name, "'s order is making. order id=", thing.id, " order name:" + thing.name); + }, + onPackage: function (event, thing) { + console.log(this.name, "'s order is packaging. order id=", thing.id, " order name:" + thing.name); + }, + onReceive: function (event, thing) { + console.log(this.name, "'s order is finished. order id=", thing.id, " order name:" + thing.name); + }, + + init: function (once) { + var method = "on"; + if (once) method = 'once'; + EventBus[method]("make/" + this.name, this.onMake, this); + EventBus[method]("package/" + this.name, this.onPackage, this); + EventBus[method]("send/" + this.name, this.onReceive, this); + } + +}; + +EventBus.on(/\w*\/\w*/, monitor, {name: "kerry"}, /make\/\w*/); + +EventBus.on(/\w*\/\w*/, monitor, {name: "peter"}, /package\/\w*/); + +function monitor(event, order) { + var state = event.getArg(3); + if (state.test(event.type) && order.consumer == this.name) { + console.log(event.type, " is dispatched! "); + } +} + +new Consumer("peter"); +new Consumer("kerry"); +new Consumer("bona", true); + +for (var i = 0; i < 4; i++) { + var order = new Order("order-" + (i + 1), "wa-li robot", ["peter", "kerry", "bona", "bona"][i]); + var maker = new Producer(order); + maker.make(); + maker.package(); + maker.send(); +} \ No newline at end of file From bcb81d1c19ab68a74ebb81654cc855d610cfca44 Mon Sep 17 00:00:00 2001 From: tony_shen Date: Fri, 16 Dec 2016 22:46:10 +0800 Subject: [PATCH 05/20] modify .gitignore --- .gitignore | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ab05030..75981ef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,77 @@ node_modules -*.log \ No newline at end of file +*.log + +### SublimeText template +# cache files for sublime text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# workspace files are user-specific +*.sublime-workspace + +# project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using SublimeText +# *.sublime-project + +# sftp configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings +### Windows template +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +.idea/ + + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + From dc0b4a7b24b99a565f32b6304994c0975d64d110 Mon Sep 17 00:00:00 2001 From: tony_shen Date: Fri, 16 Dec 2016 22:50:45 +0800 Subject: [PATCH 06/20] add EventBus.redirect feature --- example/node/cs-test.js | 22 +++++++++----- lib/eventbus.min.js | 2 +- src/EventBus.js | 64 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 78 insertions(+), 10 deletions(-) diff --git a/example/node/cs-test.js b/example/node/cs-test.js index e8be102..783b7fd 100644 --- a/example/node/cs-test.js +++ b/example/node/cs-test.js @@ -32,14 +32,14 @@ var Consumer = function (name, once) { }; Consumer.prototype = { - onMake: function (event, thing) { - console.log(this.name, "'s order is making. order id=", thing.id, " order name:" + thing.name); + onMake: function (event, order) { + console.log(this.name, "'s order is making. order id=", order.id, " order name:" + order.name); }, - onPackage: function (event, thing) { - console.log(this.name, "'s order is packaging. order id=", thing.id, " order name:" + thing.name); + onPackage: function (event, order) { + console.log(this.name, "'s order is packaging. order id=", order.id, " order name:" + order.name); }, - onReceive: function (event, thing) { - console.log(this.name, "'s order is finished. order id=", thing.id, " order name:" + thing.name); + onReceive: function (event, order) { + console.log(this.name, "'s order is received. order id=", order.id, " order name:" + order.name); }, init: function (once) { @@ -47,7 +47,7 @@ Consumer.prototype = { if (once) method = 'once'; EventBus[method]("make/" + this.name, this.onMake, this); EventBus[method]("package/" + this.name, this.onPackage, this); - EventBus[method]("send/" + this.name, this.onReceive, this); + EventBus[method]("receive/" + this.name, this.onReceive, this); } }; @@ -56,6 +56,10 @@ EventBus.on(/\w*\/\w*/, monitor, {name: "kerry"}, /make\/\w*/); EventBus.on(/\w*\/\w*/, monitor, {name: "peter"}, /package\/\w*/); +EventBus.on("make package receive",function (event,order) { + console.log(order.id,/*" ",order.name,*/" is ",event.type); +}); + function monitor(event, order) { var state = event.getArg(3); if (state.test(event.type) && order.consumer == this.name) { @@ -63,6 +67,10 @@ function monitor(event, order) { } } +EventBus.redirect(/(\w*)\/(\w*)/,function(event){return /(\w*)\/(\w*)/.exec(event.type)[1];}); + +EventBus.redirect(/send\/(\w*)/,function(event){return "receive/"+/(\w*)\/(\w*)/.exec(event.type)[2];}); + new Consumer("peter"); new Consumer("kerry"); new Consumer("bona", true); diff --git a/lib/eventbus.min.js b/lib/eventbus.min.js index 09611c0..b0ef6ff 100644 --- a/lib/eventbus.min.js +++ b/lib/eventbus.min.js @@ -1 +1 @@ -(function(_1,_2){if(typeof exports==="object"&&typeof module==="object"){module.exports=_2();}else{if(typeof define==="function"&&define.amd){define("EventBus",[],_2);}else{if(typeof exports==="object"){exports["EventBus"]=_2();}else{_1["EventBus"]=_2();}}}})(this,function(){function _3(_4,_5){_4=_4||[];var _6={stop:function(_7){this.isStopped=true;this.result=_7;}};for(var i in _4){_5(i,_4[i],_4,_6);if(_6.isStopped){break;}}if(_6.isStopped){return _6.result;}};function _8(_9,_a,_b){if(_a>_9.length){return [];}return [].slice.call(_9,_a==undefined?0:_a,_b==undefined?_9.length:_b)||[];};function _c(_d,_e,_f){if(typeof _d=="string"||_d instanceof Array){var _10=_d;if(typeof _d=="string"){_10=_d.trim().split(/\s|,/);}if(_10.length>1){var _11=this;_3(_10,function(_12,_13){_f[0]=_13;_e.apply(_11,_f);});return _11;}else{_d=_10[0];}}return _d;};var _14={};_14=function(){this.listeners={};this.regexListeners=[];};_14.prototype={on:function(_15,_16,_17){_15=_c.call(this,_15,this.on,_8(arguments));if(_15==this){return this;}var _18=_15 instanceof RegExp;var _19=_18?_15.toString():_15;var _1a=_8(arguments);var _1b={scope:_17||{},callback:_16,args:_1a,regExp:_15,eventType:_19};if(!_18){if(typeof this.listeners[_19]!="undefined"){this.listeners[_19].push(_1b);}else{this.listeners[_19]=[_1b];}}else{this.regexListeners.push(_1b);}return this;},once:function(_1c,_1d,_1e){var bus=this;var _1f=function(_20){_1d.apply(this,_8(arguments));bus.off(_1c,_1f,_1e);};var _21=_8(arguments);_21[1]=_1f;return bus.on.apply(bus,_21);},off:function(_22,_23,_24){_22=_c.call(this,_22,this.off,[undefined,_23,_24]);if(_22==this){return this;}var _25=_22 instanceof RegExp;var _26=_25?_22.toString():_22;var _27=[];if(typeof _23=="object"){_24=_23;_23=undefined;}var _28=_23==undefined;var _29=_24==undefined;function _2a(_2b){return (_28?true:_2b.callback==_23)&&(_29?true:_2b.scope==_24);};if(!_25){if(typeof this.listeners[_26]!="undefined"){if(!(_28&&_29)){_3(this.listeners[_26],function(i,_2c){if(!_2a(_2c)){_27.push(_2c);}else{}});}this.listeners[_26]=_27;}}else{_3(this.regexListeners,function(_2d,_2e){if(!(_2e.eventType==_26&&_2a(_2e))){_27.push(_2e);}else{}});this.regexListeners=_27;}return this;},has:function(_2f,_30,_31){var _32=_2f instanceof RegExp;var _33=_32?_2f.toString():_2f;var _34=[].concat(this.listeners[_33]);if(typeof _30=="object"){_31=_30;_30=undefined;}if(_34.length>0&&!_32){var _35=_34.length;if(_30===undefined&&_31===undefined){return _35>0;}var _36=_3(_34,function(_37,_38,_39,_3a){if((_31?_38.scope==_31:true)&&(_30?_38.callback==_30:true)){_3a.stop(true);}});if(_36){return true;}}else{if(_32){_34=[].concat(this.regexListeners);var _36=_3(_34,function(_3b,_3c,_3d,_3e){if(_3c.regExp.toString()==_33&&(_31?_3c.scope==_31:true)&&(_30?_3c.callback==_30:true)){_3e.stop(true);}});if(_36){return true;}}}return false;},emit:function(_3f){var _40=_8(arguments);_3f=_c.call(this,_3f,this.emit,_40);if(_3f==this){return this;}var _41={type:_3f,target:_40.length>1?_40[1]:{}};_40=[_41].concat(_8(arguments,1));var _42=[].concat(typeof this.listeners[_3f]=="undefined"?[]:this.listeners[_3f]);function _43(_44){var _45=false;_41.stop=function(){_45=true;};_41.getArg=function(_46){if(_41.args==undefined||!_41.args instanceof Array||_41.args.length-1<_46){return undefined;}return _41.args[_46];};_3(_44,function(_47,_48,_49,_4a){if(_48&&_48.callback){var _4b=[].concat(_40);_41.args=[].concat(_48.args);_48.callback.apply(_48.scope,_4b);if(_45){_4a.stop();}}});};var _4c=[].concat(this.regexListeners);_3(_4c,function(i,_4d){if(_4d.regExp.test(_3f)){_42.push(_4d);}});_43(_42);return this;},getEvents:function(){var str="";for(var _4e in this.listeners){var _4f=this.listeners[_4e].length;for(var i=0;i<_4f;i++){var _50=this.listeners[_4e][i];str+=_50.scope&&_50.scope.className?_50.scope.className:"anonymous";str+=" listen for '"+_4e+"'\n";}}_3([].concat(this.regexListeners),function(_51,_52){str+=_52.scope&&_52.scope.className?_52.scope.className:"anonymous";str+=" listen for '"+_52.eventType+"'\n";});return str;}};_14.prototype.bind=_14.prototype.addEventListener=_14.prototype.on;_14.prototype.unbind=_14.prototype.removeEventListener=_14.prototype.off;_14.prototype.trigger=_14.prototype.dispatch=_14.prototype.emit;_14.prototype.hasEventListener=_14.prototype.has;var _53=new _14();return _53;}); \ No newline at end of file +(function(a,b){if(typeof exports==="object"&&typeof module==="object"){module.exports=b()}else{if(typeof define==="function"&&define.amd){define("EventBus",[],b)}else{if(typeof exports==="object"){exports.EventBus=b()}else{a.EventBus=b()}}}})(this,function(){function d(k,j){k=k||[];var h={stop:function(i){this.isStopped=true;this.result=i}};for(var g in k){j(g,k[g],k,h);if(h.isStopped){break}}if(h.isStopped){return h.result}}function f(i,h,g){if(h>i.length){return[]}return[].slice.call(i,h==undefined?0:h,g==undefined?i.length:g)||[]}function b(i,k,g){if(typeof i=="string"||i instanceof Array){var h=i;if(typeof i=="string"){h=i.trim().split(/\s|,/)}if(h.length>1){var j=this;d(h,function(l,m){g[0]=m;k.apply(j,g)});return j}else{i=h[0]}}return i}var c=(function(){var g=1000;return function(){return ++g}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(j,m,i){j=b.call(this,j,this.on,f(arguments));if(j==this){return this}var l=j instanceof RegExp;var h=l?j.toString():j;var g=f(arguments);var k={id:c(),scope:i||{},callback:m,args:g,regExp:j,eventType:h};if(!l){if(typeof this.listeners[h]!="undefined"){this.listeners[h].push(k)}else{this.listeners[h]=[k]}}else{this.regexListeners.push(k)}return this},once:function(k,l,j){var g=this;var h=function(m){l.apply(this,f(arguments));g.off(k,h,j)};var i=f(arguments);i[1]=h;return g.on.apply(g,i)},off:function(k,l,o){k=b.call(this,k,this.off,[undefined,l,o]);if(k==this){return this}var i=k instanceof RegExp;var h=i?k.toString():k;var m=[];if(typeof l=="object"){o=l;l=undefined}var j=l==undefined;var n=o==undefined;function g(p){return(j?true:p.callback==l)&&(n?true:p.scope==o)}if(!i){if(typeof this.listeners[h]!="undefined"){if(!(j&&n)){d(this.listeners[h],function(p,q){if(!g(q)){m.push(q)}else{}})}this.listeners[h]=m}}else{d(this.regexListeners,function(p,q){if(!(q.eventType==h&&g(q))){m.push(q)}else{}});this.regexListeners=m}return this},redirect:function(h,j,k){var i=this.redirectScope=this.redirectScope||{};var g=this;if(h==j){return g}this.on(h,(function(o,p,m){if(p==undefined){p=function(){return true}}if(p instanceof RegExp){var n=p;p=function(q){return n.test(q.type)}}if(typeof p=="function"){var l=[];return function(r){var q=f(arguments);if(p.apply(this,q)){q[0]=typeof o=="function"?o.apply(this,q):o;if(l.indexOf(m)<0&&q[0]!=r.type){l.push(m);g.emit.apply(g,q);l.pop()}else{console.log("==>origin:",h.toString()," ==>endpoint:",o.toString()," redirect is looping! this event is lost.")}}}}else{return function(q){console.log("redirect condition must set function or RegExp!")}}})(j,k,c()),i);return g},has:function(k,n,j){var m=k instanceof RegExp;var h=m?k.toString():k;var i=[].concat(this.listeners[h]);if(typeof n=="object"){j=n;n=undefined}if(i.length>0&&!m){var l=i.length;if(n===undefined&&j===undefined){return l>0}var g=d(i,function(o,q,r,p){if((j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}else{if(m){i=[].concat(this.regexListeners);var g=d(i,function(o,q,r,p){if(q.regExp.toString()==h&&(j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}}return false},emit:function(j){var g=f(arguments);j=b.call(this,j,this.emit,g);if(j==this){return this}var k={type:j,target:g.length>1?g[1]:{}};g=[k].concat(f(arguments,1));var i=[].concat(typeof this.listeners[j]=="undefined"?[]:this.listeners[j]);function l(n){var m=false;k.stop=function(){m=true};k.getArg=function(o){if(k.args==undefined||!k.args instanceof Array||k.args.length-1origin:", origin.toString(), + " ==>endpoint:", endpoint.toString(), + " redirect is looping! this event is lost."); + } + } + } + } + else { + return function (event) { + console.log("redirect condition must set function or RegExp!") + } + } + })(endpoint, condition, nextId()), scope); + return bus; + }, /** * EventBus.has("click") * EventBus.has("click",buttonScope); @@ -277,7 +338,6 @@ str += listener.scope && listener.scope.className ? listener.scope.className : "anonymous"; str += " listen for '" + listener.eventType + "'\n"; }); - return str; } }; From c983f7d01450ac767732df1bb937952c735616c4 Mon Sep 17 00:00:00 2001 From: tony_shen Date: Sat, 17 Dec 2016 11:56:27 +0800 Subject: [PATCH 07/20] EventBus.redirect feature support pre-processor --- example/node/cs-test.js | 61 +++++++++++++++++++++++--- lib/eventbus.min.js | 2 +- src/EventBus.js | 95 +++++++++++++++++++++++++++++++++-------- 3 files changed, 134 insertions(+), 24 deletions(-) diff --git a/example/node/cs-test.js b/example/node/cs-test.js index 783b7fd..8ed214a 100644 --- a/example/node/cs-test.js +++ b/example/node/cs-test.js @@ -3,6 +3,8 @@ */ var EventBus = require('../../lib/eventbus.min'); +EventBus.DEFAULT.SHOW_LOG = false; + var Order = function (id, name, consumer) { this.id = id; this.name = name; @@ -16,13 +18,19 @@ var Producer = function (order) { Producer.prototype = { make: function () { + console.log("============================", "start make ", this.order.id, "=============================="); EventBus.emit("make/" + this.order.consumer, this.order); + console.log("============================", "end make ", this.order.id, "=============================="); }, package: function () { + console.log("============================", "start package ", this.order.id, "=============================="); EventBus.emit("package/" + this.order.consumer, this.order); + console.log("============================", "end package ", this.order.id, "=============================="); }, send: function () { + console.log("============================", "start send ", this.order.id, "=============================="); EventBus.emit("send/" + this.order.consumer, this.order); + console.log("============================", "end send ", this.order.id, "=============================="); } }; @@ -39,7 +47,7 @@ Consumer.prototype = { console.log(this.name, "'s order is packaging. order id=", order.id, " order name:" + order.name); }, onReceive: function (event, order) { - console.log(this.name, "'s order is received. order id=", order.id, " order name:" + order.name); + console.log(this.name, "is ready to receive order goods. order id=", order.id, " order name:" + order.name); }, init: function (once) { @@ -52,12 +60,16 @@ Consumer.prototype = { }; +EventBus.on(/QC\/\w*/, function (event, order) { + console.log(order.id, " quality testing"); +}); + EventBus.on(/\w*\/\w*/, monitor, {name: "kerry"}, /make\/\w*/); EventBus.on(/\w*\/\w*/, monitor, {name: "peter"}, /package\/\w*/); -EventBus.on("make package receive",function (event,order) { - console.log(order.id,/*" ",order.name,*/" is ",event.type); +EventBus.on("make package receive", function (event, order) { + console.log(order.id, /*" ",order.name,*/" state is ", event.type); }); function monitor(event, order) { @@ -67,9 +79,44 @@ function monitor(event, order) { } } -EventBus.redirect(/(\w*)\/(\w*)/,function(event){return /(\w*)\/(\w*)/.exec(event.type)[1];}); +EventBus.redirect(/(\w*)\/(\w*)/, function (event) { + return /(\w*)\/(\w*)/.exec(event.type)[1]; +}); -EventBus.redirect(/send\/(\w*)/,function(event){return "receive/"+/(\w*)\/(\w*)/.exec(event.type)[2];}); +EventBus.redirect(/send\/(\w*)/, function (event) {//map one to one + return "receive/" + /(\w*)\/(\w*)/.exec(event.type)[2]; +}); + +EventBus.redirect(/send\/(\w*)/, function (event) { //map one to more + var consumer = /(\w*)\/(\w*)/.exec(event.type)[2]; + return ["trans/" + consumer, "print/" + consumer, "QC/" + consumer]; +}); + +//map more to one +EventBus.redirect({ + origin: [/QC\/\w*/], + endpoint: "qc-report-collect", + processor: function (event, order) { + console.log("redirect processor for ", event.id, "==>", + "origin:", event.getOriginType(), " endpoint:", event.getEndpoint()); + + if (order.consumer == "bona") event.setEmitArgs([order, "passed"]); + } +}); + +var qcReport = { + orders: [], + passed: [], + print: function () { + console.log("qc checked order count :", this.orders.length); + console.log("qc passed order count :", this.passed.length); + } +}; + +EventBus.on("qc-report-collect", function (event, order, checkState) { + this.orders.push(order); + if (checkState == "passed") this.passed.push(order); +}, qcReport); new Consumer("peter"); new Consumer("kerry"); @@ -81,4 +128,6 @@ for (var i = 0; i < 4; i++) { maker.make(); maker.package(); maker.send(); -} \ No newline at end of file +} + +qcReport.print(); \ No newline at end of file diff --git a/lib/eventbus.min.js b/lib/eventbus.min.js index b0ef6ff..a12d1c6 100644 --- a/lib/eventbus.min.js +++ b/lib/eventbus.min.js @@ -1 +1 @@ -(function(a,b){if(typeof exports==="object"&&typeof module==="object"){module.exports=b()}else{if(typeof define==="function"&&define.amd){define("EventBus",[],b)}else{if(typeof exports==="object"){exports.EventBus=b()}else{a.EventBus=b()}}}})(this,function(){function d(k,j){k=k||[];var h={stop:function(i){this.isStopped=true;this.result=i}};for(var g in k){j(g,k[g],k,h);if(h.isStopped){break}}if(h.isStopped){return h.result}}function f(i,h,g){if(h>i.length){return[]}return[].slice.call(i,h==undefined?0:h,g==undefined?i.length:g)||[]}function b(i,k,g){if(typeof i=="string"||i instanceof Array){var h=i;if(typeof i=="string"){h=i.trim().split(/\s|,/)}if(h.length>1){var j=this;d(h,function(l,m){g[0]=m;k.apply(j,g)});return j}else{i=h[0]}}return i}var c=(function(){var g=1000;return function(){return ++g}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(j,m,i){j=b.call(this,j,this.on,f(arguments));if(j==this){return this}var l=j instanceof RegExp;var h=l?j.toString():j;var g=f(arguments);var k={id:c(),scope:i||{},callback:m,args:g,regExp:j,eventType:h};if(!l){if(typeof this.listeners[h]!="undefined"){this.listeners[h].push(k)}else{this.listeners[h]=[k]}}else{this.regexListeners.push(k)}return this},once:function(k,l,j){var g=this;var h=function(m){l.apply(this,f(arguments));g.off(k,h,j)};var i=f(arguments);i[1]=h;return g.on.apply(g,i)},off:function(k,l,o){k=b.call(this,k,this.off,[undefined,l,o]);if(k==this){return this}var i=k instanceof RegExp;var h=i?k.toString():k;var m=[];if(typeof l=="object"){o=l;l=undefined}var j=l==undefined;var n=o==undefined;function g(p){return(j?true:p.callback==l)&&(n?true:p.scope==o)}if(!i){if(typeof this.listeners[h]!="undefined"){if(!(j&&n)){d(this.listeners[h],function(p,q){if(!g(q)){m.push(q)}else{}})}this.listeners[h]=m}}else{d(this.regexListeners,function(p,q){if(!(q.eventType==h&&g(q))){m.push(q)}else{}});this.regexListeners=m}return this},redirect:function(h,j,k){var i=this.redirectScope=this.redirectScope||{};var g=this;if(h==j){return g}this.on(h,(function(o,p,m){if(p==undefined){p=function(){return true}}if(p instanceof RegExp){var n=p;p=function(q){return n.test(q.type)}}if(typeof p=="function"){var l=[];return function(r){var q=f(arguments);if(p.apply(this,q)){q[0]=typeof o=="function"?o.apply(this,q):o;if(l.indexOf(m)<0&&q[0]!=r.type){l.push(m);g.emit.apply(g,q);l.pop()}else{console.log("==>origin:",h.toString()," ==>endpoint:",o.toString()," redirect is looping! this event is lost.")}}}}else{return function(q){console.log("redirect condition must set function or RegExp!")}}})(j,k,c()),i);return g},has:function(k,n,j){var m=k instanceof RegExp;var h=m?k.toString():k;var i=[].concat(this.listeners[h]);if(typeof n=="object"){j=n;n=undefined}if(i.length>0&&!m){var l=i.length;if(n===undefined&&j===undefined){return l>0}var g=d(i,function(o,q,r,p){if((j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}else{if(m){i=[].concat(this.regexListeners);var g=d(i,function(o,q,r,p){if(q.regExp.toString()==h&&(j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}}return false},emit:function(j){var g=f(arguments);j=b.call(this,j,this.emit,g);if(j==this){return this}var k={type:j,target:g.length>1?g[1]:{}};g=[k].concat(f(arguments,1));var i=[].concat(typeof this.listeners[j]=="undefined"?[]:this.listeners[j]);function l(n){var m=false;k.stop=function(){m=true};k.getArg=function(o){if(k.args==undefined||!k.args instanceof Array||k.args.length-1i.length){return[]}return[].slice.call(i,h==undefined?0:h,g==undefined?i.length:g)||[]}function b(i,k,g){if(typeof i=="string"||i instanceof Array){var h=i;if(typeof i=="string"){h=i.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(h.length>1){var j=this;d(h,function(l,m){g[0]=m;k.apply(j,g)});return j}else{i=h[0]}}return i}var c=(function(){var g=1000;return function(){return ++g}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(j,m,i){j=b.call(this,j,this.on,f(arguments));if(j==this){return this}var l=j instanceof RegExp;var h=l?j.toString():j;var g=f(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",g)}var k={id:c(),scope:i||{},callback:m,args:g,regExp:j,eventType:h};if(!l){if(typeof this.listeners[h]!="undefined"){this.listeners[h].push(k)}else{this.listeners[h]=[k]}}else{this.regexListeners.push(k)}return this},once:function(k,l,j){var g=this;var h=function(m){l.apply(this,f(arguments));g.off(k,h,j)};var i=f(arguments);i[1]=h;return g.on.apply(g,i)},off:function(k,l,o){k=b.call(this,k,this.off,[undefined,l,o]);if(k==this){return this}var i=k instanceof RegExp;var h=i?k.toString():k;var m=[];if(typeof l=="object"){o=l;l=undefined}var j=l==undefined;var n=o==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",k," all callback:",j," all scope:",n)}function g(p){return(j?true:p.callback==l)&&(n?true:p.scope==o)}if(!i){if(typeof this.listeners[h]!="undefined"){if(!(j&&n)){d(this.listeners[h],function(p,q){if(!g(q)){m.push(q)}else{}})}this.listeners[h]=m}}else{d(this.regexListeners,function(p,q){if(!(q.eventType==h&&g(q))){m.push(q)}else{}});this.regexListeners=m}return this},redirect:function(h,l,m,k){if(arguments.length==1&&typeof h=="object"){var j=h;h=j.origin;l=j.endpoint;m=j.condition;k=j.processor}var g=this;if(h==undefined||l==undefined||h==l){return g}var i=this.redirectScope=this.redirectScope||{};k=typeof k=="function"?k:function(n){n.setEmitArgs(a.slice(arguments,1))};this.on(h,(function(q,r,o){if(r==undefined){r=function(){return true}}if(r instanceof RegExp){var p=r;r=function(s){return p.test(s.type)}}if(typeof r=="function"){var n=[];return function(u){var s=f(arguments);if(r.apply(i,s)){var t=typeof q=="function"?q.apply(i,s):q;if(n.indexOf(o)<0&&t!=u.type&&t!=undefined){n.push(o);if(typeof t=="string"){t=t.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(!(t instanceof Array)){t=[t]}d(t,function(v,x){if(x!=u.type){var w=f([].concat(s),1);u.setEmitArgs=function(y){w=y};u.getEmitArgs=function(){return[].concat(w)};u.getOriginType=function(){return h};u.getEndpoint=function(){return x};k.apply(i,s);w=(w instanceof Array)?[""].concat(w):[].concat(s);w[0]=x;if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect id:",u.id," origin:",h," ==> endpoint:",x)}g.emit.apply(g,w)}});n.pop()}else{if(e.DEFAULT.SHOW_LOG){console.log("redirect=>origin:",h.toString()," ==>endpoint:",q.toString()," redirect is looping! this event is lost.")}}}}}else{return function(s){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(l,m,c()),i);return g},has:function(k,n,j){var m=k instanceof RegExp;var h=m?k.toString():k;var i=[].concat(this.listeners[h]);if(typeof n=="object"){j=n;n=undefined}if(i.length>0&&!m){var l=i.length;if(n===undefined&&j===undefined){return l>0}var g=d(i,function(o,q,r,p){if((j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}else{if(m){i=[].concat(this.regexListeners);var g=d(i,function(o,q,r,p){if(q.regExp.toString()==h&&(j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}}return false},emit:function(j){var g=f(arguments);j=b.call(this,j,this.emit,g);if(j==this){return this}var k={id:j+"#"+c(),type:j,target:g.length>1?g[1]:{}};g=[k].concat(f(arguments,1));var i=[].concat(typeof this.listeners[j]=="undefined"?[]:this.listeners[j]);function l(n){var m=false;k.stop=function(){m=true};k.getArg=function(o){if(k.args==undefined||!k.args instanceof Array||k.args.length-1event listener call arguments:",r)}k.args=[].concat(s.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",s)}s.callback.apply(s.scope,r);if(m){p.stop()}}})}var h=[].concat(this.regexListeners);d(h,function(m,n){if(n.regExp.test(j)){i.push(n)}});l(i);return this},getEvents:function(){var l="";for(var h in this.listeners){var k=this.listeners[h].length;for(var g=0;g 1) { var that = this; iterator(types, function (index, type) { @@ -81,7 +81,8 @@ var isRegExpType = type instanceof RegExp; var eventType = isRegExpType ? type.toString() : type; var args = slice(arguments); - // console.log("listener args is ",args); + if(EventBusClass.DEFAULT.SHOW_LOG) + console.log("on=>listener args is ",args); var listener = {//create listener stub id: nextId(), scope: scope || {}, @@ -143,7 +144,8 @@ } var allCallback = callback == undefined; var allScope = scope == undefined; - // console.log("off event type:", type, " all callback:", allCallback, " all scope:", allScope); + if(EventBusClass.DEFAULT.SHOW_LOG) + console.log("off=>off event type:", type, " all callback:", allCallback, " all scope:", allScope); // console.log("callback:", callback, " scope:", scope); function isRemove(listener) { return (allCallback ? true : listener.callback == callback) && @@ -180,18 +182,35 @@ * @param origin * @param endpoint * @param condition + * @param processor processor be called before event redirection * @return {EventBusClass} */ - redirect: function (origin, endpoint, condition) { - var scope = this.redirectScope = this.redirectScope || {}; + redirect: function (origin, endpoint, condition, processor) { + //support EventBus.redirect({ + // origin:'click', + // endpoint:'onClick' + // }) + if (arguments.length == 1 && typeof origin == "object") { + var option = origin; + origin = option["origin"]; + endpoint = option["endpoint"]; + condition = option["condition"]; + processor = option["processor"]; + } var bus = this; - if (origin == endpoint)return bus; + if (origin == undefined || endpoint == undefined || origin == endpoint)return bus; + + var scope = this.redirectScope = this.redirectScope || {}; + + processor = typeof processor == "function" ? processor : function (event) { + event.setEmitArgs(EventBus.slice(arguments, 1));//example: set emit endpoint event arguments + }; this.on(origin, (function (endpoint, condition, nextId) { if (condition == undefined) - condition = function () { + condition = function () { //default all origin event to endpoint event return true; }; - if (condition instanceof RegExp) { + if (condition instanceof RegExp) {//support reg exp as condition var exp = condition; condition = function (event) { return exp.test(event.type); @@ -199,17 +218,46 @@ } if (typeof condition == "function") { var stack = []; - return function (event) { + return function (event) {//trigger redirect var args = slice(arguments); - if (condition.apply(this, args)) { - args[0] = typeof endpoint == "function" ? endpoint.apply(this, args) : endpoint; - if (stack.indexOf(nextId) < 0 && args[0] != event.type)//is redirect looping + if (condition.apply(scope, args)) {//trigger condition check + var eventType = typeof endpoint == "function" ? endpoint.apply(scope, args) : endpoint;//dynamic get endpoint + if (stack.indexOf(nextId) < 0 && eventType != event.type && eventType != undefined)//check redirect looping { stack.push(nextId); - bus.emit.apply(bus, args); + if (typeof eventType == "string") eventType = + eventType.trim().split(EventBusClass.DEFAULT.EVENT_TYPE_SPLIT_EXP);//support string split by SPACE,COMMA char + if (!(eventType instanceof Array)) { + eventType = [eventType]; + } + iterator(eventType, function (index, type) {//support endpoint array + if (type != event.type) { + var emitArgs = slice([].concat(args), 1); + event.setEmitArgs = function (args) { + emitArgs = args; + }; + event.getEmitArgs = function () { + return [].concat(emitArgs); + }; + event.getOriginType = function () { + return origin; + }; + event.getEndpoint = function () { + return type; + }; + processor.apply(scope, args); + emitArgs = (emitArgs instanceof Array) ? [""].concat(emitArgs) : [].concat(args); + emitArgs[0] = type; + if(EventBusClass.DEFAULT.SHOW_LOG) + console.log("redirect=>redirect id:", event.id, " origin:", origin, " ==> endpoint:", type); + bus.emit.apply(bus, emitArgs);//dispatch endpoint event} + } + } + ); stack.pop(); } else { - console.log("==>origin:", origin.toString(), + if(EventBusClass.DEFAULT.SHOW_LOG) + console.log("redirect=>origin:", origin.toString(), " ==>endpoint:", endpoint.toString(), " redirect is looping! this event is lost."); } @@ -218,7 +266,8 @@ } else { return function (event) { - console.log("redirect condition must set function or RegExp!") + if(EventBusClass.DEFAULT.SHOW_LOG) + console.log("redirect=>redirect condition must set function or RegExp!") } } })(endpoint, condition, nextId()), scope); @@ -284,6 +333,7 @@ if (type == this)return this; var event = { + id: type + "#" + nextId(), type: type, target: args.length > 1 ? args[1] : {}//compatibility with older versions }; @@ -303,9 +353,11 @@ iterator(listeners, function (index, listener, listeners, iterator) { if (listener && listener.callback) { var listenerArgs = [].concat(args); - // console.log("event listener call arguments:",listenerArgs); + if(EventBusClass.DEFAULT.SHOW_LOG) + console.log("emit=>event listener call arguments:",listenerArgs); event.args = [].concat(listener.args); - // console.log("fire event listener:", listener); + if(EventBusClass.DEFAULT.SHOW_LOG) + console.log("emit=>fire event listener:", listener); listener.callback.apply(listener.scope, listenerArgs); if (isStop) iterator.stop(); } @@ -348,5 +400,14 @@ EventBusClass.prototype.hasEventListener = EventBusClass.prototype.has; var EventBus = new EventBusClass(); + //common utils + EventBus.slice = slice; + EventBus.nextId = nextId; + EventBus.iterator = iterator; + //default config + EventBus.DEFAULT = EventBusClass.DEFAULT = { + SHOW_LOG: false, + EVENT_TYPE_SPLIT_EXP: /,|\s/ + }; return EventBus; }); \ No newline at end of file From 8014413a7668a5496f694c6ef8b338e796f7e9bd Mon Sep 17 00:00:00 2001 From: tony_shen Date: Mon, 19 Dec 2016 11:17:34 +0800 Subject: [PATCH 08/20] add EventBus.redirect use-case --- README.md | 43 +++++++++++++++++++++++++ example/browser/example.html | 16 +++++----- example/node/cs-test.js | 14 ++++----- lib/eventbus.min.js | 2 +- src/EventBus.js | 61 ++++++++++++++---------------------- 5 files changed, 82 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 4e6fba0..5d6ed1d 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,20 @@ EventBus.trigger(type,target,args...) EventBus.emit(type,target,args...) ``` +### redirect +```javascript +//@origin is event type or event type array +//@endpoint is target event type or event type array +//@condition redirect condition check +//@processor reset trigger endpoint event arguments +EventBus.redirect(origin,endpoint); + +EventBus.redirect(origin,endpoint,condition); + +EventBus.redirect(origin,endpoint,condition,processor); + +``` + ### `getEvents` For debugging purpose, it prints out the added listeners. @@ -181,3 +195,32 @@ var handler = function() { EventBus.addEventListener('EXAMPLE_EVENT', handler); EventBus.removeEventListener('EXAMPLE_EVENT', handler); ``` +## Example of usage EventBus.redirect +```javascript +var TestClass1 = function() { + this.className = "TestClass1"; + this.doSomething = function(event, param1, param2) { + console.log(this.className + ".doSomething"); + console.log("type=" + event.type); + console.log("params=" + param1 + param2); + console.log("coming from=" + event.target.className); + } +}; + +var TestClass2 = function() { + this.className = "TestClass2"; + this.ready = function() { + EventBus.dispatch("custom_event", this, "javascript events", " are really useful"); + } +}; + +var t1 = new TestClass1(); +var t2 = new TestClass2(); + +EventBus.redirect("custom_event","ready"); + +EventBus.on("ready",t1.doSomething,t1); + +t2.ready(); + +``` \ No newline at end of file diff --git a/example/browser/example.html b/example/browser/example.html index 2984a8b..4cbc546 100644 --- a/example/browser/example.html +++ b/example/browser/example.html @@ -5,10 +5,10 @@ - +
- +
\ No newline at end of file diff --git a/example/node/cs-test.js b/example/node/cs-test.js index 8ed214a..824c66e 100644 --- a/example/node/cs-test.js +++ b/example/node/cs-test.js @@ -1,6 +1,3 @@ -/** - * Created by bona on 2016/12/14. - */ var EventBus = require('../../lib/eventbus.min'); EventBus.DEFAULT.SHOW_LOG = false; @@ -93,16 +90,17 @@ EventBus.redirect(/send\/(\w*)/, function (event) { //map one to more }); //map more to one -EventBus.redirect({ - origin: [/QC\/\w*/], - endpoint: "qc-report-collect", - processor: function (event, order) { +EventBus.redirect( + [/QC\/\w*/],//origin event type + "qc-report-collect",//endpoint + undefined,//condition + function (event, order) { //processor console.log("redirect processor for ", event.id, "==>", "origin:", event.getOriginType(), " endpoint:", event.getEndpoint()); if (order.consumer == "bona") event.setEmitArgs([order, "passed"]); } -}); +); var qcReport = { orders: [], diff --git a/lib/eventbus.min.js b/lib/eventbus.min.js index a12d1c6..3a14803 100644 --- a/lib/eventbus.min.js +++ b/lib/eventbus.min.js @@ -1 +1 @@ -(function(a,b){if(typeof exports==="object"&&typeof module==="object"){module.exports=b()}else{if(typeof define==="function"&&define.amd){define("EventBus",[],b)}else{if(typeof exports==="object"){exports.EventBus=b()}else{a.EventBus=b()}}}})(this,function(){function d(k,j){k=k||[];var h={stop:function(i){this.isStopped=true;this.result=i}};for(var g in k){j(g,k[g],k,h);if(h.isStopped){break}}if(h.isStopped){return h.result}}function f(i,h,g){if(h>i.length){return[]}return[].slice.call(i,h==undefined?0:h,g==undefined?i.length:g)||[]}function b(i,k,g){if(typeof i=="string"||i instanceof Array){var h=i;if(typeof i=="string"){h=i.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(h.length>1){var j=this;d(h,function(l,m){g[0]=m;k.apply(j,g)});return j}else{i=h[0]}}return i}var c=(function(){var g=1000;return function(){return ++g}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(j,m,i){j=b.call(this,j,this.on,f(arguments));if(j==this){return this}var l=j instanceof RegExp;var h=l?j.toString():j;var g=f(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",g)}var k={id:c(),scope:i||{},callback:m,args:g,regExp:j,eventType:h};if(!l){if(typeof this.listeners[h]!="undefined"){this.listeners[h].push(k)}else{this.listeners[h]=[k]}}else{this.regexListeners.push(k)}return this},once:function(k,l,j){var g=this;var h=function(m){l.apply(this,f(arguments));g.off(k,h,j)};var i=f(arguments);i[1]=h;return g.on.apply(g,i)},off:function(k,l,o){k=b.call(this,k,this.off,[undefined,l,o]);if(k==this){return this}var i=k instanceof RegExp;var h=i?k.toString():k;var m=[];if(typeof l=="object"){o=l;l=undefined}var j=l==undefined;var n=o==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",k," all callback:",j," all scope:",n)}function g(p){return(j?true:p.callback==l)&&(n?true:p.scope==o)}if(!i){if(typeof this.listeners[h]!="undefined"){if(!(j&&n)){d(this.listeners[h],function(p,q){if(!g(q)){m.push(q)}else{}})}this.listeners[h]=m}}else{d(this.regexListeners,function(p,q){if(!(q.eventType==h&&g(q))){m.push(q)}else{}});this.regexListeners=m}return this},redirect:function(h,l,m,k){if(arguments.length==1&&typeof h=="object"){var j=h;h=j.origin;l=j.endpoint;m=j.condition;k=j.processor}var g=this;if(h==undefined||l==undefined||h==l){return g}var i=this.redirectScope=this.redirectScope||{};k=typeof k=="function"?k:function(n){n.setEmitArgs(a.slice(arguments,1))};this.on(h,(function(q,r,o){if(r==undefined){r=function(){return true}}if(r instanceof RegExp){var p=r;r=function(s){return p.test(s.type)}}if(typeof r=="function"){var n=[];return function(u){var s=f(arguments);if(r.apply(i,s)){var t=typeof q=="function"?q.apply(i,s):q;if(n.indexOf(o)<0&&t!=u.type&&t!=undefined){n.push(o);if(typeof t=="string"){t=t.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(!(t instanceof Array)){t=[t]}d(t,function(v,x){if(x!=u.type){var w=f([].concat(s),1);u.setEmitArgs=function(y){w=y};u.getEmitArgs=function(){return[].concat(w)};u.getOriginType=function(){return h};u.getEndpoint=function(){return x};k.apply(i,s);w=(w instanceof Array)?[""].concat(w):[].concat(s);w[0]=x;if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect id:",u.id," origin:",h," ==> endpoint:",x)}g.emit.apply(g,w)}});n.pop()}else{if(e.DEFAULT.SHOW_LOG){console.log("redirect=>origin:",h.toString()," ==>endpoint:",q.toString()," redirect is looping! this event is lost.")}}}}}else{return function(s){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(l,m,c()),i);return g},has:function(k,n,j){var m=k instanceof RegExp;var h=m?k.toString():k;var i=[].concat(this.listeners[h]);if(typeof n=="object"){j=n;n=undefined}if(i.length>0&&!m){var l=i.length;if(n===undefined&&j===undefined){return l>0}var g=d(i,function(o,q,r,p){if((j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}else{if(m){i=[].concat(this.regexListeners);var g=d(i,function(o,q,r,p){if(q.regExp.toString()==h&&(j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}}return false},emit:function(j){var g=f(arguments);j=b.call(this,j,this.emit,g);if(j==this){return this}var k={id:j+"#"+c(),type:j,target:g.length>1?g[1]:{}};g=[k].concat(f(arguments,1));var i=[].concat(typeof this.listeners[j]=="undefined"?[]:this.listeners[j]);function l(n){var m=false;k.stop=function(){m=true};k.getArg=function(o){if(k.args==undefined||!k.args instanceof Array||k.args.length-1event listener call arguments:",r)}k.args=[].concat(s.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",s)}s.callback.apply(s.scope,r);if(m){p.stop()}}})}var h=[].concat(this.regexListeners);d(h,function(m,n){if(n.regExp.test(j)){i.push(n)}});l(i);return this},getEvents:function(){var l="";for(var h in this.listeners){var k=this.listeners[h].length;for(var g=0;gi.length){return[]}return[].slice.call(i,h===undefined?0:h,g===undefined?i.length:g)||[]}function b(k,h,j,g){if(typeof j=="string"||j instanceof Array){var i=j;if(typeof j=="string"){i=j.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(i.length>1){d(i,function(l,m){g[0]=m;h.apply(k,g)});return k}else{j=i[0]}}return j}var c=(function(){var g=1000;return function(){return ++g}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(j,m,i){j=b(this,this.on,j,f(arguments));if(j==this){return this}var l=j instanceof RegExp;var h=l?j.toString():j;var g=f(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",g)}var k={id:c(),scope:i||{},callback:m,args:g,regExp:j,eventType:h};if(!l){if(typeof this.listeners[h]!="undefined"){this.listeners[h].push(k)}else{this.listeners[h]=[k]}}else{this.regexListeners.push(k)}return this},once:function(k,l,j){var g=this;var h=function(m){l.apply(this,f(arguments));g.off(k,h,j)};var i=f(arguments);i[1]=h;return g.on.apply(g,i)},off:function(k,l,o){k=b(this,this.off,k,[undefined,l,o]);if(k==this){return this}var i=k instanceof RegExp;var h=i?k.toString():k;var m=[];if(typeof l=="object"){o=l;l=undefined}var j=l==undefined;var n=o==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",k," all callback:",j," all scope:",n)}function g(p){return(j?true:p.callback==l)&&(n?true:p.scope==o)}if(!i){if(typeof this.listeners[h]!="undefined"){if(!(j&&n)){d(this.listeners[h],function(p,q){if(!g(q)){m.push(q)}else{}})}this.listeners[h]=m}}else{d(this.regexListeners,function(p,q){if(!(q.eventType===h&&g(q))){m.push(q)}else{}});this.regexListeners=m}return this},redirect:function(h,k,l,j){var g=this;if(h==undefined||k==undefined||h==k){return g}var i=this.redirectScope=this.redirectScope||{};j=typeof j=="function"?j:function(m){m.setEmitArgs(a.slice(arguments,1))};this.on(h,(function(p,q,n){if(q==undefined){q=function(){return true}}if(q instanceof RegExp){var o=q;q=function(r){return o.test(r.type)}}if(typeof q=="function"){var m=[];return function(t){var r=f(arguments);if(q.apply(i,r)){var s=typeof p=="function"?p.apply(i,r):p;if(m.indexOf(n)<0&&s!=t.type&&s!=undefined){m.push(n);if(typeof s=="string"){s=s.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(!(s instanceof Array)){s=[s]}d(s,function(u,w){if(w!=t.type){var v=f([].concat(r),1);t.setEmitArgs=function(x){v=x};t.getEmitArgs=function(){return[].concat(v)};t.getOriginType=function(){return h};t.getEndpoint=function(){return w};j.apply(i,r);v=(v instanceof Array)?[""].concat(v):[].concat(r);v[0]=w;if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect id:",t.id," origin:",h," ==> endpoint:",w)}g.emit.apply(g,v)}});m.pop()}else{if(e.DEFAULT.SHOW_LOG){console.log("redirect=>origin:",h.toString()," ==>endpoint:",p.toString()," redirect is looping! this event is lost.")}}}}}else{return function(r){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(k,l,c()),i);return g},has:function(k,n,j){var m=k instanceof RegExp;var h=m?k.toString():k;var i=[].concat(this.listeners[h]);if(typeof n=="object"){j=n;n=undefined}if(i.length>0&&!m){var l=i.length;if(n===undefined&&j===undefined){return l>0}var g=d(i,function(o,q,r,p){if((j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}else{if(m){i=[].concat(this.regexListeners);var g=d(i,function(o,q,r,p){if(q.regExp.toString()==h&&(j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}}return false},emit:function(j){var g=f(arguments);j=b(this,this.emit,j,g);if(j==this){return this}var k={id:j+"#"+c(),type:j,target:g.length>1?g[1]:{}};g=[k].concat(f(arguments,1));var i=[].concat(typeof this.listeners[j]=="undefined"?[]:this.listeners[j]);function l(n){var m=false;k.stop=function(){m=true};k.getArg=function(o){if(k.args==undefined||!k.args instanceof Array||k.args.length-1event listener call arguments:",r)}k.args=[].concat(s.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",s)}s.callback.apply(s.scope,r);if(m){p.stop()}}})}var h=[].concat(this.regexListeners);d(h,function(m,n){if(n.regExp.test(j)){i.push(n)}});l(i);return this},getEvents:function(){var l="";for(var h in this.listeners){var k=this.listeners[h].length;for(var g=0;g array.length)return []; - return [].slice.call(array, start == undefined ? 0 : start, end == undefined ? array.length : end) || []; + return [].slice.call(array, start === undefined ? 0 : start, end === undefined ? array.length : end) || []; } - function processMultiTypes(type, callback, args) { + function processMultiTypes(busObject, busMethod, type, args) { if (typeof type == "string" || type instanceof Array) { var types = type; if (typeof type == "string") types = type.trim().split(EventBusClass.DEFAULT.EVENT_TYPE_SPLIT_EXP); if (types.length > 1) { - var that = this; iterator(types, function (index, type) { args[0] = type; - callback.apply(that, args); + busMethod.apply(busObject, args); }); - return that; + return busObject; } else { type = types[0]; } } return type; } + /** * id generator */ @@ -75,14 +73,14 @@ * @returns {EventBusClass} */ on: function (type, callback, scope) { - type = processMultiTypes.call(this, type, this.on, slice(arguments)); + type = processMultiTypes(this, this.on, type, slice(arguments)); if (type == this)return this; var isRegExpType = type instanceof RegExp; var eventType = isRegExpType ? type.toString() : type; var args = slice(arguments); - if(EventBusClass.DEFAULT.SHOW_LOG) - console.log("on=>listener args is ",args); + if (EventBusClass.DEFAULT.SHOW_LOG) + console.log("on=>listener args is ", args); var listener = {//create listener stub id: nextId(), scope: scope || {}, @@ -132,7 +130,7 @@ */ off: function (type, callback, scope) { //support EventBus.off(['click',/click/]); - type = processMultiTypes.call(this, type, this.off, [undefined, callback, scope]); + type = processMultiTypes(this, this.off, type, [undefined, callback, scope]); if (type == this)return this; var isRegExpType = type instanceof RegExp; @@ -144,7 +142,7 @@ } var allCallback = callback == undefined; var allScope = scope == undefined; - if(EventBusClass.DEFAULT.SHOW_LOG) + if (EventBusClass.DEFAULT.SHOW_LOG) console.log("off=>off event type:", type, " all callback:", allCallback, " all scope:", allScope); // console.log("callback:", callback, " scope:", scope); function isRemove(listener) { @@ -165,7 +163,7 @@ } } else { iterator(this.regexListeners, function (index, listener) { - if (!(listener.eventType == eventType && isRemove(listener))) newArray.push(listener); + if (!(listener.eventType === eventType && isRemove(listener))) newArray.push(listener); else { // console.log("remove listener:", type, listener); } @@ -186,17 +184,6 @@ * @return {EventBusClass} */ redirect: function (origin, endpoint, condition, processor) { - //support EventBus.redirect({ - // origin:'click', - // endpoint:'onClick' - // }) - if (arguments.length == 1 && typeof origin == "object") { - var option = origin; - origin = option["origin"]; - endpoint = option["endpoint"]; - condition = option["condition"]; - processor = option["processor"]; - } var bus = this; if (origin == undefined || endpoint == undefined || origin == endpoint)return bus; @@ -248,25 +235,25 @@ processor.apply(scope, args); emitArgs = (emitArgs instanceof Array) ? [""].concat(emitArgs) : [].concat(args); emitArgs[0] = type; - if(EventBusClass.DEFAULT.SHOW_LOG) + if (EventBusClass.DEFAULT.SHOW_LOG) console.log("redirect=>redirect id:", event.id, " origin:", origin, " ==> endpoint:", type); - bus.emit.apply(bus, emitArgs);//dispatch endpoint event} + bus.emit.apply(bus, emitArgs);//dispatch endpoint event } } ); stack.pop(); } else { - if(EventBusClass.DEFAULT.SHOW_LOG) + if (EventBusClass.DEFAULT.SHOW_LOG) console.log("redirect=>origin:", origin.toString(), - " ==>endpoint:", endpoint.toString(), - " redirect is looping! this event is lost."); + " ==>endpoint:", endpoint.toString(), + " redirect is looping! this event is lost."); } } } } else { return function (event) { - if(EventBusClass.DEFAULT.SHOW_LOG) + if (EventBusClass.DEFAULT.SHOW_LOG) console.log("redirect=>redirect condition must set function or RegExp!") } } @@ -329,7 +316,7 @@ // console.log("emit arguments:",arguments); var args = slice(arguments); - type = processMultiTypes.call(this, type, this.emit, args); + type = processMultiTypes(this, this.emit, type, args); if (type == this)return this; var event = { @@ -353,10 +340,10 @@ iterator(listeners, function (index, listener, listeners, iterator) { if (listener && listener.callback) { var listenerArgs = [].concat(args); - if(EventBusClass.DEFAULT.SHOW_LOG) - console.log("emit=>event listener call arguments:",listenerArgs); + if (EventBusClass.DEFAULT.SHOW_LOG) + console.log("emit=>event listener call arguments:", listenerArgs); event.args = [].concat(listener.args); - if(EventBusClass.DEFAULT.SHOW_LOG) + if (EventBusClass.DEFAULT.SHOW_LOG) console.log("emit=>fire event listener:", listener); listener.callback.apply(listener.scope, listenerArgs); if (isStop) iterator.stop(); From fc13c6405ae154a130ddfad4223a3c491add27a8 Mon Sep 17 00:00:00 2001 From: tony_shen Date: Mon, 19 Dec 2016 12:04:16 +0800 Subject: [PATCH 09/20] event flow use-case --- example/node/cs-test.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/example/node/cs-test.js b/example/node/cs-test.js index 824c66e..388612d 100644 --- a/example/node/cs-test.js +++ b/example/node/cs-test.js @@ -80,19 +80,19 @@ EventBus.redirect(/(\w*)\/(\w*)/, function (event) { return /(\w*)\/(\w*)/.exec(event.type)[1]; }); -EventBus.redirect(/send\/(\w*)/, function (event) {//map one to one +EventBus.redirect(/trans\/(\w*)/, function (event) {//map one to one return "receive/" + /(\w*)\/(\w*)/.exec(event.type)[2]; }); EventBus.redirect(/send\/(\w*)/, function (event) { //map one to more var consumer = /(\w*)\/(\w*)/.exec(event.type)[2]; - return ["trans/" + consumer, "print/" + consumer, "QC/" + consumer]; + return ["print/" + consumer, "QC/" + consumer]; }); //map more to one EventBus.redirect( [/QC\/\w*/],//origin event type - "qc-report-collect",//endpoint + "qc-report",//endpoint undefined,//condition function (event, order) { //processor console.log("redirect processor for ", event.id, "==>", @@ -102,6 +102,14 @@ EventBus.redirect( } ); +EventBus.redirect( + "qc-report",function (event,order) { + return "trans/"+order.consumer; + },function (event,order,state) { + return state==="passed"; + } +); + var qcReport = { orders: [], passed: [], @@ -111,7 +119,7 @@ var qcReport = { } }; -EventBus.on("qc-report-collect", function (event, order, checkState) { +EventBus.on("qc-report", function (event, order, checkState) { this.orders.push(order); if (checkState == "passed") this.passed.push(order); }, qcReport); From a81143ef54727d9b847b2ebc105c99b784817a6d Mon Sep 17 00:00:00 2001 From: tony_shen Date: Tue, 20 Dec 2016 00:30:02 +0800 Subject: [PATCH 10/20] add event flow object property --- example/node/cs-test.js | 8 ++++++++ lib/eventbus.min.js | 2 +- src/EventBus.js | 29 +++++++++++++++++++++++------ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/example/node/cs-test.js b/example/node/cs-test.js index 388612d..7858c8c 100644 --- a/example/node/cs-test.js +++ b/example/node/cs-test.js @@ -44,6 +44,14 @@ Consumer.prototype = { console.log(this.name, "'s order is packaging. order id=", order.id, " order name:" + order.name); }, onReceive: function (event, order) { + /*event.flow.getAllEvents().forEach(function (v, i) { + console.log(v); + });*/ + var p = event; + while (p) {//print event flow + console.log("event level ",p.getLevel()," level object:",p); + p = p.flow.getClosestEvent(); + } console.log(this.name, "is ready to receive order goods. order id=", order.id, " order name:" + order.name); }, diff --git a/lib/eventbus.min.js b/lib/eventbus.min.js index 3a14803..445e102 100644 --- a/lib/eventbus.min.js +++ b/lib/eventbus.min.js @@ -1 +1 @@ -(function(a,b){if(typeof exports==="object"&&typeof module==="object"){module.exports=b()}else{if(typeof define==="function"&&define.amd){define("EventBus",[],b)}else{if(typeof exports==="object"){exports.EventBus=b()}else{a.EventBus=b()}}}})(this,function(){function d(k,j){k=k||[];var h={stop:function(i){this.isStopped=true;this.result=i},isStopped:false,result:undefined};for(var g in k){j(g,k[g],k,h);if(h.isStopped){break}}if(h.isStopped){return h.result}}function f(i,h,g){if(h>i.length){return[]}return[].slice.call(i,h===undefined?0:h,g===undefined?i.length:g)||[]}function b(k,h,j,g){if(typeof j=="string"||j instanceof Array){var i=j;if(typeof j=="string"){i=j.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(i.length>1){d(i,function(l,m){g[0]=m;h.apply(k,g)});return k}else{j=i[0]}}return j}var c=(function(){var g=1000;return function(){return ++g}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(j,m,i){j=b(this,this.on,j,f(arguments));if(j==this){return this}var l=j instanceof RegExp;var h=l?j.toString():j;var g=f(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",g)}var k={id:c(),scope:i||{},callback:m,args:g,regExp:j,eventType:h};if(!l){if(typeof this.listeners[h]!="undefined"){this.listeners[h].push(k)}else{this.listeners[h]=[k]}}else{this.regexListeners.push(k)}return this},once:function(k,l,j){var g=this;var h=function(m){l.apply(this,f(arguments));g.off(k,h,j)};var i=f(arguments);i[1]=h;return g.on.apply(g,i)},off:function(k,l,o){k=b(this,this.off,k,[undefined,l,o]);if(k==this){return this}var i=k instanceof RegExp;var h=i?k.toString():k;var m=[];if(typeof l=="object"){o=l;l=undefined}var j=l==undefined;var n=o==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",k," all callback:",j," all scope:",n)}function g(p){return(j?true:p.callback==l)&&(n?true:p.scope==o)}if(!i){if(typeof this.listeners[h]!="undefined"){if(!(j&&n)){d(this.listeners[h],function(p,q){if(!g(q)){m.push(q)}else{}})}this.listeners[h]=m}}else{d(this.regexListeners,function(p,q){if(!(q.eventType===h&&g(q))){m.push(q)}else{}});this.regexListeners=m}return this},redirect:function(h,k,l,j){var g=this;if(h==undefined||k==undefined||h==k){return g}var i=this.redirectScope=this.redirectScope||{};j=typeof j=="function"?j:function(m){m.setEmitArgs(a.slice(arguments,1))};this.on(h,(function(p,q,n){if(q==undefined){q=function(){return true}}if(q instanceof RegExp){var o=q;q=function(r){return o.test(r.type)}}if(typeof q=="function"){var m=[];return function(t){var r=f(arguments);if(q.apply(i,r)){var s=typeof p=="function"?p.apply(i,r):p;if(m.indexOf(n)<0&&s!=t.type&&s!=undefined){m.push(n);if(typeof s=="string"){s=s.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(!(s instanceof Array)){s=[s]}d(s,function(u,w){if(w!=t.type){var v=f([].concat(r),1);t.setEmitArgs=function(x){v=x};t.getEmitArgs=function(){return[].concat(v)};t.getOriginType=function(){return h};t.getEndpoint=function(){return w};j.apply(i,r);v=(v instanceof Array)?[""].concat(v):[].concat(r);v[0]=w;if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect id:",t.id," origin:",h," ==> endpoint:",w)}g.emit.apply(g,v)}});m.pop()}else{if(e.DEFAULT.SHOW_LOG){console.log("redirect=>origin:",h.toString()," ==>endpoint:",p.toString()," redirect is looping! this event is lost.")}}}}}else{return function(r){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(k,l,c()),i);return g},has:function(k,n,j){var m=k instanceof RegExp;var h=m?k.toString():k;var i=[].concat(this.listeners[h]);if(typeof n=="object"){j=n;n=undefined}if(i.length>0&&!m){var l=i.length;if(n===undefined&&j===undefined){return l>0}var g=d(i,function(o,q,r,p){if((j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}else{if(m){i=[].concat(this.regexListeners);var g=d(i,function(o,q,r,p){if(q.regExp.toString()==h&&(j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}}return false},emit:function(j){var g=f(arguments);j=b(this,this.emit,j,g);if(j==this){return this}var k={id:j+"#"+c(),type:j,target:g.length>1?g[1]:{}};g=[k].concat(f(arguments,1));var i=[].concat(typeof this.listeners[j]=="undefined"?[]:this.listeners[j]);function l(n){var m=false;k.stop=function(){m=true};k.getArg=function(o){if(k.args==undefined||!k.args instanceof Array||k.args.length-1event listener call arguments:",r)}k.args=[].concat(s.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",s)}s.callback.apply(s.scope,r);if(m){p.stop()}}})}var h=[].concat(this.regexListeners);d(h,function(m,n){if(n.regExp.test(j)){i.push(n)}});l(i);return this},getEvents:function(){var l="";for(var h in this.listeners){var k=this.listeners[h].length;for(var g=0;gi.length){return[]}return[].slice.call(i,h===undefined?0:h,g===undefined?i.length:g)||[]}function b(k,h,j,g){if(typeof j=="string"||j instanceof Array){var i=j;if(typeof j=="string"){i=j.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(i.length>1){d(i,function(l,m){g[0]=m;h.apply(k,g)});return k}else{j=i[0]}}return j}var c=(function(){var g=1000;return function(){return ++g}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(j,m,i){j=b(this,this.on,j,f(arguments));if(j==this){return this}var l=j instanceof RegExp;var h=l?j.toString():j;var g=f(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",g)}var k={id:c(),scope:i||{},callback:m,args:g,regExp:j,eventType:h};if(!l){if(typeof this.listeners[h]!="undefined"){this.listeners[h].push(k)}else{this.listeners[h]=[k]}}else{this.regexListeners.push(k)}return this},once:function(k,l,j){var g=this;var h=function(m){l.apply(this,f(arguments));g.off(k,h,j)};var i=f(arguments);i[1]=h;return g.on.apply(g,i)},off:function(k,l,o){k=b(this,this.off,k,[undefined,l,o]);if(k==this){return this}var i=k instanceof RegExp;var h=i?k.toString():k;var m=[];if(typeof l=="object"){o=l;l=undefined}var j=l==undefined;var n=o==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",k," all callback:",j," all scope:",n)}function g(p){return(j?true:p.callback==l)&&(n?true:p.scope==o)}if(!i){if(typeof this.listeners[h]!="undefined"){if(!(j&&n)){d(this.listeners[h],function(p,q){if(!g(q)){m.push(q)}else{}})}this.listeners[h]=m}}else{d(this.regexListeners,function(p,q){if(!(q.eventType===h&&g(q))){m.push(q)}else{}});this.regexListeners=m}return this},redirect:function(h,k,l,j){var g=this;if(h==undefined||k==undefined||h==k){return g}var i=this.redirectScope=this.redirectScope||{};j=typeof j=="function"?j:function(m){m.setEmitArgs(a.slice(arguments,1))};this.on(h,(function(p,q,n){if(q==undefined){q=function(){return true}}if(q instanceof RegExp){var o=q;q=function(r){return o.test(r.type)}}if(typeof q=="function"){var m=[];return function(t){var r=f(arguments);if(q.apply(i,r)){var s=typeof p=="function"?p.apply(i,r):p;if(m.indexOf(n)<0&&s!=t.type&&s!=undefined){m.push(n);if(typeof s=="string"){s=s.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(!(s instanceof Array)){s=[s]}d(s,function(u,w){if(w!=t.type){var v=f([].concat(r),1);t.setEmitArgs=function(x){v=x};t.getEmitArgs=function(){return[].concat(v)};t.getOriginType=function(){return h};t.getEndpoint=function(){return w};t.endpoints=t.endpoints||[];t.endpoints.push(w);j.apply(i,r);v=(v instanceof Array)?[""].concat(v):[].concat(r);v[0]=w;if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect id:",t.id," origin:",h," ==> endpoint:",w)}g.emit.apply(g,v)}});m.pop()}else{if(e.DEFAULT.SHOW_LOG){console.log("redirect=>origin:",h.toString()," ==>endpoint:",p.toString()," redirect is looping! this event is lost.")}}}}}else{return function(r){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(k,l,c()),i);return g},has:function(k,n,j){var m=k instanceof RegExp;var h=m?k.toString():k;var i=[].concat(this.listeners[h]);if(typeof n=="object"){j=n;n=undefined}if(i.length>0&&!m){var l=i.length;if(n===undefined&&j===undefined){return l>0}var g=d(i,function(o,q,r,p){if((j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}else{if(m){i=[].concat(this.regexListeners);var g=d(i,function(o,q,r,p){if(q.regExp.toString()==h&&(j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}}return false},emit:function(k){var g=this.eventFlow=this.eventFlow||[];var h=f(arguments);k=b(this,this.emit,k,h);if(k==this){return this}var l={id:k+"#"+c(),type:k,target:h.length>1?h[1]:{}};h=[l].concat(f(arguments,1));var j=[].concat(typeof this.listeners[k]=="undefined"?[]:this.listeners[k]);function m(p){var n=[].concat(g);var o=false;l.stop=function(){o=true};l.getArg=function(q){if(l.args==undefined||!l.args instanceof Array||l.args.length-1event listener call arguments:",t)}l.args=[].concat(u.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",u)}u.callback.apply(u.scope,t);if(o){r.stop()}}})}var i=[].concat(this.regexListeners);d(i,function(n,o){if(o.regExp.test(k)){j.push(o)}});g.push(l);m(j);g.pop();return this},getAllEvents:function(){var l="";for(var h in this.listeners){var k=this.listeners[h].length;for(var g=0;g 1 ? args[1] : {}//compatibility with older versions }; args = [event].concat(slice(arguments, 1)); - // console.log("emit arguments:",arguments," listener arguments:",args); var listeners = [].concat(typeof this.listeners[type] == "undefined" ? [] : this.listeners[type]); function dispatchEvent(listeners) { + var stack = [].concat(eventFlow); var isStop = false; event.stop = function () { isStop = true; @@ -337,6 +337,22 @@ if (event.args == undefined || !event.args instanceof Array || event.args.length - 1 < index)return undefined; return event.args[index]; }; + event.flow = { + getEarlyEvent: function () { + return stack.slice(0, 1).shift(); + }, + getClosestEvent: function () { + return stack.slice(0, stack.length - 1).pop(); + }, + getAllEvents: function () { + return stack.slice(0); + } + }; + + event.getLevel = function () { + return stack.length-1; + }; + iterator(listeners, function (index, listener, listeners, iterator) { if (listener && listener.callback) { var listenerArgs = [].concat(args); @@ -358,11 +374,12 @@ listeners.push(listener); } }); - + eventFlow.push(event); dispatchEvent(listeners); + eventFlow.pop(); return this; }, - getEvents: function () { + getAllEvents: function () { var str = ""; for (var type in this.listeners) { var numOfCallbacks = this.listeners[type].length; From c9cee8342e2081a84f2e7b8cfd93b28df6abbdae Mon Sep 17 00:00:00 2001 From: tony_shen Date: Tue, 20 Dec 2016 09:35:20 +0800 Subject: [PATCH 11/20] add EventBus.flow method support quick and intuitive configuration of event flow --- example/node/cs-test.js | 20 +++++--- lib/eventbus.min.js | 2 +- src/EventBus.js | 105 +++++++++++++++++++++++++--------------- 3 files changed, 80 insertions(+), 47 deletions(-) diff --git a/example/node/cs-test.js b/example/node/cs-test.js index 7858c8c..a02bcab 100644 --- a/example/node/cs-test.js +++ b/example/node/cs-test.js @@ -49,10 +49,11 @@ Consumer.prototype = { });*/ var p = event; while (p) {//print event flow - console.log("event level ",p.getLevel()," level object:",p); + console.log("event level ", p.getLevel(), " level object:", p); p = p.flow.getClosestEvent(); } - console.log(this.name, "is ready to receive order goods. order id=", order.id, " order name:" + order.name); + // console.log(this.name, "is ready to receive order goods. order id=", order.id, " order name:" + order.name); + throw "Not enough space for storage of goods in order " + order.id + "!"; }, init: function (once) { @@ -105,16 +106,15 @@ EventBus.redirect( function (event, order) { //processor console.log("redirect processor for ", event.id, "==>", "origin:", event.getOriginType(), " endpoint:", event.getEndpoint()); - if (order.consumer == "bona") event.setEmitArgs([order, "passed"]); } ); EventBus.redirect( - "qc-report",function (event,order) { - return "trans/"+order.consumer; - },function (event,order,state) { - return state==="passed"; + "qc-report", function (event, order) { + return "trans/" + order.consumer; + }, function (event, order, state) { + return state === "passed"; } ); @@ -132,6 +132,12 @@ EventBus.on("qc-report", function (event, order, checkState) { if (checkState == "passed") this.passed.push(order); }, qcReport); + +//exception handling +EventBus.on(EventBus.DEFAULT.ERROR_EVENT_TYPE, function (event, exception, listener, listenerArgs) { + console.log("found exception:", exception, ", listener is ", listener, " ,args:", listenerArgs); +}); + new Consumer("peter"); new Consumer("kerry"); new Consumer("bona", true); diff --git a/lib/eventbus.min.js b/lib/eventbus.min.js index 445e102..fe641a4 100644 --- a/lib/eventbus.min.js +++ b/lib/eventbus.min.js @@ -1 +1 @@ -(function(a,b){if(typeof exports==="object"&&typeof module==="object"){module.exports=b()}else{if(typeof define==="function"&&define.amd){define("EventBus",[],b)}else{if(typeof exports==="object"){exports.EventBus=b()}else{a.EventBus=b()}}}})(this,function(){function d(k,j){k=k||[];var h={stop:function(i){this.isStopped=true;this.result=i},isStopped:false,result:undefined};for(var g in k){j(g,k[g],k,h);if(h.isStopped){break}}if(h.isStopped){return h.result}}function f(i,h,g){if(h>i.length){return[]}return[].slice.call(i,h===undefined?0:h,g===undefined?i.length:g)||[]}function b(k,h,j,g){if(typeof j=="string"||j instanceof Array){var i=j;if(typeof j=="string"){i=j.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(i.length>1){d(i,function(l,m){g[0]=m;h.apply(k,g)});return k}else{j=i[0]}}return j}var c=(function(){var g=1000;return function(){return ++g}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(j,m,i){j=b(this,this.on,j,f(arguments));if(j==this){return this}var l=j instanceof RegExp;var h=l?j.toString():j;var g=f(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",g)}var k={id:c(),scope:i||{},callback:m,args:g,regExp:j,eventType:h};if(!l){if(typeof this.listeners[h]!="undefined"){this.listeners[h].push(k)}else{this.listeners[h]=[k]}}else{this.regexListeners.push(k)}return this},once:function(k,l,j){var g=this;var h=function(m){l.apply(this,f(arguments));g.off(k,h,j)};var i=f(arguments);i[1]=h;return g.on.apply(g,i)},off:function(k,l,o){k=b(this,this.off,k,[undefined,l,o]);if(k==this){return this}var i=k instanceof RegExp;var h=i?k.toString():k;var m=[];if(typeof l=="object"){o=l;l=undefined}var j=l==undefined;var n=o==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",k," all callback:",j," all scope:",n)}function g(p){return(j?true:p.callback==l)&&(n?true:p.scope==o)}if(!i){if(typeof this.listeners[h]!="undefined"){if(!(j&&n)){d(this.listeners[h],function(p,q){if(!g(q)){m.push(q)}else{}})}this.listeners[h]=m}}else{d(this.regexListeners,function(p,q){if(!(q.eventType===h&&g(q))){m.push(q)}else{}});this.regexListeners=m}return this},redirect:function(h,k,l,j){var g=this;if(h==undefined||k==undefined||h==k){return g}var i=this.redirectScope=this.redirectScope||{};j=typeof j=="function"?j:function(m){m.setEmitArgs(a.slice(arguments,1))};this.on(h,(function(p,q,n){if(q==undefined){q=function(){return true}}if(q instanceof RegExp){var o=q;q=function(r){return o.test(r.type)}}if(typeof q=="function"){var m=[];return function(t){var r=f(arguments);if(q.apply(i,r)){var s=typeof p=="function"?p.apply(i,r):p;if(m.indexOf(n)<0&&s!=t.type&&s!=undefined){m.push(n);if(typeof s=="string"){s=s.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(!(s instanceof Array)){s=[s]}d(s,function(u,w){if(w!=t.type){var v=f([].concat(r),1);t.setEmitArgs=function(x){v=x};t.getEmitArgs=function(){return[].concat(v)};t.getOriginType=function(){return h};t.getEndpoint=function(){return w};t.endpoints=t.endpoints||[];t.endpoints.push(w);j.apply(i,r);v=(v instanceof Array)?[""].concat(v):[].concat(r);v[0]=w;if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect id:",t.id," origin:",h," ==> endpoint:",w)}g.emit.apply(g,v)}});m.pop()}else{if(e.DEFAULT.SHOW_LOG){console.log("redirect=>origin:",h.toString()," ==>endpoint:",p.toString()," redirect is looping! this event is lost.")}}}}}else{return function(r){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(k,l,c()),i);return g},has:function(k,n,j){var m=k instanceof RegExp;var h=m?k.toString():k;var i=[].concat(this.listeners[h]);if(typeof n=="object"){j=n;n=undefined}if(i.length>0&&!m){var l=i.length;if(n===undefined&&j===undefined){return l>0}var g=d(i,function(o,q,r,p){if((j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}else{if(m){i=[].concat(this.regexListeners);var g=d(i,function(o,q,r,p){if(q.regExp.toString()==h&&(j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}}return false},emit:function(k){var g=this.eventFlow=this.eventFlow||[];var h=f(arguments);k=b(this,this.emit,k,h);if(k==this){return this}var l={id:k+"#"+c(),type:k,target:h.length>1?h[1]:{}};h=[l].concat(f(arguments,1));var j=[].concat(typeof this.listeners[k]=="undefined"?[]:this.listeners[k]);function m(p){var n=[].concat(g);var o=false;l.stop=function(){o=true};l.getArg=function(q){if(l.args==undefined||!l.args instanceof Array||l.args.length-1event listener call arguments:",t)}l.args=[].concat(u.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",u)}u.callback.apply(u.scope,t);if(o){r.stop()}}})}var i=[].concat(this.regexListeners);d(i,function(n,o){if(o.regExp.test(k)){j.push(o)}});g.push(l);m(j);g.pop();return this},getAllEvents:function(){var l="";for(var h in this.listeners){var k=this.listeners[h].length;for(var g=0;gi.length){return[]}return[].slice.call(i,h===undefined?0:h,g===undefined?i.length:g)||[]}function b(k,h,j,g){if(typeof j=="string"||j instanceof Array){var i=j;if(typeof j=="string"){i=j.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(i.length>1){d(i,function(l,m){g[0]=m;h.apply(k,g)});return k}else{j=i[0]}}return j}var c=(function(){var g=1000;return function(){return ++g}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(j,m,i){j=b(this,this.on,j,f(arguments));if(j==this){return this}var l=j instanceof RegExp;var h=l?j.toString():j;var g=f(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",g)}var k={id:c(),scope:i||{},callback:m,args:g,regExp:j,eventType:h};if(!l){if(typeof this.listeners[h]!="undefined"){this.listeners[h].push(k)}else{this.listeners[h]=[k]}}else{this.regexListeners.push(k)}return this},once:function(k,l,j){var g=this;var h=function(m){l.apply(this,f(arguments));g.off(k,h,j)};var i=f(arguments);i[1]=h;return g.on.apply(g,i)},off:function(k,l,o){k=b(this,this.off,k,[undefined,l,o]);if(k==this){return this}var i=k instanceof RegExp;var h=i?k.toString():k;var m=[];if(typeof l=="object"){o=l;l=undefined}var j=l==undefined;var n=o==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",k," all callback:",j," all scope:",n)}function g(p){return(j?true:p.callback==l)&&(n?true:p.scope==o)}if(!i){if(typeof this.listeners[h]!="undefined"){if(!(j&&n)){d(this.listeners[h],function(p,q){if(!g(q)){m.push(q)}else{}})}this.listeners[h]=m}}else{d(this.regexListeners,function(p,q){if(!(q.eventType===h&&g(q))){m.push(q)}else{}});this.regexListeners=m}return this},redirect:function(h,k,l,j){var g=this;if(h==undefined||k==undefined||h==k){return g}var i=this.redirectScope=this.redirectScope||{};j=typeof j=="function"?j:function(m){m.setEmitArgs(a.slice(arguments,1))};this.on(h,(function(p,q,n){if(q==undefined){q=function(){return true}}if(q instanceof RegExp){var o=q;q=function(r){return o.test(r.type)}}if(typeof q=="function"){var m=[];return function(t){var r=f(arguments);if(q.apply(i,r)){var s=typeof p=="function"?p.apply(i,r):p;if(m.indexOf(n)<0&&s!=t.type&&s!=undefined){m.push(n);try{if(typeof s=="string"){s=s.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(!(s instanceof Array)){s=[s]}d(s,function(u,w){if(w!=t.type){var v=f([].concat(r),1);t.setEmitArgs=function(x){v=x};t.getEmitArgs=function(){return[].concat(v)};t.getOriginType=function(){return h};t.getEndpoint=function(){return w};t.endpoints=t.endpoints||[];t.endpoints.push(w);j.apply(i,r);v=(v instanceof Array)?[""].concat(v):[].concat(r);v[0]=w;if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect id:",t.id," origin:",h," ==> endpoint:",w)}g.emit.apply(g,v)}})}finally{m.pop()}}else{throw"redirect origin:"+h.toString()+" => endpoint:"+p.toString()+" is looping!"}}}}else{return function(r){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(k,l,c()),i);return g},flow:function(h){var i=f(arguments);if(h instanceof Array){i=h}var g=this;d(i,function(j,k){if(k instanceof Object&&typeof k=="object"&&k.from!=undefined&&k.to!=undefined){g.redirect(k.from,k.to,k.where,k.processor)}});return g},has:function(k,n,j){var m=k instanceof RegExp;var h=m?k.toString():k;var i=[].concat(this.listeners[h]);if(typeof n=="object"){j=n;n=undefined}if(i.length>0&&!m){var l=i.length;if(n===undefined&&j===undefined){return l>0}var g=d(i,function(o,q,r,p){if((j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}else{if(m){i=[].concat(this.regexListeners);var g=d(i,function(o,q,r,p){if(q.regExp.toString()==h&&(j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}}return false},emit:function(l){var h=this.eventFlow=this.eventFlow||[];var i=f(arguments);l=b(this,this.emit,l,i);if(l==this){return this}var m={id:l+"#"+c(),type:l,target:i.length>1?i[1]:{}};i=[m].concat(f(arguments,1));var k=[].concat(typeof this.listeners[l]=="undefined"?[]:this.listeners[l]);var g=this;function n(q){var o=[].concat(h);var p=false;m.stop=function(){p=true};m.getArg=function(r){if(m.args==undefined||!m.args instanceof Array||m.args.length-1event listener call arguments:",v)}m.args=[].concat(w.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",w)}try{w.callback.apply(w.scope,v)}catch(s){p=true;g.emit(g.DEFAULT.ERROR_EVENT_TYPE,s,w,v)}if(p){t.stop()}}})}var j=[].concat(this.regexListeners);d(j,function(o,p){if(p.regExp.test(l)){k.push(p)}});h.push(m);n(k);h.pop();return this},getAllEvents:function(){var l="";for(var h in this.listeners){var k=this.listeners[h].length;for(var g=0;gredirect id:", event.id, " origin:", origin, " ==> endpoint:", type); - bus.emit.apply(bus, emitArgs);//dispatch endpoint event - } + try { + if (typeof eventType == "string") eventType = + eventType.trim().split(EventBusClass.DEFAULT.EVENT_TYPE_SPLIT_EXP);//support string split by SPACE,COMMA char + if (!(eventType instanceof Array)) { + eventType = [eventType]; } - ); - stack.pop(); + iterator(eventType, function (index, type) {//support endpoint array + if (type != event.type) { + var emitArgs = slice([].concat(args), 1); + event.setEmitArgs = function (args) { + emitArgs = args; + }; + event.getEmitArgs = function () { + return [].concat(emitArgs); + }; + event.getOriginType = function () { + return origin; + }; + event.getEndpoint = function () { + return type; + }; + event.endpoints = event.endpoints || []; + event.endpoints.push(type); + processor.apply(scope, args); + emitArgs = (emitArgs instanceof Array) ? [""].concat(emitArgs) : [].concat(args); + emitArgs[0] = type; + if (EventBusClass.DEFAULT.SHOW_LOG) + console.log("redirect=>redirect id:", event.id, " origin:", origin, " ==> endpoint:", type); + bus.emit.apply(bus, emitArgs);//dispatch endpoint event + } + } + ); + } finally { + stack.pop(); + } } else { - if (EventBusClass.DEFAULT.SHOW_LOG) - console.log("redirect=>origin:", origin.toString(), - " ==>endpoint:", endpoint.toString(), - " redirect is looping! this event is lost."); + throw "redirect origin:" + origin.toString() + " => endpoint:" + endpoint.toString() + + " is looping!"; } } } @@ -262,6 +263,25 @@ })(endpoint, condition, nextId()), scope); return bus; }, + /** + * build event flow + * EventBus.flow({from:'click',to:'onClick'}) + * EventBus.flow({from:'ready',to:'start'},{from:'start',to:'end'}) + * EventBus.flow({from:'click',to:'onClick',where:function(event){event.getLevel()>1}}) + * @param node is event flow node map config,maybe node map array + * @return {EventBusClass} + */ + flow: function (node) { + var nodeMap = slice(arguments); + if (node instanceof Array) nodeMap = node; + var bus = this; + iterator(nodeMap, function (index, node) { + if (node instanceof Object && typeof node == "object" && node['from'] != undefined && node['to'] != undefined) { + bus.redirect(node['from'], node['to'], node['where'], node['processor']); + } + }); + return bus; + }, /** * EventBus.has("click") * EventBus.has("click",buttonScope); @@ -326,6 +346,7 @@ }; args = [event].concat(slice(arguments, 1)); var listeners = [].concat(typeof this.listeners[type] == "undefined" ? [] : this.listeners[type]); + var bus = this; function dispatchEvent(listeners) { var stack = [].concat(eventFlow); @@ -350,7 +371,7 @@ }; event.getLevel = function () { - return stack.length-1; + return stack.length - 1; }; iterator(listeners, function (index, listener, listeners, iterator) { @@ -361,7 +382,12 @@ event.args = [].concat(listener.args); if (EventBusClass.DEFAULT.SHOW_LOG) console.log("emit=>fire event listener:", listener); - listener.callback.apply(listener.scope, listenerArgs); + try { + listener.callback.apply(listener.scope, listenerArgs); + } catch (exception) { + isStop = true; + bus.emit(bus.DEFAULT.ERROR_EVENT_TYPE, exception, listener, listenerArgs); + } if (isStop) iterator.stop(); } }); @@ -411,7 +437,8 @@ //default config EventBus.DEFAULT = EventBusClass.DEFAULT = { SHOW_LOG: false, - EVENT_TYPE_SPLIT_EXP: /,|\s/ + EVENT_TYPE_SPLIT_EXP: /,|\s/, + ERROR_EVENT_TYPE: "EMIT_ERROR" }; return EventBus; }); \ No newline at end of file From 1b18304a0a1248eaf734778f1faa27090524c24f Mon Sep 17 00:00:00 2001 From: tony_shen Date: Tue, 20 Dec 2016 10:12:26 +0800 Subject: [PATCH 12/20] add isStop method for Event Object --- lib/eventbus.min.js | 2 +- src/EventBus.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/eventbus.min.js b/lib/eventbus.min.js index fe641a4..e85578c 100644 --- a/lib/eventbus.min.js +++ b/lib/eventbus.min.js @@ -1 +1 @@ -(function(a,b){if(typeof exports==="object"&&typeof module==="object"){module.exports=b()}else{if(typeof define==="function"&&define.amd){define("EventBus",[],b)}else{if(typeof exports==="object"){exports.EventBus=b()}else{a.EventBus=b()}}}})(this,function(){function d(k,j){k=k||[];var h={stop:function(i){this.isStopped=true;this.result=i},isStopped:false,result:undefined};for(var g in k){j(g,k[g],k,h);if(h.isStopped){break}}if(h.isStopped){return h.result}}function f(i,h,g){if(h>i.length){return[]}return[].slice.call(i,h===undefined?0:h,g===undefined?i.length:g)||[]}function b(k,h,j,g){if(typeof j=="string"||j instanceof Array){var i=j;if(typeof j=="string"){i=j.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(i.length>1){d(i,function(l,m){g[0]=m;h.apply(k,g)});return k}else{j=i[0]}}return j}var c=(function(){var g=1000;return function(){return ++g}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(j,m,i){j=b(this,this.on,j,f(arguments));if(j==this){return this}var l=j instanceof RegExp;var h=l?j.toString():j;var g=f(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",g)}var k={id:c(),scope:i||{},callback:m,args:g,regExp:j,eventType:h};if(!l){if(typeof this.listeners[h]!="undefined"){this.listeners[h].push(k)}else{this.listeners[h]=[k]}}else{this.regexListeners.push(k)}return this},once:function(k,l,j){var g=this;var h=function(m){l.apply(this,f(arguments));g.off(k,h,j)};var i=f(arguments);i[1]=h;return g.on.apply(g,i)},off:function(k,l,o){k=b(this,this.off,k,[undefined,l,o]);if(k==this){return this}var i=k instanceof RegExp;var h=i?k.toString():k;var m=[];if(typeof l=="object"){o=l;l=undefined}var j=l==undefined;var n=o==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",k," all callback:",j," all scope:",n)}function g(p){return(j?true:p.callback==l)&&(n?true:p.scope==o)}if(!i){if(typeof this.listeners[h]!="undefined"){if(!(j&&n)){d(this.listeners[h],function(p,q){if(!g(q)){m.push(q)}else{}})}this.listeners[h]=m}}else{d(this.regexListeners,function(p,q){if(!(q.eventType===h&&g(q))){m.push(q)}else{}});this.regexListeners=m}return this},redirect:function(h,k,l,j){var g=this;if(h==undefined||k==undefined||h==k){return g}var i=this.redirectScope=this.redirectScope||{};j=typeof j=="function"?j:function(m){m.setEmitArgs(a.slice(arguments,1))};this.on(h,(function(p,q,n){if(q==undefined){q=function(){return true}}if(q instanceof RegExp){var o=q;q=function(r){return o.test(r.type)}}if(typeof q=="function"){var m=[];return function(t){var r=f(arguments);if(q.apply(i,r)){var s=typeof p=="function"?p.apply(i,r):p;if(m.indexOf(n)<0&&s!=t.type&&s!=undefined){m.push(n);try{if(typeof s=="string"){s=s.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(!(s instanceof Array)){s=[s]}d(s,function(u,w){if(w!=t.type){var v=f([].concat(r),1);t.setEmitArgs=function(x){v=x};t.getEmitArgs=function(){return[].concat(v)};t.getOriginType=function(){return h};t.getEndpoint=function(){return w};t.endpoints=t.endpoints||[];t.endpoints.push(w);j.apply(i,r);v=(v instanceof Array)?[""].concat(v):[].concat(r);v[0]=w;if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect id:",t.id," origin:",h," ==> endpoint:",w)}g.emit.apply(g,v)}})}finally{m.pop()}}else{throw"redirect origin:"+h.toString()+" => endpoint:"+p.toString()+" is looping!"}}}}else{return function(r){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(k,l,c()),i);return g},flow:function(h){var i=f(arguments);if(h instanceof Array){i=h}var g=this;d(i,function(j,k){if(k instanceof Object&&typeof k=="object"&&k.from!=undefined&&k.to!=undefined){g.redirect(k.from,k.to,k.where,k.processor)}});return g},has:function(k,n,j){var m=k instanceof RegExp;var h=m?k.toString():k;var i=[].concat(this.listeners[h]);if(typeof n=="object"){j=n;n=undefined}if(i.length>0&&!m){var l=i.length;if(n===undefined&&j===undefined){return l>0}var g=d(i,function(o,q,r,p){if((j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}else{if(m){i=[].concat(this.regexListeners);var g=d(i,function(o,q,r,p){if(q.regExp.toString()==h&&(j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}}return false},emit:function(l){var h=this.eventFlow=this.eventFlow||[];var i=f(arguments);l=b(this,this.emit,l,i);if(l==this){return this}var m={id:l+"#"+c(),type:l,target:i.length>1?i[1]:{}};i=[m].concat(f(arguments,1));var k=[].concat(typeof this.listeners[l]=="undefined"?[]:this.listeners[l]);var g=this;function n(q){var o=[].concat(h);var p=false;m.stop=function(){p=true};m.getArg=function(r){if(m.args==undefined||!m.args instanceof Array||m.args.length-1event listener call arguments:",v)}m.args=[].concat(w.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",w)}try{w.callback.apply(w.scope,v)}catch(s){p=true;g.emit(g.DEFAULT.ERROR_EVENT_TYPE,s,w,v)}if(p){t.stop()}}})}var j=[].concat(this.regexListeners);d(j,function(o,p){if(p.regExp.test(l)){k.push(p)}});h.push(m);n(k);h.pop();return this},getAllEvents:function(){var l="";for(var h in this.listeners){var k=this.listeners[h].length;for(var g=0;gi.length){return[]}return[].slice.call(i,h===undefined?0:h,g===undefined?i.length:g)||[]}function b(k,h,j,g){if(typeof j=="string"||j instanceof Array){var i=j;if(typeof j=="string"){i=j.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(i.length>1){d(i,function(l,m){g[0]=m;h.apply(k,g)});return k}else{j=i[0]}}return j}var c=(function(){var g=1000;return function(){return ++g}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(j,m,i){j=b(this,this.on,j,f(arguments));if(j==this){return this}var l=j instanceof RegExp;var h=l?j.toString():j;var g=f(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",g)}var k={id:c(),scope:i||{},callback:m,args:g,regExp:j,eventType:h};if(!l){if(typeof this.listeners[h]!="undefined"){this.listeners[h].push(k)}else{this.listeners[h]=[k]}}else{this.regexListeners.push(k)}return this},once:function(k,l,j){var g=this;var h=function(m){l.apply(this,f(arguments));g.off(k,h,j)};var i=f(arguments);i[1]=h;return g.on.apply(g,i)},off:function(k,l,o){k=b(this,this.off,k,[undefined,l,o]);if(k==this){return this}var i=k instanceof RegExp;var h=i?k.toString():k;var m=[];if(typeof l=="object"){o=l;l=undefined}var j=l==undefined;var n=o==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",k," all callback:",j," all scope:",n)}function g(p){return(j?true:p.callback==l)&&(n?true:p.scope==o)}if(!i){if(typeof this.listeners[h]!="undefined"){if(!(j&&n)){d(this.listeners[h],function(p,q){if(!g(q)){m.push(q)}else{}})}this.listeners[h]=m}}else{d(this.regexListeners,function(p,q){if(!(q.eventType===h&&g(q))){m.push(q)}else{}});this.regexListeners=m}return this},redirect:function(h,k,l,j){var g=this;if(h==undefined||k==undefined||h==k){return g}var i=this.redirectScope=this.redirectScope||{};j=typeof j=="function"?j:function(m){m.setEmitArgs(a.slice(arguments,1))};this.on(h,(function(p,q,n){if(q==undefined){q=function(){return true}}if(q instanceof RegExp){var o=q;q=function(r){return o.test(r.type)}}if(typeof q=="function"){var m=[];return function(t){var r=f(arguments);if(q.apply(i,r)){var s=typeof p=="function"?p.apply(i,r):p;if(m.indexOf(n)<0&&s!=t.type&&s!=undefined){m.push(n);try{if(typeof s=="string"){s=s.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(!(s instanceof Array)){s=[s]}d(s,function(u,x,y,w){if(x!=t.type){var v=f([].concat(r),1);t.setEmitArgs=function(z){v=z};t.getEmitArgs=function(){return[].concat(v)};t.getOriginType=function(){return h};t.getEndpoint=function(){return x};t.endpoints=t.endpoints||[];t.endpoints.push(x);j.apply(i,r);v=(v instanceof Array)?[""].concat(v):[].concat(r);v[0]=x;if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect id:",t.id," origin:",h," ==> endpoint:",x)}g.emit.apply(g,v);if(t.isStopped()){w.stop(true)}}})}finally{m.pop()}}else{throw"redirect origin:"+h.toString()+" => endpoint:"+p.toString()+" is looping!"}}}}else{return function(r){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(k,l,c()),i);return g},flow:function(h){var i=f(arguments);if(h instanceof Array){i=h}var g=this;d(i,function(j,k){if(k instanceof Object&&typeof k=="object"&&k.from!=undefined&&k.to!=undefined){g.redirect(k.from,k.to,k.where,k.processor)}});return g},has:function(k,n,j){var m=k instanceof RegExp;var h=m?k.toString():k;var i=[].concat(this.listeners[h]);if(typeof n=="object"){j=n;n=undefined}if(i.length>0&&!m){var l=i.length;if(n===undefined&&j===undefined){return l>0}var g=d(i,function(o,q,r,p){if((j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}else{if(m){i=[].concat(this.regexListeners);var g=d(i,function(o,q,r,p){if(q.regExp.toString()==h&&(j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}}return false},emit:function(l){var h=this.eventFlow=this.eventFlow||[];var i=f(arguments);l=b(this,this.emit,l,i);if(l==this){return this}var m={id:l+"#"+c(),type:l,target:i.length>1?i[1]:{}};i=[m].concat(f(arguments,1));var k=[].concat(typeof this.listeners[l]=="undefined"?[]:this.listeners[l]);var g=this;function n(q){var o=[].concat(h);var p=false;m.stop=function(){p=true};m.isStopped=function(){return p};m.getArg=function(r){if(m.args==undefined||!m.args instanceof Array||m.args.length-1event listener call arguments:",v)}m.args=[].concat(w.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",w)}try{w.callback.apply(w.scope,v)}catch(s){p=true;g.emit(g.DEFAULT.ERROR_EVENT_TYPE,s,w,v)}if(p){t.stop()}}})}var j=[].concat(this.regexListeners);d(j,function(o,p){if(p.regExp.test(l)){k.push(p)}});h.push(m);n(k);h.pop();return this},getAllEvents:function(){var l="";for(var h in this.listeners){var k=this.listeners[h].length;for(var g=0;gredirect id:", event.id, " origin:", origin, " ==> endpoint:", type); bus.emit.apply(bus, emitArgs);//dispatch endpoint event + if (event.isStopped()) iterator.stop(true); } } ); @@ -354,6 +355,9 @@ event.stop = function () { isStop = true; }; + event.isStopped = function () { + return isStop; + }; event.getArg = function (index) { if (event.args == undefined || !event.args instanceof Array || event.args.length - 1 < index)return undefined; return event.args[index]; From 4d4f39621ca8808627b7e86ca59f816d04f0ec47 Mon Sep 17 00:00:00 2001 From: tony_shen Date: Tue, 20 Dec 2016 10:28:33 +0800 Subject: [PATCH 13/20] add flow & event object usage --- README.md | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/README.md b/README.md index 5d6ed1d..6b28635 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,17 @@ EventBus.redirect(origin,endpoint,condition); EventBus.redirect(origin,endpoint,condition,processor); +``` +### flow +```javascript +EventBus.flow({from:'click',to:'onClick'}); +EventBus.flow({from:'click',to:'onClick'},{from:'onClick',to:'labelClick'}); +EventBus.flow({from:'click',to:'onClick'},{from:'onClick',to:'labelClick',processor:function(event) { + event.setEmitArgs(EventBus.slice(arguments,1)); +}}); +EventBus.flow({from:'click',to:'onClick'},{from:'onClick',to:'labelClick',where:function(event) { + return event.getLevel()>0;//only receive redirect +}}); ``` ### `getEvents` @@ -223,4 +234,56 @@ EventBus.on("ready",t1.doSomething,t1); t2.ready(); +``` +## Example of usage EventBus.flow +**flow** method like **redirect**,this method objective for quick and intuitive configuration event flow. +```javascript + +EventBus.on("start",function(event) { + console.log("The game is start..."); + }) + .on("chase",function(event) { + console.log("overtaken"); + EventBus.emit("overtaken"); + }) + .flow( + {from:"ready",to:"start"}, + {from:"start",to:"take-flight"},{from:"start",to:"chase"}, + {from:"overtaken",to:"end"} ) + .on("end",function(event) { + console.log("The game is end."); + }); + +EventBus.emit("ready"); + +``` + +## Example of Error event handling +focus all error event handling. +```javascript +EventBus.on(EventBus.DEFAULT.ERROR_EVENT_TYPE,function(event,error,listener,triggerArguments) { + console.log(error); +}); + +EventBus.on("click",function(event) { + throw "We are not ready!"; +}); + +EventBus.emit("click"); +``` + +## Example of usage event object +For debugging purpose, print event objects tree. +```javascript +EventBus.redirect("click","onClick"); +EventBus.on("onClick",function(event) { + var e = event; + while(e){ + console.log(e.getLevel()," event id:",e.id," event object:",e); + e.stop(); // stop event dispatch. + e = e.flow.getClosestEvent();//get prior event. + } +}); + +EventBus.emit("click"); ``` \ No newline at end of file From ce688f069e6444d1b0047c331d5adb2ebde568c4 Mon Sep 17 00:00:00 2001 From: tony_shen Date: Tue, 20 Dec 2016 11:39:32 +0800 Subject: [PATCH 14/20] add getEventIdsPath to Event Object --- README.md | 8 ++++++++ example/node/flow-test.js | 30 ++++++++++++++++++++++++++++++ lib/eventbus.min.js | 2 +- src/EventBus.js | 7 +++++++ 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 example/node/flow-test.js diff --git a/README.md b/README.md index 6b28635..e062a5d 100644 --- a/README.md +++ b/README.md @@ -239,11 +239,18 @@ t2.ready(); **flow** method like **redirect**,this method objective for quick and intuitive configuration event flow. ```javascript +var printEventStack = function (event) { + var p = event; + console.log("==>current stage:",event.type," event id:",event.id); + console.log("event flow :",event.flow.getEventIdsPath()); +}; + EventBus.on("start",function(event) { console.log("The game is start..."); }) .on("chase",function(event) { console.log("overtaken"); + printEventStack(event);//event flow : ready#1012==>start#1013==>chase#1015 EventBus.emit("overtaken"); }) .flow( @@ -251,6 +258,7 @@ EventBus.on("start",function(event) { {from:"start",to:"take-flight"},{from:"start",to:"chase"}, {from:"overtaken",to:"end"} ) .on("end",function(event) { + printEventStack(event);//event flow : ready#1012==>start#1013==>chase#1015==>overtaken#1016==>end#1017 console.log("The game is end."); }); diff --git a/example/node/flow-test.js b/example/node/flow-test.js new file mode 100644 index 0000000..0781de1 --- /dev/null +++ b/example/node/flow-test.js @@ -0,0 +1,30 @@ +/** + * Created by bona on 2016/12/20. + */ + +var EventBus = require('../../lib/eventbus.min'); + +var printEventStack = function (event) { + var p = event; + console.log("==>current stage:",event.type," event id:",event.id); + console.log("event flow :",event.flow.getEventIdsPath()); +}; + +EventBus.on("start",function(event) { + console.log("The game is start..."); +}) + .on("chase",function(event) { + console.log("overtaken"); + printEventStack(event); + EventBus.emit("overtaken"); + }) + .flow( + {from:"ready",to:"start"}, + {from:"start",to:"take-flight"},{from:"start",to:"chase"}, + {from:"overtaken",to:"end"} ) + .on("end",function(event) { + console.log("The game is end."); + printEventStack(event); + }); + +EventBus.emit("ready"); \ No newline at end of file diff --git a/lib/eventbus.min.js b/lib/eventbus.min.js index e85578c..c5196c0 100644 --- a/lib/eventbus.min.js +++ b/lib/eventbus.min.js @@ -1 +1 @@ -(function(a,b){if(typeof exports==="object"&&typeof module==="object"){module.exports=b()}else{if(typeof define==="function"&&define.amd){define("EventBus",[],b)}else{if(typeof exports==="object"){exports.EventBus=b()}else{a.EventBus=b()}}}})(this,function(){function d(k,j){k=k||[];var h={stop:function(i){this.isStopped=true;this.result=i},isStopped:false,result:undefined};for(var g in k){j(g,k[g],k,h);if(h.isStopped){break}}if(h.isStopped){return h.result}}function f(i,h,g){if(h>i.length){return[]}return[].slice.call(i,h===undefined?0:h,g===undefined?i.length:g)||[]}function b(k,h,j,g){if(typeof j=="string"||j instanceof Array){var i=j;if(typeof j=="string"){i=j.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(i.length>1){d(i,function(l,m){g[0]=m;h.apply(k,g)});return k}else{j=i[0]}}return j}var c=(function(){var g=1000;return function(){return ++g}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(j,m,i){j=b(this,this.on,j,f(arguments));if(j==this){return this}var l=j instanceof RegExp;var h=l?j.toString():j;var g=f(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",g)}var k={id:c(),scope:i||{},callback:m,args:g,regExp:j,eventType:h};if(!l){if(typeof this.listeners[h]!="undefined"){this.listeners[h].push(k)}else{this.listeners[h]=[k]}}else{this.regexListeners.push(k)}return this},once:function(k,l,j){var g=this;var h=function(m){l.apply(this,f(arguments));g.off(k,h,j)};var i=f(arguments);i[1]=h;return g.on.apply(g,i)},off:function(k,l,o){k=b(this,this.off,k,[undefined,l,o]);if(k==this){return this}var i=k instanceof RegExp;var h=i?k.toString():k;var m=[];if(typeof l=="object"){o=l;l=undefined}var j=l==undefined;var n=o==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",k," all callback:",j," all scope:",n)}function g(p){return(j?true:p.callback==l)&&(n?true:p.scope==o)}if(!i){if(typeof this.listeners[h]!="undefined"){if(!(j&&n)){d(this.listeners[h],function(p,q){if(!g(q)){m.push(q)}else{}})}this.listeners[h]=m}}else{d(this.regexListeners,function(p,q){if(!(q.eventType===h&&g(q))){m.push(q)}else{}});this.regexListeners=m}return this},redirect:function(h,k,l,j){var g=this;if(h==undefined||k==undefined||h==k){return g}var i=this.redirectScope=this.redirectScope||{};j=typeof j=="function"?j:function(m){m.setEmitArgs(a.slice(arguments,1))};this.on(h,(function(p,q,n){if(q==undefined){q=function(){return true}}if(q instanceof RegExp){var o=q;q=function(r){return o.test(r.type)}}if(typeof q=="function"){var m=[];return function(t){var r=f(arguments);if(q.apply(i,r)){var s=typeof p=="function"?p.apply(i,r):p;if(m.indexOf(n)<0&&s!=t.type&&s!=undefined){m.push(n);try{if(typeof s=="string"){s=s.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(!(s instanceof Array)){s=[s]}d(s,function(u,x,y,w){if(x!=t.type){var v=f([].concat(r),1);t.setEmitArgs=function(z){v=z};t.getEmitArgs=function(){return[].concat(v)};t.getOriginType=function(){return h};t.getEndpoint=function(){return x};t.endpoints=t.endpoints||[];t.endpoints.push(x);j.apply(i,r);v=(v instanceof Array)?[""].concat(v):[].concat(r);v[0]=x;if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect id:",t.id," origin:",h," ==> endpoint:",x)}g.emit.apply(g,v);if(t.isStopped()){w.stop(true)}}})}finally{m.pop()}}else{throw"redirect origin:"+h.toString()+" => endpoint:"+p.toString()+" is looping!"}}}}else{return function(r){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(k,l,c()),i);return g},flow:function(h){var i=f(arguments);if(h instanceof Array){i=h}var g=this;d(i,function(j,k){if(k instanceof Object&&typeof k=="object"&&k.from!=undefined&&k.to!=undefined){g.redirect(k.from,k.to,k.where,k.processor)}});return g},has:function(k,n,j){var m=k instanceof RegExp;var h=m?k.toString():k;var i=[].concat(this.listeners[h]);if(typeof n=="object"){j=n;n=undefined}if(i.length>0&&!m){var l=i.length;if(n===undefined&&j===undefined){return l>0}var g=d(i,function(o,q,r,p){if((j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}else{if(m){i=[].concat(this.regexListeners);var g=d(i,function(o,q,r,p){if(q.regExp.toString()==h&&(j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}}return false},emit:function(l){var h=this.eventFlow=this.eventFlow||[];var i=f(arguments);l=b(this,this.emit,l,i);if(l==this){return this}var m={id:l+"#"+c(),type:l,target:i.length>1?i[1]:{}};i=[m].concat(f(arguments,1));var k=[].concat(typeof this.listeners[l]=="undefined"?[]:this.listeners[l]);var g=this;function n(q){var o=[].concat(h);var p=false;m.stop=function(){p=true};m.isStopped=function(){return p};m.getArg=function(r){if(m.args==undefined||!m.args instanceof Array||m.args.length-1event listener call arguments:",v)}m.args=[].concat(w.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",w)}try{w.callback.apply(w.scope,v)}catch(s){p=true;g.emit(g.DEFAULT.ERROR_EVENT_TYPE,s,w,v)}if(p){t.stop()}}})}var j=[].concat(this.regexListeners);d(j,function(o,p){if(p.regExp.test(l)){k.push(p)}});h.push(m);n(k);h.pop();return this},getAllEvents:function(){var l="";for(var h in this.listeners){var k=this.listeners[h].length;for(var g=0;gi.length){return[]}return[].slice.call(i,h===undefined?0:h,g===undefined?i.length:g)||[]}function b(k,h,j,g){if(typeof j=="string"||j instanceof Array){var i=j;if(typeof j=="string"){i=j.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(i.length>1){d(i,function(l,m){g[0]=m;h.apply(k,g)});return k}else{j=i[0]}}return j}var c=(function(){var g=1000;return function(){return ++g}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(j,m,i){j=b(this,this.on,j,f(arguments));if(j==this){return this}var l=j instanceof RegExp;var h=l?j.toString():j;var g=f(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",g)}var k={id:c(),scope:i||{},callback:m,args:g,regExp:j,eventType:h};if(!l){if(typeof this.listeners[h]!="undefined"){this.listeners[h].push(k)}else{this.listeners[h]=[k]}}else{this.regexListeners.push(k)}return this},once:function(k,l,j){var g=this;var h=function(m){l.apply(this,f(arguments));g.off(k,h,j)};var i=f(arguments);i[1]=h;return g.on.apply(g,i)},off:function(k,l,o){k=b(this,this.off,k,[undefined,l,o]);if(k==this){return this}var i=k instanceof RegExp;var h=i?k.toString():k;var m=[];if(typeof l=="object"){o=l;l=undefined}var j=l==undefined;var n=o==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",k," all callback:",j," all scope:",n)}function g(p){return(j?true:p.callback==l)&&(n?true:p.scope==o)}if(!i){if(typeof this.listeners[h]!="undefined"){if(!(j&&n)){d(this.listeners[h],function(p,q){if(!g(q)){m.push(q)}else{}})}this.listeners[h]=m}}else{d(this.regexListeners,function(p,q){if(!(q.eventType===h&&g(q))){m.push(q)}else{}});this.regexListeners=m}return this},redirect:function(h,k,l,j){var g=this;if(h==undefined||k==undefined||h==k){return g}var i=this.redirectScope=this.redirectScope||{};j=typeof j=="function"?j:function(m){m.setEmitArgs(a.slice(arguments,1))};this.on(h,(function(p,q,n){if(q==undefined){q=function(){return true}}if(q instanceof RegExp){var o=q;q=function(r){return o.test(r.type)}}if(typeof q=="function"){var m=[];return function(t){var r=f(arguments);if(q.apply(i,r)){var s=typeof p=="function"?p.apply(i,r):p;if(m.indexOf(n)<0&&s!=t.type&&s!=undefined){m.push(n);try{if(typeof s=="string"){s=s.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(!(s instanceof Array)){s=[s]}d(s,function(u,x,y,w){if(x!=t.type){var v=f([].concat(r),1);t.setEmitArgs=function(z){v=z};t.getEmitArgs=function(){return[].concat(v)};t.getOriginType=function(){return h};t.getEndpoint=function(){return x};t.endpoints=t.endpoints||[];t.endpoints.push(x);j.apply(i,r);v=(v instanceof Array)?[""].concat(v):[].concat(r);v[0]=x;if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect id:",t.id," origin:",h," ==> endpoint:",x)}g.emit.apply(g,v);if(t.isStopped()){w.stop(true)}}})}finally{m.pop()}}else{throw"redirect origin:"+h.toString()+" => endpoint:"+p.toString()+" is looping!"}}}}else{return function(r){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(k,l,c()),i);return g},flow:function(h){var i=f(arguments);if(h instanceof Array){i=h}var g=this;d(i,function(j,k){if(k instanceof Object&&typeof k=="object"&&k.from!=undefined&&k.to!=undefined){g.redirect(k.from,k.to,k.where,k.processor)}});return g},has:function(k,n,j){var m=k instanceof RegExp;var h=m?k.toString():k;var i=[].concat(this.listeners[h]);if(typeof n=="object"){j=n;n=undefined}if(i.length>0&&!m){var l=i.length;if(n===undefined&&j===undefined){return l>0}var g=d(i,function(o,q,r,p){if((j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}else{if(m){i=[].concat(this.regexListeners);var g=d(i,function(o,q,r,p){if(q.regExp.toString()==h&&(j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}}return false},emit:function(l){var h=this.eventFlow=this.eventFlow||[];var i=f(arguments);l=b(this,this.emit,l,i);if(l==this){return this}var m={id:l+"#"+c(),type:l,target:i.length>1?i[1]:{}};i=[m].concat(f(arguments,1));var k=[].concat(typeof this.listeners[l]=="undefined"?[]:this.listeners[l]);var g=this;function n(q){var o=[].concat(h);var p=false;m.stop=function(){p=true};m.isStopped=function(){return p};m.getArg=function(r){if(m.args==undefined||!m.args instanceof Array||m.args.length-1")}};m.getLevel=function(){return o.length-1};d(q,function(r,w,u,t){if(w&&w.callback){var v=[].concat(i);if(e.DEFAULT.SHOW_LOG){console.log("emit=>event listener call arguments:",v)}m.args=[].concat(w.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",w)}try{if(e.DEFAULT.SHOW_LOG){console.log("event flow:",m.flow.getEventIdsPath())}w.callback.apply(w.scope,v)}catch(s){p=true;g.emit(g.DEFAULT.ERROR_EVENT_TYPE,s,w,v)}if(p){t.stop()}}})}var j=[].concat(this.regexListeners);d(j,function(o,p){if(p.regExp.test(l)){k.push(p)}});h.push(m);n(k);h.pop();return this},getAllEvents:function(){var l="";for(var h in this.listeners){var k=this.listeners[h].length;for(var g=0;g"); } }; @@ -387,6 +392,8 @@ if (EventBusClass.DEFAULT.SHOW_LOG) console.log("emit=>fire event listener:", listener); try { + if(EventBusClass.DEFAULT.SHOW_LOG) + console.log("event flow:",event.flow.getEventIdsPath()); listener.callback.apply(listener.scope, listenerArgs); } catch (exception) { isStop = true; From 1ab14d4052610c8bc04198df5502dc825af52673 Mon Sep 17 00:00:00 2001 From: tony_shen Date: Sat, 24 Dec 2016 17:33:33 +0800 Subject: [PATCH 15/20] add plugin method --- example/node/flow-test.js | 8 +- lib/eventbus.min.js | 2 +- src/EventBus.js | 303 +++++++++++++++++++++----------------- 3 files changed, 173 insertions(+), 140 deletions(-) diff --git a/example/node/flow-test.js b/example/node/flow-test.js index 0781de1..cb7dd91 100644 --- a/example/node/flow-test.js +++ b/example/node/flow-test.js @@ -2,7 +2,7 @@ * Created by bona on 2016/12/20. */ -var EventBus = require('../../lib/eventbus.min'); +var ebus = require('../../lib/eventbus.min'); var printEventStack = function (event) { var p = event; @@ -10,13 +10,13 @@ var printEventStack = function (event) { console.log("event flow :",event.flow.getEventIdsPath()); }; -EventBus.on("start",function(event) { +ebus.on("start",function(event) { console.log("The game is start..."); }) .on("chase",function(event) { console.log("overtaken"); printEventStack(event); - EventBus.emit("overtaken"); + ebus.emit("overtaken"); }) .flow( {from:"ready",to:"start"}, @@ -27,4 +27,4 @@ EventBus.on("start",function(event) { printEventStack(event); }); -EventBus.emit("ready"); \ No newline at end of file +ebus("ready"); \ No newline at end of file diff --git a/lib/eventbus.min.js b/lib/eventbus.min.js index c5196c0..2908d01 100644 --- a/lib/eventbus.min.js +++ b/lib/eventbus.min.js @@ -1 +1 @@ -(function(a,b){if(typeof exports==="object"&&typeof module==="object"){module.exports=b()}else{if(typeof define==="function"&&define.amd){define("EventBus",[],b)}else{if(typeof exports==="object"){exports.EventBus=b()}else{a.EventBus=b()}}}})(this,function(){function d(k,j){k=k||[];var h={stop:function(i){this.isStopped=true;this.result=i},isStopped:false,result:undefined};for(var g in k){j(g,k[g],k,h);if(h.isStopped){break}}if(h.isStopped){return h.result}}function f(i,h,g){if(h>i.length){return[]}return[].slice.call(i,h===undefined?0:h,g===undefined?i.length:g)||[]}function b(k,h,j,g){if(typeof j=="string"||j instanceof Array){var i=j;if(typeof j=="string"){i=j.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(i.length>1){d(i,function(l,m){g[0]=m;h.apply(k,g)});return k}else{j=i[0]}}return j}var c=(function(){var g=1000;return function(){return ++g}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(j,m,i){j=b(this,this.on,j,f(arguments));if(j==this){return this}var l=j instanceof RegExp;var h=l?j.toString():j;var g=f(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",g)}var k={id:c(),scope:i||{},callback:m,args:g,regExp:j,eventType:h};if(!l){if(typeof this.listeners[h]!="undefined"){this.listeners[h].push(k)}else{this.listeners[h]=[k]}}else{this.regexListeners.push(k)}return this},once:function(k,l,j){var g=this;var h=function(m){l.apply(this,f(arguments));g.off(k,h,j)};var i=f(arguments);i[1]=h;return g.on.apply(g,i)},off:function(k,l,o){k=b(this,this.off,k,[undefined,l,o]);if(k==this){return this}var i=k instanceof RegExp;var h=i?k.toString():k;var m=[];if(typeof l=="object"){o=l;l=undefined}var j=l==undefined;var n=o==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",k," all callback:",j," all scope:",n)}function g(p){return(j?true:p.callback==l)&&(n?true:p.scope==o)}if(!i){if(typeof this.listeners[h]!="undefined"){if(!(j&&n)){d(this.listeners[h],function(p,q){if(!g(q)){m.push(q)}else{}})}this.listeners[h]=m}}else{d(this.regexListeners,function(p,q){if(!(q.eventType===h&&g(q))){m.push(q)}else{}});this.regexListeners=m}return this},redirect:function(h,k,l,j){var g=this;if(h==undefined||k==undefined||h==k){return g}var i=this.redirectScope=this.redirectScope||{};j=typeof j=="function"?j:function(m){m.setEmitArgs(a.slice(arguments,1))};this.on(h,(function(p,q,n){if(q==undefined){q=function(){return true}}if(q instanceof RegExp){var o=q;q=function(r){return o.test(r.type)}}if(typeof q=="function"){var m=[];return function(t){var r=f(arguments);if(q.apply(i,r)){var s=typeof p=="function"?p.apply(i,r):p;if(m.indexOf(n)<0&&s!=t.type&&s!=undefined){m.push(n);try{if(typeof s=="string"){s=s.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(!(s instanceof Array)){s=[s]}d(s,function(u,x,y,w){if(x!=t.type){var v=f([].concat(r),1);t.setEmitArgs=function(z){v=z};t.getEmitArgs=function(){return[].concat(v)};t.getOriginType=function(){return h};t.getEndpoint=function(){return x};t.endpoints=t.endpoints||[];t.endpoints.push(x);j.apply(i,r);v=(v instanceof Array)?[""].concat(v):[].concat(r);v[0]=x;if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect id:",t.id," origin:",h," ==> endpoint:",x)}g.emit.apply(g,v);if(t.isStopped()){w.stop(true)}}})}finally{m.pop()}}else{throw"redirect origin:"+h.toString()+" => endpoint:"+p.toString()+" is looping!"}}}}else{return function(r){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(k,l,c()),i);return g},flow:function(h){var i=f(arguments);if(h instanceof Array){i=h}var g=this;d(i,function(j,k){if(k instanceof Object&&typeof k=="object"&&k.from!=undefined&&k.to!=undefined){g.redirect(k.from,k.to,k.where,k.processor)}});return g},has:function(k,n,j){var m=k instanceof RegExp;var h=m?k.toString():k;var i=[].concat(this.listeners[h]);if(typeof n=="object"){j=n;n=undefined}if(i.length>0&&!m){var l=i.length;if(n===undefined&&j===undefined){return l>0}var g=d(i,function(o,q,r,p){if((j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}else{if(m){i=[].concat(this.regexListeners);var g=d(i,function(o,q,r,p){if(q.regExp.toString()==h&&(j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}}return false},emit:function(l){var h=this.eventFlow=this.eventFlow||[];var i=f(arguments);l=b(this,this.emit,l,i);if(l==this){return this}var m={id:l+"#"+c(),type:l,target:i.length>1?i[1]:{}};i=[m].concat(f(arguments,1));var k=[].concat(typeof this.listeners[l]=="undefined"?[]:this.listeners[l]);var g=this;function n(q){var o=[].concat(h);var p=false;m.stop=function(){p=true};m.isStopped=function(){return p};m.getArg=function(r){if(m.args==undefined||!m.args instanceof Array||m.args.length-1")}};m.getLevel=function(){return o.length-1};d(q,function(r,w,u,t){if(w&&w.callback){var v=[].concat(i);if(e.DEFAULT.SHOW_LOG){console.log("emit=>event listener call arguments:",v)}m.args=[].concat(w.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",w)}try{if(e.DEFAULT.SHOW_LOG){console.log("event flow:",m.flow.getEventIdsPath())}w.callback.apply(w.scope,v)}catch(s){p=true;g.emit(g.DEFAULT.ERROR_EVENT_TYPE,s,w,v)}if(p){t.stop()}}})}var j=[].concat(this.regexListeners);d(j,function(o,p){if(p.regExp.test(l)){k.push(p)}});h.push(m);n(k);h.pop();return this},getAllEvents:function(){var l="";for(var h in this.listeners){var k=this.listeners[h].length;for(var g=0;gk.length){return[]}return[].slice.call(k,j===undefined?0:j,i===undefined?k.length:i)||[]}function b(m,j,l,i){if(typeof l=="string"||l instanceof Array){var k=l;if(typeof l=="string"){k=l.trim().split(f.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(k.length>1){e(k,function(n,o){i[0]=o;j.apply(m,i)});return m}else{l=k[0]}}return l}var d=(function(){var i=1000;return function(){return ++i}})();var f={};f=function(){this.listeners={};this.regexListeners=[]};f.prototype={on:function(l,o,k){l=b(this,this.on,l,h(arguments));if(l==this){return this}var n=l instanceof RegExp;var j=n?l.toString():l;var i=h(arguments);if(f.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",i)}var m={id:d(),scope:k||{},callback:o,args:i,regExp:l,eventType:j};if(!n){if(typeof this.listeners[j]!="undefined"){this.listeners[j].push(m)}else{this.listeners[j]=[m]}}else{this.regexListeners.push(m)}return this},off:function(m,n,q){m=b(this,this.off,m,[undefined,n,q]);if(m==this){return this}var k=m instanceof RegExp;var j=k?m.toString():m;var o=[];if(typeof n=="object"){q=n;n=undefined}var l=n==undefined;var p=q==undefined;if(f.DEFAULT.SHOW_LOG){console.log("off=>off event type:",m," all callback:",l," all scope:",p)}function i(r){return(l?true:r.callback==n)&&(p?true:r.scope==q)}if(!k){if(typeof this.listeners[j]!="undefined"){if(!(l&&p)){e(this.listeners[j],function(r,s){if(!i(s)){o.push(s)}else{}})}this.listeners[j]=o}}else{e(this.regexListeners,function(r,s){if(!(s.eventType===j&&i(s))){o.push(s)}else{}});this.regexListeners=o}return this},has:function(m,p,l){var o=m instanceof RegExp;var j=o?m.toString():m;var k=[].concat(this.listeners[j]);if(typeof p=="object"){l=p;p=undefined}if(k.length>0&&!o){var n=k.length;if(p===undefined&&l===undefined){return n>0}var i=e(k,function(q,s,t,r){if((l?s.scope==l:true)&&(p?s.callback==p:true)){r.stop(true)}});if(i){return true}}else{if(o){k=[].concat(this.regexListeners);var i=e(k,function(q,s,t,r){if(s.regExp.toString()==j&&(l?s.scope==l:true)&&(p?s.callback==p:true)){r.stop(true)}});if(i){return true}}}return false},emit:function(n){var j=this.eventFlow=this.eventFlow||[];var k=h(arguments);n=b(this,this.emit,n,k);if(n==this){return this}var o={id:n+"#"+d(),type:n,target:k.length>1?k[1]:{}};k=[o].concat(h(arguments,1));var m=[].concat(typeof this.listeners[n]=="undefined"?[]:this.listeners[n]);var i=this;function p(s){var q=[].concat(j);var r=false;o.stop=function(){r=true};o.isStopped=function(){return r};o.getArg=function(t){if(o.args==undefined||!o.args instanceof Array||o.args.length-1")}};o.getLevel=function(){return q.length-1};e(s,function(t,y,w,v){if(y&&y.callback){var x=[].concat(k);if(f.DEFAULT.SHOW_LOG){console.log("emit=>event listener call arguments:",x)}o.args=[].concat(y.args);if(f.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",y)}try{if(f.DEFAULT.SHOW_LOG){console.log("event flow:",o.flow.getEventIdsPath())}y.callback.apply(y.scope,x)}catch(u){r=true;i.emit(i.DEFAULT.ERROR_EVENT_TYPE,u,y,x)}if(r){v.stop()}}})}var l=[].concat(this.regexListeners);e(l,function(q,r){if(r.regExp.test(n)){m.push(r)}});j.push(o);p(m);j.pop();return this},getAllEvents:function(){var n="";for(var k in this.listeners){var m=this.listeners[k].length;for(var j=0;jredirect id:",w.id," origin:",k," ==> endpoint:",A)}j.emit.apply(j,y);if(w.isStopped()){z.stop(true)}}})}finally{p.pop()}}else{throw"redirect origin:"+k.toString()+" => endpoint:"+s.toString()+" is looping!"}}}}else{return function(u){if(f.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(n,o,d()),l);return j}});return a}); \ No newline at end of file diff --git a/src/EventBus.js b/src/EventBus.js index e584172..a7b1587 100644 --- a/src/EventBus.js +++ b/src/EventBus.js @@ -2,11 +2,11 @@ if (typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if (typeof define === 'function' && define.amd) - define("EventBus", [], factory); + define("ebus", [], factory); else if (typeof exports === 'object') - exports["EventBus"] = factory(); + exports["ebus"] = factory(); else - root["EventBus"] = factory(); + root["ebus"] = factory(); })(this, function () { function iterator(array, callback) { @@ -99,24 +99,6 @@ this.regexListeners.push(listener); return this; }, - /** - * EventBus.once("click",callback); - * EventBus.once("click",callback,buttonScope); - * @param type - * @param callback - * @param scope - * @returns {EventBusClass} - */ - once: function (type, callback, scope) { - var bus = this; - var proxyCallback = function (event) { - callback.apply(this, slice(arguments)); - bus.off(type, proxyCallback, scope); - }; - var args = slice(arguments); - args[1] = proxyCallback; - return bus.on.apply(bus, args); - }, /** * EventBus.off("click"); //remove all click listeners * EventBus.off("click",onClick); @@ -172,117 +154,6 @@ } return this; }, - /** - * redirect("click","onClick",function(event){return true;}); - * redirect("click","onClick"); - * redirect("click",function(event){return "onClick"},function(event){return true;}); - * redirect(/\w*_click/,"onClick",/btn[0-9]+_click/); - * @param origin - * @param endpoint - * @param condition - * @param processor processor be called before event redirection - * @return {EventBusClass} - */ - redirect: function (origin, endpoint, condition, processor) { - var bus = this; - if (origin == undefined || endpoint == undefined || origin == endpoint)return bus; - - var scope = this.redirectScope = this.redirectScope || {}; - - processor = typeof processor == "function" ? processor : function (event) { - event.setEmitArgs(EventBus.slice(arguments, 1));//example: set emit endpoint event arguments - }; - this.on(origin, (function (endpoint, condition, nextId) {//Unified exception handling by emit method. - if (condition == undefined) - condition = function () { //default all origin event to endpoint event - return true; - }; - if (condition instanceof RegExp) {//support reg exp as condition - var exp = condition; - condition = function (event) { - return exp.test(event.type); - } - } - if (typeof condition == "function") { - var stack = []; - return function (event) {//trigger redirect - var args = slice(arguments); - if (condition.apply(scope, args)) {//trigger condition check - var eventType = typeof endpoint == "function" ? endpoint.apply(scope, args) : endpoint;//dynamic get endpoint - if (stack.indexOf(nextId) < 0 && eventType != event.type && eventType != undefined)//check redirect looping - { - stack.push(nextId); - try { - if (typeof eventType == "string") eventType = - eventType.trim().split(EventBusClass.DEFAULT.EVENT_TYPE_SPLIT_EXP);//support string split by SPACE,COMMA char - if (!(eventType instanceof Array)) { - eventType = [eventType]; - } - iterator(eventType, function (index, type, array, iterator) {//support endpoint array - if (type != event.type) { - var emitArgs = slice([].concat(args), 1); - event.setEmitArgs = function (args) { - emitArgs = args; - }; - event.getEmitArgs = function () { - return [].concat(emitArgs); - }; - event.getOriginType = function () { - return origin; - }; - event.getEndpoint = function () { - return type; - }; - event.endpoints = event.endpoints || []; - event.endpoints.push(type); - processor.apply(scope, args); - emitArgs = (emitArgs instanceof Array) ? [""].concat(emitArgs) : [].concat(args); - emitArgs[0] = type; - if (EventBusClass.DEFAULT.SHOW_LOG) - console.log("redirect=>redirect id:", event.id, " origin:", origin, " ==> endpoint:", type); - bus.emit.apply(bus, emitArgs);//dispatch endpoint event - if (event.isStopped()) iterator.stop(true); - } - } - ); - } finally { - stack.pop(); - } - } else { - throw "redirect origin:" + origin.toString() + " => endpoint:" + endpoint.toString() + - " is looping!"; - } - } - } - } - else { - return function (event) { - if (EventBusClass.DEFAULT.SHOW_LOG) - console.log("redirect=>redirect condition must set function or RegExp!") - } - } - })(endpoint, condition, nextId()), scope); - return bus; - }, - /** - * build event flow - * EventBus.flow({from:'click',to:'onClick'}) - * EventBus.flow({from:'ready',to:'start'},{from:'start',to:'end'}) - * EventBus.flow({from:'click',to:'onClick',where:function(event){event.getLevel()>1}}) - * @param node is event flow node map config,maybe node map array - * @return {EventBusClass} - */ - flow: function (node) { - var nodeMap = slice(arguments); - if (node instanceof Array) nodeMap = node; - var bus = this; - iterator(nodeMap, function (index, node) { - if (node instanceof Object && typeof node == "object" && node['from'] != undefined && node['to'] != undefined) { - bus.redirect(node['from'], node['to'], node['where'], node['processor']); - } - }); - return bus; - }, /** * EventBus.has("click") * EventBus.has("click",buttonScope); @@ -392,8 +263,8 @@ if (EventBusClass.DEFAULT.SHOW_LOG) console.log("emit=>fire event listener:", listener); try { - if(EventBusClass.DEFAULT.SHOW_LOG) - console.log("event flow:",event.flow.getEventIdsPath()); + if (EventBusClass.DEFAULT.SHOW_LOG) + console.log("event flow:", event.flow.getEventIdsPath()); listener.callback.apply(listener.scope, listenerArgs); } catch (exception) { isStop = true; @@ -440,7 +311,30 @@ EventBusClass.prototype.trigger = EventBusClass.prototype.dispatch = EventBusClass.prototype.emit; EventBusClass.prototype.hasEventListener = EventBusClass.prototype.has; - var EventBus = new EventBusClass(); + var _EventBus_ = new EventBusClass(); + + var EventBus = function (event) { + return _EventBus_.emit.apply(_EventBus_, slice(arguments)); + }; + + var makeProxy = function (object, fn) { + return function () { + return fn.apply(object, slice(arguments)); + } + }; + + iterator(EventBusClass.prototype, function (key, fn) { + if (fn && !EventBus["hasOwnProperty"](key) && typeof fn == "function") + EventBus[key] = makeProxy(_EventBus_, fn); + }); + + //support extend. + EventBus.fn = EventBusClass.prototype; + + EventBus.plugin = function (f) { + f(EventBus); + }; + //common utils EventBus.slice = slice; EventBus.nextId = nextId; @@ -451,5 +345,144 @@ EVENT_TYPE_SPLIT_EXP: /,|\s/, ERROR_EVENT_TYPE: "EMIT_ERROR" }; + + EventBus.plugin(function (eBus) { + /** + * EventBus.once("click",callback); + * EventBus.once("click",callback,buttonScope); + * @param type + * @param callback + * @param scope + * @returns {EventBusClass} + */ + eBus.fn.once = function (type, callback, scope) { + var bus = this; + var proxyCallback = function (event) { + callback.apply(this, slice(arguments)); + bus.off(type, proxyCallback, scope); + }; + var args = slice(arguments); + args[1] = proxyCallback; + return bus.on.apply(bus, args); + } + }); + + EventBus.plugin(function (eBus) { + /** + * build event flow + * EventBus.flow({from:'click',to:'onClick'}) + * EventBus.flow({from:'ready',to:'start'},{from:'start',to:'end'}) + * EventBus.flow({from:'click',to:'onClick',where:function(event){event.getLevel()>1}}) + * @param node is event flow node map config,maybe node map array + * @return {EventBusClass} + */ + eBus.fn.flow = function (node) { + var nodeMap = slice(arguments); + if (node instanceof Array) nodeMap = node; + var bus = this; + iterator(nodeMap, function (index, node) { + if (node instanceof Object && typeof node == "object" && node['from'] != undefined && node['to'] != undefined) { + bus.redirect(node['from'], node['to'], node['where'], node['processor']); + } + }); + return bus; + }; + }); + + EventBus.plugin(function (eBus) { + /** + * redirect("click","onClick",function(event){return true;}); + * redirect("click","onClick"); + * redirect("click",function(event){return "onClick"},function(event){return true;}); + * redirect(/\w*_click/,"onClick",/btn[0-9]+_click/); + * @param origin + * @param endpoint + * @param condition + * @param processor processor be called before event redirection + * @return {EventBusClass} + */ + eBus.fn.redirect = function (origin, endpoint, condition, processor) { + var bus = this; + if (origin == undefined || endpoint == undefined || origin == endpoint)return bus; + + var scope = this.redirectScope = this.redirectScope || {}; + + processor = typeof processor == "function" ? processor : function (event) { + event.setEmitArgs(EventBus.slice(arguments, 1));//example: set emit endpoint event arguments + }; + this.on(origin, (function (endpoint, condition, nextId) {//Unified exception handling by emit method. + if (condition == undefined) + condition = function () { //default all origin event to endpoint event + return true; + }; + if (condition instanceof RegExp) {//support reg exp as condition + var exp = condition; + condition = function (event) { + return exp.test(event.type); + } + } + if (typeof condition == "function") { + var stack = []; + return function (event) {//trigger redirect + var args = slice(arguments); + if (condition.apply(scope, args)) {//trigger condition check + var eventType = typeof endpoint == "function" ? endpoint.apply(scope, args) : endpoint;//dynamic get endpoint + if (stack.indexOf(nextId) < 0 && eventType != event.type && eventType != undefined)//check redirect looping + { + stack.push(nextId); + try { + if (typeof eventType == "string") eventType = + eventType.trim().split(EventBusClass.DEFAULT.EVENT_TYPE_SPLIT_EXP);//support string split by SPACE,COMMA char + if (!(eventType instanceof Array)) { + eventType = [eventType]; + } + iterator(eventType, function (index, type, array, iterator) {//support endpoint array + if (type != event.type) { + var emitArgs = slice([].concat(args), 1); + event.setEmitArgs = function (args) { + emitArgs = args; + }; + event.getEmitArgs = function () { + return [].concat(emitArgs); + }; + event.getOriginType = function () { + return origin; + }; + event.getEndpoint = function () { + return type; + }; + event.endpoints = event.endpoints || []; + event.endpoints.push(type); + processor.apply(scope, args); + emitArgs = (emitArgs instanceof Array) ? [""].concat(emitArgs) : [].concat(args); + emitArgs[0] = type; + if (EventBusClass.DEFAULT.SHOW_LOG) + console.log("redirect=>redirect id:", event.id, " origin:", origin, " ==> endpoint:", type); + bus.emit.apply(bus, emitArgs);//dispatch endpoint event + if (event.isStopped()) iterator.stop(true); + } + } + ); + } finally { + stack.pop(); + } + } else { + throw "redirect origin:" + origin.toString() + " => endpoint:" + endpoint.toString() + + " is looping!"; + } + } + } + } + else { + return function (event) { + if (EventBusClass.DEFAULT.SHOW_LOG) + console.log("redirect=>redirect condition must set function or RegExp!") + } + } + })(endpoint, condition, nextId()), scope); + return bus; + } + }); + return EventBus; }); \ No newline at end of file From 67d2261d0976435df395e81183666ad96f0b300a Mon Sep 17 00:00:00 2001 From: tony_shen Date: Tue, 27 Dec 2016 08:11:31 +0800 Subject: [PATCH 16/20] add aspect method --- example/node/flow-test.js | 42 ++++ lib/eventbus.min.js | 2 +- src/EventBus.js | 449 ++++++++++++++++++++++++++------------ 3 files changed, 352 insertions(+), 141 deletions(-) create mode 100644 example/node/flow-test.js diff --git a/example/node/flow-test.js b/example/node/flow-test.js new file mode 100644 index 0000000..44e75f3 --- /dev/null +++ b/example/node/flow-test.js @@ -0,0 +1,42 @@ +/** + * Created by bona on 2016/12/20. + */ + +var ebus = require('../../lib/eventbus.min'); + +var printEventStack = function (event) { + var p = event; + console.log("==>current stage:", event.type, " event id:", event.id); + console.log("event flow :", event.flow.getEventIdsPath()); +}; + +ebus.before("emit", function (handler) { + console.log("before emit=>", handler); + // console.log("early event: ", this.getEarlyEvent() ? this.getEarlyEvent().id : undefined); + console.log("closest event path: ", this.getCurrentEvent() ? this.getCurrentEvent().flow.getEventIdsPath() : undefined); +})/*.after("emit", function (handler, result) { + console.log("after emit=>", handler); + console.log("current event path: ", this.getCurrentEvent() ? this.getCurrentEvent().flow.getEventIdsPath() : undefined); +})*/.before("beforeEmit",function (handler) { + // console.log(handler); + console.log("current event path: ", this.getCurrentEvent() ? this.getCurrentEvent().flow.getEventIdsPath() : undefined); +}); + +ebus.on("start", function (event) { + console.log("The game is start..."); +}) + .on("chase", function (event) { + console.log("overtaken"); + printEventStack(event); + ebus.emit("overtaken"); + }) + .flow( + {from: "ready", to: "start"}, + {from: "start", to: "take-flight"}, {from: "start", to: "chase"}, + {from: "overtaken", to: "end"}) + .on("end", function (event) { + console.log("The game is end."); + printEventStack(event); + }); + +ebus("ready"); \ No newline at end of file diff --git a/lib/eventbus.min.js b/lib/eventbus.min.js index fe641a4..25d38d7 100644 --- a/lib/eventbus.min.js +++ b/lib/eventbus.min.js @@ -1 +1 @@ -(function(a,b){if(typeof exports==="object"&&typeof module==="object"){module.exports=b()}else{if(typeof define==="function"&&define.amd){define("EventBus",[],b)}else{if(typeof exports==="object"){exports.EventBus=b()}else{a.EventBus=b()}}}})(this,function(){function d(k,j){k=k||[];var h={stop:function(i){this.isStopped=true;this.result=i},isStopped:false,result:undefined};for(var g in k){j(g,k[g],k,h);if(h.isStopped){break}}if(h.isStopped){return h.result}}function f(i,h,g){if(h>i.length){return[]}return[].slice.call(i,h===undefined?0:h,g===undefined?i.length:g)||[]}function b(k,h,j,g){if(typeof j=="string"||j instanceof Array){var i=j;if(typeof j=="string"){i=j.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(i.length>1){d(i,function(l,m){g[0]=m;h.apply(k,g)});return k}else{j=i[0]}}return j}var c=(function(){var g=1000;return function(){return ++g}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(j,m,i){j=b(this,this.on,j,f(arguments));if(j==this){return this}var l=j instanceof RegExp;var h=l?j.toString():j;var g=f(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",g)}var k={id:c(),scope:i||{},callback:m,args:g,regExp:j,eventType:h};if(!l){if(typeof this.listeners[h]!="undefined"){this.listeners[h].push(k)}else{this.listeners[h]=[k]}}else{this.regexListeners.push(k)}return this},once:function(k,l,j){var g=this;var h=function(m){l.apply(this,f(arguments));g.off(k,h,j)};var i=f(arguments);i[1]=h;return g.on.apply(g,i)},off:function(k,l,o){k=b(this,this.off,k,[undefined,l,o]);if(k==this){return this}var i=k instanceof RegExp;var h=i?k.toString():k;var m=[];if(typeof l=="object"){o=l;l=undefined}var j=l==undefined;var n=o==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",k," all callback:",j," all scope:",n)}function g(p){return(j?true:p.callback==l)&&(n?true:p.scope==o)}if(!i){if(typeof this.listeners[h]!="undefined"){if(!(j&&n)){d(this.listeners[h],function(p,q){if(!g(q)){m.push(q)}else{}})}this.listeners[h]=m}}else{d(this.regexListeners,function(p,q){if(!(q.eventType===h&&g(q))){m.push(q)}else{}});this.regexListeners=m}return this},redirect:function(h,k,l,j){var g=this;if(h==undefined||k==undefined||h==k){return g}var i=this.redirectScope=this.redirectScope||{};j=typeof j=="function"?j:function(m){m.setEmitArgs(a.slice(arguments,1))};this.on(h,(function(p,q,n){if(q==undefined){q=function(){return true}}if(q instanceof RegExp){var o=q;q=function(r){return o.test(r.type)}}if(typeof q=="function"){var m=[];return function(t){var r=f(arguments);if(q.apply(i,r)){var s=typeof p=="function"?p.apply(i,r):p;if(m.indexOf(n)<0&&s!=t.type&&s!=undefined){m.push(n);try{if(typeof s=="string"){s=s.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(!(s instanceof Array)){s=[s]}d(s,function(u,w){if(w!=t.type){var v=f([].concat(r),1);t.setEmitArgs=function(x){v=x};t.getEmitArgs=function(){return[].concat(v)};t.getOriginType=function(){return h};t.getEndpoint=function(){return w};t.endpoints=t.endpoints||[];t.endpoints.push(w);j.apply(i,r);v=(v instanceof Array)?[""].concat(v):[].concat(r);v[0]=w;if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect id:",t.id," origin:",h," ==> endpoint:",w)}g.emit.apply(g,v)}})}finally{m.pop()}}else{throw"redirect origin:"+h.toString()+" => endpoint:"+p.toString()+" is looping!"}}}}else{return function(r){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(k,l,c()),i);return g},flow:function(h){var i=f(arguments);if(h instanceof Array){i=h}var g=this;d(i,function(j,k){if(k instanceof Object&&typeof k=="object"&&k.from!=undefined&&k.to!=undefined){g.redirect(k.from,k.to,k.where,k.processor)}});return g},has:function(k,n,j){var m=k instanceof RegExp;var h=m?k.toString():k;var i=[].concat(this.listeners[h]);if(typeof n=="object"){j=n;n=undefined}if(i.length>0&&!m){var l=i.length;if(n===undefined&&j===undefined){return l>0}var g=d(i,function(o,q,r,p){if((j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}else{if(m){i=[].concat(this.regexListeners);var g=d(i,function(o,q,r,p){if(q.regExp.toString()==h&&(j?q.scope==j:true)&&(n?q.callback==n:true)){p.stop(true)}});if(g){return true}}}return false},emit:function(l){var h=this.eventFlow=this.eventFlow||[];var i=f(arguments);l=b(this,this.emit,l,i);if(l==this){return this}var m={id:l+"#"+c(),type:l,target:i.length>1?i[1]:{}};i=[m].concat(f(arguments,1));var k=[].concat(typeof this.listeners[l]=="undefined"?[]:this.listeners[l]);var g=this;function n(q){var o=[].concat(h);var p=false;m.stop=function(){p=true};m.getArg=function(r){if(m.args==undefined||!m.args instanceof Array||m.args.length-1event listener call arguments:",v)}m.args=[].concat(w.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",w)}try{w.callback.apply(w.scope,v)}catch(s){p=true;g.emit(g.DEFAULT.ERROR_EVENT_TYPE,s,w,v)}if(p){t.stop()}}})}var j=[].concat(this.regexListeners);d(j,function(o,p){if(p.regExp.test(l)){k.push(p)}});h.push(m);n(k);h.pop();return this},getAllEvents:function(){var l="";for(var h in this.listeners){var k=this.listeners[h].length;for(var g=0;gk.length){return[]}return[].slice.call(k,j===undefined?0:j,i===undefined?k.length:i)||[]}function b(m,j,l,i){if(typeof l=="string"||l instanceof Array){var k=l;if(typeof l=="string"){k=l.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(k.length>1){d(k,function(n,o){i[0]=o;j.apply(m,i)});return m}else{l=k[0]}}return l}var c=(function(){var i=1000;return function(){return ++i}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(l,o,k){l=b(this,this.on,l,h(arguments));if(l==this){return this}var n=l instanceof RegExp;var j=n?l.toString():l;var i=h(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",i)}var m={id:c(),scope:k||{},callback:o,args:i,regExp:l,eventType:j};if(!n){if(typeof this.listeners[j]!="undefined"){this.listeners[j].push(m)}else{this.listeners[j]=[m]}}else{this.regexListeners.push(m)}return this},off:function(m,n,q){m=b(this,this.off,m,[undefined,n,q]);if(m==this){return this}var k=m instanceof RegExp;var j=k?m.toString():m;var o=[];if(typeof n=="object"){q=n;n=undefined}var l=n==undefined;var p=q==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",m," all callback:",l," all scope:",p)}function i(r){return(l?true:r.callback==n)&&(p?true:r.scope==q)}if(!k){if(typeof this.listeners[j]!="undefined"){if(!(l&&p)){d(this.listeners[j],function(r,s){if(!i(s)){o.push(s)}else{}})}this.listeners[j]=o}}else{d(this.regexListeners,function(r,s){if(!(s.eventType===j&&i(s))){o.push(s)}else{}});this.regexListeners=o}return this},has:function(m,p,l){var o=m instanceof RegExp;var j=o?m.toString():m;var k=[].concat(this.listeners[j]);if(typeof p=="object"){l=p;p=undefined}if(k.length>0&&!o){var n=k.length;if(p===undefined&&l===undefined){return n>0}var i=d(k,function(q,s,t,r){if((l?s.scope==l:true)&&(p?s.callback==p:true)){r.stop(true)}});if(i){return true}}else{if(o){k=[].concat(this.regexListeners);var i=d(k,function(q,s,t,r){if(s.regExp.toString()==j&&(l?s.scope==l:true)&&(p?s.callback==p:true)){r.stop(true)}});if(i){return true}}}return false},emit:function(n){var j=this.eventFlow=this.eventFlow||[];var k=h(arguments);n=b(this,this.emit,n,k);if(n==this){return this}var o={id:n+"#"+c(),type:n,target:k.length>1?k[1]:{}};k=[o].concat(h(arguments,1));var m=[].concat(typeof this.listeners[n]=="undefined"?[]:this.listeners[n]);var i=this;function p(s){var q=[].concat(j);var r=false;o.stop=function(){r=true};o.isStopped=function(){return r};o.getArg=function(t){if(o.args==undefined||!o.args instanceof Array||o.args.length-1")}};o.getLevel=function(){return q.length-1};d(s,function(u,z,x,w){if(z&&z.callback){var y=[].concat(k);if(e.DEFAULT.SHOW_LOG){console.log("emit=>event listener call arguments:",y)}o.args=[].concat(z.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",z)}try{if(e.DEFAULT.SHOW_LOG){console.log("event flow:",o.flow.getEventIdsPath())}var t=i.beforeEmit;if(t&&typeof t=="function"){t.apply(i,[z].concat(y))}z.callback.apply(z.scope,y);t=i.afterEmit;if(t&&typeof t=="function"){t.apply(i,[z].concat(y))}}catch(v){r=true;i.emit(e.DEFAULT.ERROR_EVENT_TYPE,v,z,y)}if(r){w.stop()}}})}var l=[].concat(this.regexListeners);d(l,function(q,r){if(r.regExp.test(n)){m.push(r)}});j.push(o);p(m);j.pop();return this},getAllEvents:function(){var n="";for(var k in this.listeners){var m=this.listeners[k].length;for(var j=0;jredirect id:",w.id," origin:",k," ==> endpoint:",A)}j.emit.apply(j,y);if(w.isStopped()){z.stop(true)}}})}finally{p.pop()}}else{throw"redirect origin:"+k.toString()+" => endpoint:"+s.toString()+" is looping!"}}}}else{return function(u){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(n,o,c()),l);return j}});a.plugin(function(k){var j={};function i(m,l,o){var n=j[m]=k.isArray(j[m])?j[m]:[];var p=k.fn[m];var q=k.isFunction(p);k.fn[m]=function(){var t=h(arguments);var r=this;var s;if(l==="before"||l==="around"){s=o.apply(r,[{name:m,orientation:l,args:t}])}if(q){s=p.apply(r,t)}if(l==="after"||l==="around"){s=o.apply(r,[{name:m,orientation:l,args:t},s])}return s};k.fn[m].aspect={orientation:l,next:p};return k}k.aspect=i;k.before=function(l,m){return k.aspect(l,"before",m)};k.after=function(l,m){return k.aspect(l,"after",m)};k.around=function(l,m){return k.aspect(l,"around",m)}});a.plugin(function(i){i.fn.beforeEmit=function(){};i.fn.afterEmit=function(){}});var f=function(i,j){return function(){return j.apply(i,h(arguments))}};d(e.prototype,function(i,j){if(j&&!a.hasOwnProperty(i)&&typeof j=="function"){a[i]=f(g,j)}});a.plugin(function(i){i.slice=h;i.nextId=c;i.iterator=d;i.hit=f;i.isFunction=function(j){return j&&typeof j==="function"};i.isArray=function(j){return j&&j.constructor.name=="Array"}});return a}); \ No newline at end of file diff --git a/src/EventBus.js b/src/EventBus.js index e808dd1..eb052c4 100644 --- a/src/EventBus.js +++ b/src/EventBus.js @@ -99,24 +99,6 @@ this.regexListeners.push(listener); return this; }, - /** - * EventBus.once("click",callback); - * EventBus.once("click",callback,buttonScope); - * @param type - * @param callback - * @param scope - * @returns {EventBusClass} - */ - once: function (type, callback, scope) { - var bus = this; - var proxyCallback = function (event) { - callback.apply(this, slice(arguments)); - bus.off(type, proxyCallback, scope); - }; - var args = slice(arguments); - args[1] = proxyCallback; - return bus.on.apply(bus, args); - }, /** * EventBus.off("click"); //remove all click listeners * EventBus.off("click",onClick); @@ -172,116 +154,6 @@ } return this; }, - /** - * redirect("click","onClick",function(event){return true;}); - * redirect("click","onClick"); - * redirect("click",function(event){return "onClick"},function(event){return true;}); - * redirect(/\w*_click/,"onClick",/btn[0-9]+_click/); - * @param origin - * @param endpoint - * @param condition - * @param processor processor be called before event redirection - * @return {EventBusClass} - */ - redirect: function (origin, endpoint, condition, processor) { - var bus = this; - if (origin == undefined || endpoint == undefined || origin == endpoint)return bus; - - var scope = this.redirectScope = this.redirectScope || {}; - - processor = typeof processor == "function" ? processor : function (event) { - event.setEmitArgs(EventBus.slice(arguments, 1));//example: set emit endpoint event arguments - }; - this.on(origin, (function (endpoint, condition, nextId) {//Unified exception handling by emit method. - if (condition == undefined) - condition = function () { //default all origin event to endpoint event - return true; - }; - if (condition instanceof RegExp) {//support reg exp as condition - var exp = condition; - condition = function (event) { - return exp.test(event.type); - } - } - if (typeof condition == "function") { - var stack = []; - return function (event) {//trigger redirect - var args = slice(arguments); - if (condition.apply(scope, args)) {//trigger condition check - var eventType = typeof endpoint == "function" ? endpoint.apply(scope, args) : endpoint;//dynamic get endpoint - if (stack.indexOf(nextId) < 0 && eventType != event.type && eventType != undefined)//check redirect looping - { - stack.push(nextId); - try { - if (typeof eventType == "string") eventType = - eventType.trim().split(EventBusClass.DEFAULT.EVENT_TYPE_SPLIT_EXP);//support string split by SPACE,COMMA char - if (!(eventType instanceof Array)) { - eventType = [eventType]; - } - iterator(eventType, function (index, type) {//support endpoint array - if (type != event.type) { - var emitArgs = slice([].concat(args), 1); - event.setEmitArgs = function (args) { - emitArgs = args; - }; - event.getEmitArgs = function () { - return [].concat(emitArgs); - }; - event.getOriginType = function () { - return origin; - }; - event.getEndpoint = function () { - return type; - }; - event.endpoints = event.endpoints || []; - event.endpoints.push(type); - processor.apply(scope, args); - emitArgs = (emitArgs instanceof Array) ? [""].concat(emitArgs) : [].concat(args); - emitArgs[0] = type; - if (EventBusClass.DEFAULT.SHOW_LOG) - console.log("redirect=>redirect id:", event.id, " origin:", origin, " ==> endpoint:", type); - bus.emit.apply(bus, emitArgs);//dispatch endpoint event - } - } - ); - } finally { - stack.pop(); - } - } else { - throw "redirect origin:" + origin.toString() + " => endpoint:" + endpoint.toString() + - " is looping!"; - } - } - } - } - else { - return function (event) { - if (EventBusClass.DEFAULT.SHOW_LOG) - console.log("redirect=>redirect condition must set function or RegExp!") - } - } - })(endpoint, condition, nextId()), scope); - return bus; - }, - /** - * build event flow - * EventBus.flow({from:'click',to:'onClick'}) - * EventBus.flow({from:'ready',to:'start'},{from:'start',to:'end'}) - * EventBus.flow({from:'click',to:'onClick',where:function(event){event.getLevel()>1}}) - * @param node is event flow node map config,maybe node map array - * @return {EventBusClass} - */ - flow: function (node) { - var nodeMap = slice(arguments); - if (node instanceof Array) nodeMap = node; - var bus = this; - iterator(nodeMap, function (index, node) { - if (node instanceof Object && typeof node == "object" && node['from'] != undefined && node['to'] != undefined) { - bus.redirect(node['from'], node['to'], node['where'], node['processor']); - } - }); - return bus; - }, /** * EventBus.has("click") * EventBus.has("click",buttonScope); @@ -354,6 +226,9 @@ event.stop = function () { isStop = true; }; + event.isStopped = function () { + return isStop; + }; event.getArg = function (index) { if (event.args == undefined || !event.args instanceof Array || event.args.length - 1 < index)return undefined; return event.args[index]; @@ -367,6 +242,11 @@ }, getAllEvents: function () { return stack.slice(0); + }, + getEventIdsPath: function (separator) { + return stack.map(function (event) { + return event.id; + }).join(separator || "==>"); } }; @@ -383,10 +263,16 @@ if (EventBusClass.DEFAULT.SHOW_LOG) console.log("emit=>fire event listener:", listener); try { + if (EventBusClass.DEFAULT.SHOW_LOG) + console.log("event flow:", event.flow.getEventIdsPath()); + var emitAspect = bus["beforeEmit"]; + if (emitAspect && typeof emitAspect == "function") emitAspect.apply(bus, [listener].concat(listenerArgs)); listener.callback.apply(listener.scope, listenerArgs); + emitAspect = bus["afterEmit"]; + if (emitAspect && typeof emitAspect == "function") emitAspect.apply(bus, [listener].concat(listenerArgs)); } catch (exception) { isStop = true; - bus.emit(bus.DEFAULT.ERROR_EVENT_TYPE, exception, listener, listenerArgs); + bus.emit(EventBusClass.DEFAULT.ERROR_EVENT_TYPE, exception, listener, listenerArgs); } if (isStop) iterator.stop(); } @@ -423,22 +309,305 @@ return str; } }; - //alis - EventBusClass.prototype.bind = EventBusClass.prototype.addEventListener = EventBusClass.prototype.on; - EventBusClass.prototype.unbind = EventBusClass.prototype.removeEventListener = EventBusClass.prototype.off; - EventBusClass.prototype.trigger = EventBusClass.prototype.dispatch = EventBusClass.prototype.emit; - EventBusClass.prototype.hasEventListener = EventBusClass.prototype.has; - - var EventBus = new EventBusClass(); - //common utils - EventBus.slice = slice; - EventBus.nextId = nextId; - EventBus.iterator = iterator; + + + var _EventBus_ = new EventBusClass(); + + var EventBus = function (event) { + return _EventBus_.emit.apply(_EventBus_, slice(arguments)); + }; + + //support extend. + EventBus.fn = EventBusClass.prototype; + + /** + * define EventBus plugin extend + * examples: + * EventBus.plugin(function(eBus){ + * + * eBus.fn.newExtend = function(){ + * + * }; + * + * eBus.newStaticMethod = function(){ + * + * } + * }); + * @param f + */ + EventBus.plugin = function (f) { + f(EventBus); + }; + + EventBus.plugin(function (eBus) { + //alis + eBus.fn.bind = eBus.fn.addEventListener = eBus.fn.on; + eBus.fn.unbind = eBus.fn.removeEventListener = eBus.fn.off; + eBus.fn.trigger = eBus.fn.dispatch = eBus.fn.emit; + eBus.fn.hasEventListener = eBus.fn.has; + }); + //default config EventBus.DEFAULT = EventBusClass.DEFAULT = { SHOW_LOG: false, EVENT_TYPE_SPLIT_EXP: /,|\s/, ERROR_EVENT_TYPE: "EMIT_ERROR" }; + + EventBus.plugin(function (eBus) { + + eBus.fn.getCurrentEvent = function () { + return [].concat(this.eventFlow).pop(); + }; + + eBus.fn.getEarlyEvent = function () { + return [].concat(this.eventFlow).shift(); + }; + + eBus.fn.getClosestEvent = function () { + return this.getCurrentEvent() ? this.getCurrentEvent().flow.getClosestEvent() : undefined; + } + }); + + EventBus.plugin(function (eBus) { + /** + * EventBus.once("click",callback); + * EventBus.once("click",callback,buttonScope); + * @param type + * @param callback + * @param scope + * @returns {EventBusClass} + */ + eBus.fn.once = function (type, callback, scope) { + var bus = this; + var proxyCallback = function (event) { + callback.apply(this, slice(arguments)); + bus.off(type, proxyCallback, scope); + }; + var args = slice(arguments); + args[1] = proxyCallback; + return bus.on.apply(bus, args); + } + }); + + EventBus.plugin(function (eBus) { + /** + * build event flow + * EventBus.flow({from:'click',to:'onClick'}) + * EventBus.flow({from:'ready',to:'start'},{from:'start',to:'end'}) + * EventBus.flow({from:'click',to:'onClick',where:function(event){event.getLevel()>1}}) + * @param node is event flow node map config,maybe node map array + * @return {EventBusClass} + */ + eBus.fn.flow = function (node) { + var nodeMap = slice(arguments); + if (node instanceof Array) nodeMap = node; + var bus = this; + iterator(nodeMap, function (index, node) { + if (node instanceof Object && typeof node == "object" && node['from'] != undefined && node['to'] != undefined) { + bus.redirect(node['from'], node['to'], node['where'], node['processor']); + } + }); + return bus; + }; + }); + + EventBus.plugin(function (eBus) { + /** + * redirect("click","onClick",function(event){return true;}); + * redirect("click","onClick"); + * redirect("click",function(event){return "onClick"},function(event){return true;}); + * redirect(/\w*_click/,"onClick",/btn[0-9]+_click/); + * @param origin + * @param endpoint + * @param condition + * @param processor processor be called before event redirection + * @return {EventBusClass} + */ + eBus.fn.redirect = function (origin, endpoint, condition, processor) { + var bus = this; + if (origin == undefined || endpoint == undefined || origin == endpoint)return bus; + + var scope = this.redirectScope = this.redirectScope || {}; + + processor = typeof processor == "function" ? processor : function (event) { + event.setEmitArgs(EventBus.slice(arguments, 1));//example: set emit endpoint event arguments + }; + this.on(origin, (function (endpoint, condition, nextId) {//Unified exception handling by emit method. + if (condition == undefined) + condition = function () { //default all origin event to endpoint event + return true; + }; + if (condition instanceof RegExp) {//support reg exp as condition + var exp = condition; + condition = function (event) { + return exp.test(event.type); + } + } + if (typeof condition == "function") { + var stack = []; + return function (event) {//trigger redirect + var args = slice(arguments); + if (condition.apply(scope, args)) {//trigger condition check + var eventType = typeof endpoint == "function" ? endpoint.apply(scope, args) : endpoint;//dynamic get endpoint + if (stack.indexOf(nextId) < 0 && eventType != event.type && eventType != undefined)//check redirect looping + { + stack.push(nextId); + try { + if (typeof eventType == "string") eventType = + eventType.trim().split(EventBusClass.DEFAULT.EVENT_TYPE_SPLIT_EXP);//support string split by SPACE,COMMA char + if (!(eventType instanceof Array)) { + eventType = [eventType]; + } + iterator(eventType, function (index, type, array, iterator) {//support endpoint array + if (type != event.type) { + var emitArgs = slice([].concat(args), 1); + event.setEmitArgs = function (args) { + emitArgs = args; + }; + event.getEmitArgs = function () { + return [].concat(emitArgs); + }; + event.getOriginType = function () { + return origin; + }; + event.getEndpoint = function () { + return type; + }; + event.isRedirect = function () { + return true; + }; + event.endpoints = event.endpoints || []; + event.endpoints.push(type); + processor.apply(scope, args); + emitArgs = (emitArgs instanceof Array) ? [""].concat(emitArgs) : [].concat(args); + emitArgs[0] = type; + if (EventBusClass.DEFAULT.SHOW_LOG) + console.log("redirect=>redirect id:", event.id, " origin:", origin, " ==> endpoint:", type); + bus.emit.apply(bus, emitArgs);//dispatch endpoint event + if (event.isStopped()) iterator.stop(true); + } + } + ); + } finally { + stack.pop(); + } + } else { + throw "redirect origin:" + origin.toString() + " => endpoint:" + endpoint.toString() + + " is looping!"; + } + } + } + } + else { + return function (event) { + if (EventBusClass.DEFAULT.SHOW_LOG) + console.log("redirect=>redirect condition must set function or RegExp!") + } + } + })(endpoint, condition, nextId()), scope); + return bus; + } + }); + + EventBus.plugin(function (eBus) { + var aspect_cache={}; + function aspect(name, orientation, fn) { + var chain = aspect_cache[name] = eBus.isArray(aspect_cache[name])?aspect_cache[name]:[]; + var old_aspect = eBus.fn[name]; + var isFunction = eBus.isFunction(old_aspect); + // if (!isFunction)return; + eBus.fn[name] = function () { + var args = slice(arguments); + var bus = this; + var ret; + if (orientation === "before" || orientation === "around") { + ret = fn.apply(bus, [{name: name, orientation: orientation, args: args}]); + } + if (isFunction) ret = old_aspect.apply(bus, args); + if (orientation === "after" || orientation === "around") { + ret = fn.apply(bus, [{name: name, orientation: orientation, args: args}, ret]); + } + return ret; + }; + + eBus.fn[name].aspect = { + orientation: orientation, + next: old_aspect + }; + return eBus; + } + + eBus.aspect = aspect; + + /** + * the handler called before named method invocation + * @param name + * @param handler + * @return {EventBus} + */ + eBus.before = function (name, handler) { + return eBus.aspect(name, "before", handler); + }; + + /** + * the handler called after named method invocation + * @param name + * @param handler + * @return {EventBus} + */ + + eBus.after = function (name, handler) { + return eBus.aspect(name, "after", handler); + }; + + /** + * the handler called before and after named method invocation + * @param name + * @param handler + * @return {EventBus} + */ + eBus.around = function (name, handler) { + return eBus.aspect(name, "around", handler); + }; + }); + + EventBus.plugin(function (eBus) { + eBus.fn.beforeEmit = function () { + + }; + + eBus.fn.afterEmit = function () { + + }; + }); + + var hit = function (object, fn) { + return function () { + return fn.apply(object, slice(arguments)); + } + }; + + iterator(EventBusClass.prototype, function (key, fn) { + if (fn && !EventBus["hasOwnProperty"](key) && typeof fn == "function") + EventBus[key] = hit(_EventBus_, fn); + }); + + EventBus.plugin(function (eBus) { + //common utils + eBus.slice = slice; + eBus.nextId = nextId; + eBus.iterator = iterator; + eBus.hit = hit; + eBus.isFunction = function (fn) { + return fn&&typeof fn ==="function"; + }; + + eBus.isArray = function (array) { + return array && array.constructor.name=="Array"; + } + + }); + return EventBus; }); \ No newline at end of file From c1eeca15f536f3569ff8a33c5c5b09128b2e952e Mon Sep 17 00:00:00 2001 From: bonashen Date: Tue, 27 Dec 2016 14:54:56 +0800 Subject: [PATCH 17/20] add aspect ,before,after,around method --- example/node/flow-test.js | 14 +++- src/EventBus.js | 149 +++++++++++++++++++++++++++----------- 2 files changed, 117 insertions(+), 46 deletions(-) diff --git a/example/node/flow-test.js b/example/node/flow-test.js index 44e75f3..61895b9 100644 --- a/example/node/flow-test.js +++ b/example/node/flow-test.js @@ -14,12 +14,18 @@ ebus.before("emit", function (handler) { console.log("before emit=>", handler); // console.log("early event: ", this.getEarlyEvent() ? this.getEarlyEvent().id : undefined); console.log("closest event path: ", this.getCurrentEvent() ? this.getCurrentEvent().flow.getEventIdsPath() : undefined); -})/*.after("emit", function (handler, result) { - console.log("after emit=>", handler); + handler.remove(); +}); + +ebus.after("beforeEmit", function (handler, result) { + console.log("after beforeEmit=>", handler); console.log("current event path: ", this.getCurrentEvent() ? this.getCurrentEvent().flow.getEventIdsPath() : undefined); -})*/.before("beforeEmit",function (handler) { +}).remove(); + +ebus.before("beforeEmit", function (handler) { // console.log(handler); - console.log("current event path: ", this.getCurrentEvent() ? this.getCurrentEvent().flow.getEventIdsPath() : undefined); + console.log("beforeEmit,current event path: ", this.getCurrentEvent() ? this.getCurrentEvent().flow.getEventIdsPath() : undefined); + handler.remove(); }); ebus.on("start", function (event) { diff --git a/src/EventBus.js b/src/EventBus.js index eb052c4..7c3efd0 100644 --- a/src/EventBus.js +++ b/src/EventBus.js @@ -317,6 +317,21 @@ return _EventBus_.emit.apply(_EventBus_, slice(arguments)); }; + var isFunction = function (fn) { + return fn && typeof fn === "function"; + }, + + isArray = function (array) { + return array && array.constructor.name == "Array"; + }, + + hit = function (object, fn) { + return function () { + return fn.apply(object, slice(arguments)); + } + }; + + //support extend. EventBus.fn = EventBusClass.prototype; @@ -337,6 +352,10 @@ */ EventBus.plugin = function (f) { f(EventBus); + iterator(EventBusClass.prototype, function (key, fn) { + if (fn && !EventBus["hasOwnProperty"](key) && isFunction(fn)) + EventBus[key] = hit(_EventBus_, fn); + }); }; EventBus.plugin(function (eBus) { @@ -431,8 +450,9 @@ var scope = this.redirectScope = this.redirectScope || {}; processor = typeof processor == "function" ? processor : function (event) { - event.setEmitArgs(EventBus.slice(arguments, 1));//example: set emit endpoint event arguments - }; + event.setEmitArgs(EventBus.slice(arguments, 1));//example: set emit endpoint event arguments + }; + this.on(origin, (function (endpoint, condition, nextId) {//Unified exception handling by emit method. if (condition == undefined) condition = function () { //default all origin event to endpoint event @@ -511,31 +531,93 @@ }); EventBus.plugin(function (eBus) { - var aspect_cache={}; + var aspect_cache = {}, old_fn = {}; + function aspect(name, orientation, fn) { - var chain = aspect_cache[name] = eBus.isArray(aspect_cache[name])?aspect_cache[name]:[]; + var chain = aspect_cache[name] = eBus.isArray(aspect_cache[name]) ? aspect_cache[name] : []; var old_aspect = eBus.fn[name]; - var isFunction = eBus.isFunction(old_aspect); - // if (!isFunction)return; - eBus.fn[name] = function () { - var args = slice(arguments); - var bus = this; - var ret; - if (orientation === "before" || orientation === "around") { - ret = fn.apply(bus, [{name: name, orientation: orientation, args: args}]); - } - if (isFunction) ret = old_aspect.apply(bus, args); - if (orientation === "after" || orientation === "around") { - ret = fn.apply(bus, [{name: name, orientation: orientation, args: args}, ret]); - } - return ret; + var isAspect = eBus.isFunction(old_aspect) && old_aspect.aspect; + if (!isAspect) { + old_fn[name] = eBus.fn[name]; + } + var handlerId = [orientation, name, eBus.nextId()].join("-"); + chain.push(handlerId); + + var handler = { + handlerId: handlerId, + fn: fn, + name: name, + orientation: orientation }; - eBus.fn[name].aspect = { - orientation: orientation, - next: old_aspect - }; - return eBus; + function removeHandler() { + var index = chain.indexOf(handlerId); + chain.splice(index, 1); + delete aspect_cache[handlerId]; + if (chain.length == 0) { + eBus.fn[this.name] = old_fn[this.name]; + } + } + + function indexHandler(index) { + var old_index = chain.indexOf(this.handlerId); + if (old_index == index)return; + index = chain.length - index; + index = index > chain.length ? chain.length : (index < 0 ? 0 : index); + chain.splice(index, 0, this.handlerId); + old_index = index > old_index ? old_index : old_index + 1; + chain.splice(old_index, 1); + } + + handler.remove = eBus.hit(handler, removeHandler); + handler.index = eBus.hit(handler, indexHandler); + + aspect_cache[handlerId] = handler; + + if (!isAspect) { + eBus.fn[name] = function () { + var args = slice(arguments); + var bus = this; + var ret; + var handlerIds = [].concat(chain); + var handlerId; + while (handlerId = handlerIds.pop()) { + var fn = aspect_cache[handlerId].fn; + var orientation = aspect_cache[handlerId].orientation; + if (orientation === "before" || orientation === "around") { + ret = fn.apply(bus, [{ + name: name, + orientation: orientation, + args: args, + handlerId: handlerId, + remove: aspect_cache[handlerId].remove, + index: aspect_cache[handlerId].index + }]); + } + + if (handlerIds.length == 0 && eBus.isFunction(old_fn[name])) + ret = old_fn[name].apply(bus, args); + + if (orientation === "after" || orientation === "around") { + ret = fn.apply(bus, [{ + name: name, + orientation: orientation, + args: args, + handlerId: handlerId, + remove: aspect_cache[handlerId].remove, + index: aspect_cache[handlerId].index + }, ret]); + } + return ret; + } + }; + + eBus.fn[name].aspect = { + orientation: orientation, + next: handler + }; + } + return handler; } eBus.aspect = aspect; @@ -582,31 +664,14 @@ }; }); - var hit = function (object, fn) { - return function () { - return fn.apply(object, slice(arguments)); - } - }; - - iterator(EventBusClass.prototype, function (key, fn) { - if (fn && !EventBus["hasOwnProperty"](key) && typeof fn == "function") - EventBus[key] = hit(_EventBus_, fn); - }); - EventBus.plugin(function (eBus) { //common utils eBus.slice = slice; eBus.nextId = nextId; eBus.iterator = iterator; eBus.hit = hit; - eBus.isFunction = function (fn) { - return fn&&typeof fn ==="function"; - }; - - eBus.isArray = function (array) { - return array && array.constructor.name=="Array"; - } - + eBus.isFunction = isFunction; + eBus.isArray = isArray; }); return EventBus; From 56f7ca7a883e4aa16b4c595becaa57b51c9220a0 Mon Sep 17 00:00:00 2001 From: tony_shen Date: Wed, 28 Dec 2016 16:05:02 +0800 Subject: [PATCH 18/20] modified aspect method --- example/node/aspect-test.js | 31 +++ example/node/flow-test.js | 20 +- lib/eventbus.min.js | 4 +- src/EventBus.js | 450 ++++++++++++++++++++++++------------ 4 files changed, 331 insertions(+), 174 deletions(-) create mode 100644 example/node/aspect-test.js diff --git a/example/node/aspect-test.js b/example/node/aspect-test.js new file mode 100644 index 0000000..1f4d5e8 --- /dev/null +++ b/example/node/aspect-test.js @@ -0,0 +1,31 @@ +/** + * Created by bona on 2016/12/28. + */ + +var ebus = require('../../lib/eventbus.min'); + +ebus.before("emit", function (event) { + console.log("before-emit,event type:", event); + console.log("closest event path: ", this.getCurrentEvent() ? this.getCurrentEvent().flow.getEventIdsPath() : undefined); + if(event=="ready")return [event,{name:"new object"}]; +}); + +ebus.after("emit",function (event) { + console.log("after-emit,event type:",event); +},true); + +ebus.on("ready",function (event,o) { + console.log("ready",o); +}); + +ebus.redirect("ready","end"); + +ebus.on("end",function (event,o) { + console.log("end event,",event,o); +}); + +ebus.beforeTriggerListener(/end/,function (listener,event,o) { + console.log("beforeTriggerListener,",event,o); +}); + +ebus("ready"); \ No newline at end of file diff --git a/example/node/flow-test.js b/example/node/flow-test.js index 61895b9..5b672f8 100644 --- a/example/node/flow-test.js +++ b/example/node/flow-test.js @@ -10,31 +10,13 @@ var printEventStack = function (event) { console.log("event flow :", event.flow.getEventIdsPath()); }; -ebus.before("emit", function (handler) { - console.log("before emit=>", handler); - // console.log("early event: ", this.getEarlyEvent() ? this.getEarlyEvent().id : undefined); - console.log("closest event path: ", this.getCurrentEvent() ? this.getCurrentEvent().flow.getEventIdsPath() : undefined); - handler.remove(); -}); - -ebus.after("beforeEmit", function (handler, result) { - console.log("after beforeEmit=>", handler); - console.log("current event path: ", this.getCurrentEvent() ? this.getCurrentEvent().flow.getEventIdsPath() : undefined); -}).remove(); - -ebus.before("beforeEmit", function (handler) { - // console.log(handler); - console.log("beforeEmit,current event path: ", this.getCurrentEvent() ? this.getCurrentEvent().flow.getEventIdsPath() : undefined); - handler.remove(); -}); - ebus.on("start", function (event) { console.log("The game is start..."); }) .on("chase", function (event) { console.log("overtaken"); printEventStack(event); - ebus.emit("overtaken"); + ebus("overtaken"); }) .flow( {from: "ready", to: "start"}, diff --git a/lib/eventbus.min.js b/lib/eventbus.min.js index 25d38d7..a50c22e 100644 --- a/lib/eventbus.min.js +++ b/lib/eventbus.min.js @@ -1 +1,3 @@ -(function(a,b){if(typeof exports==="object"&&typeof module==="object"){module.exports=b()}else{if(typeof define==="function"&&define.amd){define("EventBus",[],b)}else{if(typeof exports==="object"){exports.EventBus=b()}else{a.EventBus=b()}}}})(this,function(){function d(m,l){m=m||[];var k={stop:function(i){this.isStopped=true;this.result=i},isStopped:false,result:undefined};for(var j in m){l(j,m[j],m,k);if(k.isStopped){break}}if(k.isStopped){return k.result}}function h(k,j,i){if(j>k.length){return[]}return[].slice.call(k,j===undefined?0:j,i===undefined?k.length:i)||[]}function b(m,j,l,i){if(typeof l=="string"||l instanceof Array){var k=l;if(typeof l=="string"){k=l.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(k.length>1){d(k,function(n,o){i[0]=o;j.apply(m,i)});return m}else{l=k[0]}}return l}var c=(function(){var i=1000;return function(){return ++i}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(l,o,k){l=b(this,this.on,l,h(arguments));if(l==this){return this}var n=l instanceof RegExp;var j=n?l.toString():l;var i=h(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",i)}var m={id:c(),scope:k||{},callback:o,args:i,regExp:l,eventType:j};if(!n){if(typeof this.listeners[j]!="undefined"){this.listeners[j].push(m)}else{this.listeners[j]=[m]}}else{this.regexListeners.push(m)}return this},off:function(m,n,q){m=b(this,this.off,m,[undefined,n,q]);if(m==this){return this}var k=m instanceof RegExp;var j=k?m.toString():m;var o=[];if(typeof n=="object"){q=n;n=undefined}var l=n==undefined;var p=q==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",m," all callback:",l," all scope:",p)}function i(r){return(l?true:r.callback==n)&&(p?true:r.scope==q)}if(!k){if(typeof this.listeners[j]!="undefined"){if(!(l&&p)){d(this.listeners[j],function(r,s){if(!i(s)){o.push(s)}else{}})}this.listeners[j]=o}}else{d(this.regexListeners,function(r,s){if(!(s.eventType===j&&i(s))){o.push(s)}else{}});this.regexListeners=o}return this},has:function(m,p,l){var o=m instanceof RegExp;var j=o?m.toString():m;var k=[].concat(this.listeners[j]);if(typeof p=="object"){l=p;p=undefined}if(k.length>0&&!o){var n=k.length;if(p===undefined&&l===undefined){return n>0}var i=d(k,function(q,s,t,r){if((l?s.scope==l:true)&&(p?s.callback==p:true)){r.stop(true)}});if(i){return true}}else{if(o){k=[].concat(this.regexListeners);var i=d(k,function(q,s,t,r){if(s.regExp.toString()==j&&(l?s.scope==l:true)&&(p?s.callback==p:true)){r.stop(true)}});if(i){return true}}}return false},emit:function(n){var j=this.eventFlow=this.eventFlow||[];var k=h(arguments);n=b(this,this.emit,n,k);if(n==this){return this}var o={id:n+"#"+c(),type:n,target:k.length>1?k[1]:{}};k=[o].concat(h(arguments,1));var m=[].concat(typeof this.listeners[n]=="undefined"?[]:this.listeners[n]);var i=this;function p(s){var q=[].concat(j);var r=false;o.stop=function(){r=true};o.isStopped=function(){return r};o.getArg=function(t){if(o.args==undefined||!o.args instanceof Array||o.args.length-1")}};o.getLevel=function(){return q.length-1};d(s,function(u,z,x,w){if(z&&z.callback){var y=[].concat(k);if(e.DEFAULT.SHOW_LOG){console.log("emit=>event listener call arguments:",y)}o.args=[].concat(z.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",z)}try{if(e.DEFAULT.SHOW_LOG){console.log("event flow:",o.flow.getEventIdsPath())}var t=i.beforeEmit;if(t&&typeof t=="function"){t.apply(i,[z].concat(y))}z.callback.apply(z.scope,y);t=i.afterEmit;if(t&&typeof t=="function"){t.apply(i,[z].concat(y))}}catch(v){r=true;i.emit(e.DEFAULT.ERROR_EVENT_TYPE,v,z,y)}if(r){w.stop()}}})}var l=[].concat(this.regexListeners);d(l,function(q,r){if(r.regExp.test(n)){m.push(r)}});j.push(o);p(m);j.pop();return this},getAllEvents:function(){var n="";for(var k in this.listeners){var m=this.listeners[k].length;for(var j=0;jredirect id:",w.id," origin:",k," ==> endpoint:",A)}j.emit.apply(j,y);if(w.isStopped()){z.stop(true)}}})}finally{p.pop()}}else{throw"redirect origin:"+k.toString()+" => endpoint:"+s.toString()+" is looping!"}}}}else{return function(u){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(n,o,c()),l);return j}});a.plugin(function(k){var j={};function i(m,l,o){var n=j[m]=k.isArray(j[m])?j[m]:[];var p=k.fn[m];var q=k.isFunction(p);k.fn[m]=function(){var t=h(arguments);var r=this;var s;if(l==="before"||l==="around"){s=o.apply(r,[{name:m,orientation:l,args:t}])}if(q){s=p.apply(r,t)}if(l==="after"||l==="around"){s=o.apply(r,[{name:m,orientation:l,args:t},s])}return s};k.fn[m].aspect={orientation:l,next:p};return k}k.aspect=i;k.before=function(l,m){return k.aspect(l,"before",m)};k.after=function(l,m){return k.aspect(l,"after",m)};k.around=function(l,m){return k.aspect(l,"around",m)}});a.plugin(function(i){i.fn.beforeEmit=function(){};i.fn.afterEmit=function(){}});var f=function(i,j){return function(){return j.apply(i,h(arguments))}};d(e.prototype,function(i,j){if(j&&!a.hasOwnProperty(i)&&typeof j=="function"){a[i]=f(g,j)}});a.plugin(function(i){i.slice=h;i.nextId=c;i.iterator=d;i.hit=f;i.isFunction=function(j){return j&&typeof j==="function"};i.isArray=function(j){return j&&j.constructor.name=="Array"}});return a}); \ No newline at end of file +(function(a,b){if(typeof exports==="object"&&typeof module==="object"){module.exports=b()}else{if(typeof define==="function"&&define.amd){define("EventBus",[],b)}else{if(typeof exports==="object"){exports.EventBus=b()}else{a.EventBus=b()}}}})(this,function(){var e;var d=function(l){return l&&typeof l==="function"},i=function(l){return l&&l.constructor.name==="Array"},a=function(l,m){return function(){return m.apply(l,k(arguments))}};function g(o,n){o=o||[];var m={stop:function(p){this.isStopped=true;this.result=p},isStopped:false,result:e};for(var l in o){n(l,o[l],o,m);if(m.isStopped){break}}if(m.isStopped){return m.result}}function k(n,m,l){if(m>n.length){return[]}return[].slice.call(n,m===e?0:m,l===e?n.length:l)||[]}function c(p,m,o,l){if(typeof o=="string"||i(o)){var n=o;if(typeof o=="string"){n=o.trim().split(j.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(n.length>1){g(n,function(q,r){l[0]=r;m.apply(p,l)});return p}else{o=n[0]}}return o}var b=(function(){var l=1000;return function(){return ++l}})();var j={};j=function(){this.listeners={};this.regexListeners=[]};j.prototype={on:function(o,r,n){o=c(this,this.on,o,k(arguments));if(o==this){return this}var q=o instanceof RegExp;var m=q?o.toString():o;var l=k(arguments);if(j.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",l)}var p={id:b(),scope:n||{},callback:r,args:l,regExp:o,eventType:m};if(!q){if(typeof this.listeners[m]!="undefined"){this.listeners[m].push(p)}else{this.listeners[m]=[p]}}else{this.regexListeners.push(p)}return this},off:function(p,q,t){p=c(this,this.off,p,[e,q,t]);if(p==this){return this}var n=p instanceof RegExp;var m=n?p.toString():p;var r=[];if(typeof q=="object"){t=q;q=e}var o=q==e;var s=t==e;if(j.DEFAULT.SHOW_LOG){console.log("off=>off event type:",p," all callback:",o," all scope:",s)}function l(u){return(o?true:u.callback==q)&&(s?true:u.scope==t)}if(!n){if(typeof this.listeners[m]!="undefined"){if(!(o&&s)){g(this.listeners[m],function(u,v){if(!l(v)){r.push(v)}else{}})}this.listeners[m]=r}}else{g(this.regexListeners,function(u,v){if(!(v.eventType===m&&l(v))){r.push(v)}else{}});this.regexListeners=r}return this},has:function(p,s,o){var r=p instanceof RegExp;var m=r?p.toString():p;var n=[].concat(this.listeners[m]);if(typeof s=="object"){o=s;s=e}if(n.length>0&&!r){var q=n.length;if(s===e&&o===e){return q>0}var l=g(n,function(t,v,w,u){if((o?v.scope==o:true)&&(s?v.callback==s:true)){u.stop(true)}});if(l){return true}}else{if(r){n=[].concat(this.regexListeners);var l=g(n,function(t,v,w,u){if(v.regExp.toString()==m&&(o?v.scope==o:true)&&(s?v.callback==s:true)){u.stop(true)}});if(l){return true}}}return false},emit:function(q){var m=this.eventFlow=this.eventFlow||[];var n=k(arguments);q=c(this,this.emit,q,n);if(q==this){return this}var r={id:q+"#"+b(),type:q,target:n.length>1?n[1]:{}};n=[r].concat(k(arguments,1));var p=[].concat(typeof this.listeners[q]=="undefined"?[]:this.listeners[q]);var l=this;function s(v){var t=[].concat(m);var u=false;r.stop=function(){u=true};r.isStopped=function(){return u};r.getArg=function(w){if(!i(r.args)||r.args.length-1")}};r.getLevel=function(){return t.length-1};g(v,function(x,C,A,z){if(C&&C.callback){var B=[].concat(n);if(j.DEFAULT.SHOW_LOG){console.log("emit=>event listener call arguments:",B)}r.args=[].concat(C.args);if(j.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",C)}try{if(j.DEFAULT.SHOW_LOG){console.log("event flow:",r.flow.getEventIdsPath())}var w=l.beforeTriggerListener;if(d(w)){w.apply(l,[C].concat(B))}C.callback.apply(C.scope,B);w=l.afterTriggerListener;if(d(w)){w.apply(l,[C].concat(B))}}catch(y){u=true;l.emit(j.DEFAULT.ERROR_EVENT_TYPE,y,C,B)}if(u){z.stop()}}})}var o=[].concat(this.regexListeners);g(o,function(t,u){if(u.regExp.test(q)){p.push(u)}});m.push(r);s(p);m.pop();return this}};var f=new j();var h=function(l){return f.emit.apply(f,k(arguments))};h.fn=j.prototype;h.DEFAULT=j.DEFAULT={SHOW_LOG:false,EVENT_TYPE_SPLIT_EXP:/,|\s/,ERROR_EVENT_TYPE:"EMIT_ERROR",EXCLUDE_NAMES:["aspect","before","after","around","isFunction","isArray","hit","slice","iterator"]};h.plugin=function(l){l(h);g(j.prototype,function(m,n){if(n&& +/*!EventBus["hasOwnProperty"](key) &&*/ +(!{}["hasOwnProperty"](m))&&d(n)&&j.DEFAULT.EXCLUDE_NAMES.indexOf(m)<0){h[m]=a(f,n)}})};h.plugin(function(l){l.fn.bind=l.fn.addEventListener=l.fn.on;l.fn.unbind=l.fn.removeEventListener=l.fn.off;l.fn.trigger=l.fn.dispatch=l.fn.emit;l.fn.hasEventListener=l.fn.has});h.plugin(function(l){l.fn.getCurrentEvent=function(){return[].concat(this.eventFlow).pop()};l.fn.getEarlyEvent=function(){return[].concat(this.eventFlow).shift()};l.fn.getClosestEvent=function(){return this.getCurrentEvent()?this.getCurrentEvent().flow.getClosestEvent():e}});h.plugin(function(l){l.fn.once=function(q,r,p){var m=this;var n=function(s){r.apply(this,k(arguments));m.off(q,n,p)};var o=k(arguments);o[1]=n;return m.on.apply(m,o)}});h.plugin(function(l){l.fn.flow=function(n){var o=k(arguments);if(i(n)){o=n}var m=this;g(o,function(p,q){if(q instanceof Object&&typeof q=="object"&&q.from!=e&&q.to!=e){m.redirect(q.from,q.to,q.where,q.processor)}});return m}});h.plugin(function(l){l.fn.redirect=function(n,q,r,p){var m=this;if(n==e||q==e||n==q){return m}var o=this.redirectScope=this.redirectScope||{};p=d(p)?p:function(s){s.setEmitArgs(h.slice(arguments,1))};this.on(n,(function(v,w,t){if(w==e){w=function(){return true}}if(w instanceof RegExp){var u=w;w=function(x){return u.test(x.type)}}if(d(w)){var s=[];return function(z){var x=k(arguments);if(w.apply(o,x)){var y=d(v)?v.apply(o,x):v;if(s.indexOf(t)<0&&y!=z.type&&y!=e){s.push(t);try{if(typeof y=="string"){y=y.trim().split(j.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(!(i(y))){y=[y]}g(y,function(A,D,E,C){if(D!=z.type){var B=k([].concat(x),1);z.setEmitArgs=function(F){B=F};z.getEmitArgs=function(){return[].concat(B)};z.getOriginType=function(){return n};z.getEndpoint=function(){return D};z.isRedirect=function(){return true};z.endpoints=z.endpoints||[];z.endpoints.push(D);p.apply(o,x);B=(i(B))?[""].concat(B):[].concat(x);B[0]=D;if(j.DEFAULT.SHOW_LOG){console.log("redirect=>redirect id:",z.id," origin:",n," ==> endpoint:",D)}m.emit.apply(m,B);if(z.isStopped()){C.stop(true)}}})}finally{s.pop()}}else{throw"redirect origin:"+n.toString()+" => endpoint:"+v.toString()+" is looping!"}}}}else{return function(x){if(j.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(q,r,b()),o);return m}});h.plugin(function(n){function m(v,u,s,t){var x=v[u];var w=u=="around";var y;if(w){var r=s(function(){return x.advice(this,arguments)});y={remove:function(){if(r){r=v=s=null}},advice:function(A,z){return r?r.apply(A,z):x.advice(A,z)}}}else{y={remove:function(){if(y.advice){var A=y.previous;var z=y.next;if(!z&&!A){delete v[u]}else{if(A){A.next=z}else{v[u]=z}if(z){z.previous=A}}v=s=y.advice=null}},id:v.nextId++,advice:s,receiveArguments:t}}if(x&&!w){if(u=="after"){while(x.next&&(x=x.next)){}x.next=y;y.previous=x}else{if(u=="before"){v[u]=y;y.next=x;x.previous=y}}}else{v[u]=y}return y}function l(r){return function(y,s,t,v){var x=y[s],w;if(!x||x.target!=y){y[s]=w=function(){var B=w.nextId;var z=arguments;var C=w.before;while(C){if(C.advice){z=C.advice.apply(this,z)||z}C=C.next}if(w.around){var A=w.around.advice(this,z)}var D=w.after;while(D&&D.id 1) { @@ -230,7 +245,7 @@ return isStop; }; event.getArg = function (index) { - if (event.args == undefined || !event.args instanceof Array || event.args.length - 1 < index)return undefined; + if (!isArray(event.args) || event.args.length - 1 < index)return undefined; return event.args[index]; }; event.flow = { @@ -265,11 +280,11 @@ try { if (EventBusClass.DEFAULT.SHOW_LOG) console.log("event flow:", event.flow.getEventIdsPath()); - var emitAspect = bus["beforeEmit"]; - if (emitAspect && typeof emitAspect == "function") emitAspect.apply(bus, [listener].concat(listenerArgs)); + var emitAspect = bus["beforeTriggerListener"]; + if (isFunction(emitAspect)) emitAspect.apply(bus, [listener].concat(listenerArgs)); listener.callback.apply(listener.scope, listenerArgs); - emitAspect = bus["afterEmit"]; - if (emitAspect && typeof emitAspect == "function") emitAspect.apply(bus, [listener].concat(listenerArgs)); + emitAspect = bus["afterTriggerListener"]; + if (isFunction(emitAspect)) emitAspect.apply(bus, [listener].concat(listenerArgs)); } catch (exception) { isStop = true; bus.emit(EventBusClass.DEFAULT.ERROR_EVENT_TYPE, exception, listener, listenerArgs); @@ -290,23 +305,6 @@ dispatchEvent(listeners); eventFlow.pop(); return this; - }, - getAllEvents: function () { - var str = ""; - for (var type in this.listeners) { - var numOfCallbacks = this.listeners[type].length; - for (var i = 0; i < numOfCallbacks; i++) { - var listener = this.listeners[type][i]; - str += listener.scope && listener.scope.className ? listener.scope.className : "anonymous"; - str += " listen for '" + type + "'\n"; - } - } - - iterator([].concat(this.regexListeners), function (index, listener) { - str += listener.scope && listener.scope.className ? listener.scope.className : "anonymous"; - str += " listen for '" + listener.eventType + "'\n"; - }); - return str; } }; @@ -317,24 +315,18 @@ return _EventBus_.emit.apply(_EventBus_, slice(arguments)); }; - var isFunction = function (fn) { - return fn && typeof fn === "function"; - }, - - isArray = function (array) { - return array && array.constructor.name == "Array"; - }, - - hit = function (object, fn) { - return function () { - return fn.apply(object, slice(arguments)); - } - }; - - //support extend. EventBus.fn = EventBusClass.prototype; + //default config + EventBus.DEFAULT = EventBusClass.DEFAULT = { + SHOW_LOG: false, + EVENT_TYPE_SPLIT_EXP: /,|\s/, + ERROR_EVENT_TYPE: "EMIT_ERROR", + EXCLUDE_NAMES: ["aspect", "before", "after", "around", "isFunction", "isArray", "hit", "slice", "iterator"] + }; + + /** * define EventBus plugin extend * examples: @@ -350,10 +342,13 @@ * }); * @param f */ + EventBus.plugin = function (f) { f(EventBus); iterator(EventBusClass.prototype, function (key, fn) { - if (fn && !EventBus["hasOwnProperty"](key) && isFunction(fn)) + if (fn && /*!EventBus["hasOwnProperty"](key) &&*/(!{}["hasOwnProperty"](key)) && + isFunction(fn) && + EventBusClass.DEFAULT.EXCLUDE_NAMES.indexOf(key) < 0) EventBus[key] = hit(_EventBus_, fn); }); }; @@ -366,13 +361,6 @@ eBus.fn.hasEventListener = eBus.fn.has; }); - //default config - EventBus.DEFAULT = EventBusClass.DEFAULT = { - SHOW_LOG: false, - EVENT_TYPE_SPLIT_EXP: /,|\s/, - ERROR_EVENT_TYPE: "EMIT_ERROR" - }; - EventBus.plugin(function (eBus) { eBus.fn.getCurrentEvent = function () { @@ -420,7 +408,7 @@ */ eBus.fn.flow = function (node) { var nodeMap = slice(arguments); - if (node instanceof Array) nodeMap = node; + if (isArray(node)) nodeMap = node; var bus = this; iterator(nodeMap, function (index, node) { if (node instanceof Object && typeof node == "object" && node['from'] != undefined && node['to'] != undefined) { @@ -449,9 +437,9 @@ var scope = this.redirectScope = this.redirectScope || {}; - processor = typeof processor == "function" ? processor : function (event) { - event.setEmitArgs(EventBus.slice(arguments, 1));//example: set emit endpoint event arguments - }; + processor = isFunction(processor) ? processor : function (event) { + event.setEmitArgs(EventBus.slice(arguments, 1));//example: set emit endpoint event arguments + }; this.on(origin, (function (endpoint, condition, nextId) {//Unified exception handling by emit method. if (condition == undefined) @@ -464,19 +452,19 @@ return exp.test(event.type); } } - if (typeof condition == "function") { + if (isFunction(condition)) { var stack = []; return function (event) {//trigger redirect var args = slice(arguments); if (condition.apply(scope, args)) {//trigger condition check - var eventType = typeof endpoint == "function" ? endpoint.apply(scope, args) : endpoint;//dynamic get endpoint + var eventType = isFunction(endpoint) ? endpoint.apply(scope, args) : endpoint;//dynamic get endpoint if (stack.indexOf(nextId) < 0 && eventType != event.type && eventType != undefined)//check redirect looping { stack.push(nextId); try { if (typeof eventType == "string") eventType = eventType.trim().split(EventBusClass.DEFAULT.EVENT_TYPE_SPLIT_EXP);//support string split by SPACE,COMMA char - if (!(eventType instanceof Array)) { + if (!(isArray(eventType))) { eventType = [eventType]; } iterator(eventType, function (index, type, array, iterator) {//support endpoint array @@ -500,7 +488,7 @@ event.endpoints = event.endpoints || []; event.endpoints.push(type); processor.apply(scope, args); - emitArgs = (emitArgs instanceof Array) ? [""].concat(emitArgs) : [].concat(args); + emitArgs = (isArray(emitArgs)) ? [""].concat(emitArgs) : [].concat(args); emitArgs[0] = type; if (EventBusClass.DEFAULT.SHOW_LOG) console.log("redirect=>redirect id:", event.id, " origin:", origin, " ==> endpoint:", type); @@ -531,136 +519,290 @@ }); EventBus.plugin(function (eBus) { - var aspect_cache = {}, old_fn = {}; - - function aspect(name, orientation, fn) { - var chain = aspect_cache[name] = eBus.isArray(aspect_cache[name]) ? aspect_cache[name] : []; - var old_aspect = eBus.fn[name]; - var isAspect = eBus.isFunction(old_aspect) && old_aspect.aspect; - if (!isAspect) { - old_fn[name] = eBus.fn[name]; - } - var handlerId = [orientation, name, eBus.nextId()].join("-"); - chain.push(handlerId); - - var handler = { - handlerId: handlerId, - fn: fn, - name: name, - orientation: orientation - }; + //remember: aspect code from dojo/aspect module + function advise(dispatcher, type, advice, receiveArguments) { + var previous = dispatcher[type]; + var around = type == "around"; + var signal; + if (around) { + var advised = advice(function () { + return previous.advice(this, arguments); + }); + signal = { + remove: function () { + if (advised) { + advised = dispatcher = advice = null; + } + }, + advice: function (target, args) { + return advised ? + advised.apply(target, args) : // called the advised function + previous.advice(target, args); // cancelled, skip to next one + } + }; + } else { + // create the remove handler + signal = { + remove: function () { + if (signal.advice) { + var previous = signal.previous; + var next = signal.next; + if (!next && !previous) { + delete dispatcher[type]; + } else { + if (previous) { + previous.next = next; + } else { + dispatcher[type] = next; + } + if (next) { + next.previous = previous; + } + } - function removeHandler() { - var index = chain.indexOf(handlerId); - chain.splice(index, 1); - delete aspect_cache[handlerId]; - if (chain.length == 0) { - eBus.fn[this.name] = old_fn[this.name]; - } + // remove the advice to signal that this signal has been removed + dispatcher = advice = signal.advice = null; + } + }, + id: dispatcher.nextId++, + advice: advice, + receiveArguments: receiveArguments + }; } - - function indexHandler(index) { - var old_index = chain.indexOf(this.handlerId); - if (old_index == index)return; - index = chain.length - index; - index = index > chain.length ? chain.length : (index < 0 ? 0 : index); - chain.splice(index, 0, this.handlerId); - old_index = index > old_index ? old_index : old_index + 1; - chain.splice(old_index, 1); + if (previous && !around) { + if (type == "after") { + // add the listener to the end of the list + // note that we had to change this loop a little bit to workaround a bizarre IE10 JIT bug + while (previous.next && (previous = previous.next)) { + } + previous.next = signal; + signal.previous = previous; + } else if (type == "before") { + // add to beginning + dispatcher[type] = signal; + signal.next = previous; + previous.previous = signal; + } + } else { + // around or first one just replaces + dispatcher[type] = signal; } + return signal; + } - handler.remove = eBus.hit(handler, removeHandler); - handler.index = eBus.hit(handler, indexHandler); - - aspect_cache[handlerId] = handler; - - if (!isAspect) { - eBus.fn[name] = function () { - var args = slice(arguments); - var bus = this; - var ret; - var handlerIds = [].concat(chain); - var handlerId; - while (handlerId = handlerIds.pop()) { - var fn = aspect_cache[handlerId].fn; - var orientation = aspect_cache[handlerId].orientation; - if (orientation === "before" || orientation === "around") { - ret = fn.apply(bus, [{ - name: name, - orientation: orientation, - args: args, - handlerId: handlerId, - remove: aspect_cache[handlerId].remove, - index: aspect_cache[handlerId].index - }]); + function aspect(type) { + return function (target, methodName, advice, receiveArguments) { + var existing = target[methodName], dispatcher; + if (!existing || existing.target != target) { + // no dispatcher in place + target[methodName] = dispatcher = function () { + var executionId = dispatcher.nextId; + // before advice + var args = arguments; + var before = dispatcher.before; + while (before) { + if (before.advice) { + args = before.advice.apply(this, args) || args; + } + before = before.next; } - - if (handlerIds.length == 0 && eBus.isFunction(old_fn[name])) - ret = old_fn[name].apply(bus, args); - - if (orientation === "after" || orientation === "around") { - ret = fn.apply(bus, [{ - name: name, - orientation: orientation, - args: args, - handlerId: handlerId, - remove: aspect_cache[handlerId].remove, - index: aspect_cache[handlerId].index - }, ret]); + // around advice + if (dispatcher.around) { + var results = dispatcher.around.advice(this, args); + } + // after advice + var after = dispatcher.after; + while (after && after.id < executionId) { + if (after.advice) { + if (after.receiveArguments) { + var newResults = after.advice.apply(this, args); + // change the return value only if a new value was returned + results = newResults === undefined ? results : newResults; + } else { + results = after.advice.call(this, results, args); + } + } + after = after.next; } - return ret; + return results; + }; + if (existing) { + dispatcher.around = { + advice: function (target, args) { + return existing.apply(target, args); + } + }; } - }; - - eBus.fn[name].aspect = { - orientation: orientation, - next: handler - }; - } - return handler; + dispatcher.target = target; + dispatcher.nextId = dispatcher.nextId || 0; + } + var results = advise((dispatcher || existing), type, advice, receiveArguments); + advice = null; + return results; + }; } - eBus.aspect = aspect; + var after = aspect("after"); + /*===== + after = function(target, methodName, advice, receiveArguments){ + // summary: + // The "after" export of the aspect module is a function that can be used to attach + // "after" advice to a method. This function will be executed after the original method + // is executed. By default the function will be called with a single argument, the return + // value of the original method, or the the return value of the last executed advice (if a previous one exists). + // The fourth (optional) argument can be set to true to so the function receives the original + // arguments (from when the original method was called) rather than the return value. + // If there are multiple "after" advisors, they are executed in the order they were registered. + // target: Object + // This is the target object + // methodName: String + // This is the name of the method to attach to. + // advice: Function + // This is function to be called after the original method + // receiveArguments: Boolean? + // If this is set to true, the advice function receives the original arguments (from when the original mehtod + // was called) rather than the return value of the original/previous method. + // returns: + // A signal object that can be used to cancel the advice. If remove() is called on this signal object, it will + // stop the advice function from being executed. + }; + =====*/ + + var before = aspect("before"); + /*===== + before = function(target, methodName, advice){ + // summary: + // The "before" export of the aspect module is a function that can be used to attach + // "before" advice to a method. This function will be executed before the original method + // is executed. This function will be called with the arguments used to call the method. + // This function may optionally return an array as the new arguments to use to call + // the original method (or the previous, next-to-execute before advice, if one exists). + // If the before method doesn't return anything (returns undefined) the original arguments + // will be preserved. + // If there are multiple "before" advisors, they are executed in the reverse order they were registered. + // target: Object + // This is the target object + // methodName: String + // This is the name of the method to attach to. + // advice: Function + // This is function to be called before the original method + }; + =====*/ + + var around = aspect("around"); + /*===== + around = function(target, methodName, advice){ + // summary: + // The "around" export of the aspect module is a function that can be used to attach + // "around" advice to a method. The advisor function is immediately executed when + // the around() is called, is passed a single argument that is a function that can be + // called to continue execution of the original method (or the next around advisor). + // The advisor function should return a function, and this function will be called whenever + // the method is called. It will be called with the arguments used to call the method. + // Whatever this function returns will be returned as the result of the method call (unless after advise changes it). + // example: + // If there are multiple "around" advisors, the most recent one is executed first, + // which can then delegate to the next one and so on. For example: + // | around(obj, "foo", function(originalFoo){ + // | return function(){ + // | var start = new Date().getTime(); + // | var results = originalFoo.apply(this, arguments); // call the original + // | var end = new Date().getTime(); + // | console.log("foo execution took " + (end - start) + " ms"); + // | return results; + // | }; + // | }); + // target: Object + // This is the target object + // methodName: String + // This is the name of the method to attach to. + // advice: Function + // This is function to be called around the original method + }; + =====*/ /** - * the handler called before named method invocation - * @param name - * @param handler - * @return {EventBus} + * The provided advising function will be called before the main method is called + * @param methodName + * @param advisingFunction + * @return {Handler} */ - eBus.before = function (name, handler) { - return eBus.aspect(name, "before", handler); + eBus.before = function (methodName, advisingFunction) { + return before(_EventBus_, methodName, advisingFunction); }; /** - * the handler called after named method invocation - * @param name - * @param handler - * @return {EventBus} + * The provided advising function will be called after the main method is called + * @param methodName + * @param advisingFunction + * @param receiveArguments + * @return {Handler} */ - eBus.after = function (name, handler) { - return eBus.aspect(name, "after", handler); + eBus.after = function (methodName, advisingFunction, receiveArguments) { + return after(_EventBus_, methodName, advisingFunction, receiveArguments); }; /** - * the handler called before and after named method invocation + * the advisingFactory called before and after named method invocation * @param name - * @param handler - * @return {EventBus} + * @param advisingFactory + * @return {Handler} */ - eBus.around = function (name, handler) { - return eBus.aspect(name, "around", handler); + eBus.around = function (name, advisingFactory) { + return eBus.aspect(_EventBus_, name, advisingFactory); }; + + eBus.aspect = { + around: around, + before: before, + after: after + } }); EventBus.plugin(function (eBus) { - eBus.fn.beforeEmit = function () { + /** + * the stub called before listener trigger + * @param listener + * @param event + * @param otherListenerArg.. + */ + eBus.fn.beforeTriggerListener = function (listener, event, otherListenerArg) { + + }; + /** + * the stub called after listener trigger + * @param listener + * @param event + * @param otherListenerArg.. + */ + eBus.fn.afterTriggerListener = function (listener, event, otherListenerArg) { }; - eBus.fn.afterEmit = function () { + eBus.DEFAULT.EXCLUDE_NAMES.push("beforeTriggerListener", "afterTriggerListener"); + + function isMatch(eventType, event, condition, args) { + if (typeof eventType == "string") { + eventType = new RegExp(eventType); + } + return eBus.isFunction(condition) ? + (eventType.test(event.type) && condition.apply(this, args)) : + eventType.test(event.type) + } + + eBus.beforeTriggerListener = function (eventType, fn, condition) { + return eBus.before("beforeTriggerListener", function (listener, event) { + if (isMatch(eventType, event, condition, slice(arguments))) + return fn.apply(this, eBus.slice(arguments)); + }); + }; + eBus.afterTriggerListener = function (eventType, fn, condition) { + return eBus.before("afterTriggerListener", function (listener, event) { + if (isMatch(eventType, event, condition, slice(arguments))) + return fn.apply(this, eBus.slice(arguments)); + }); }; }); From 35c93daa16869b0764b68cf6135a1e6d6f085893 Mon Sep 17 00:00:00 2001 From: tony_shen Date: Wed, 28 Dec 2016 16:05:02 +0800 Subject: [PATCH 19/20] modified aspect method --- example/node/aspect-test.js | 31 +++ example/node/flow-test.js | 20 +- lib/eventbus.min.js | 4 +- src/EventBus.js | 450 ++++++++++++++++++++++++------------ 4 files changed, 331 insertions(+), 174 deletions(-) create mode 100644 example/node/aspect-test.js diff --git a/example/node/aspect-test.js b/example/node/aspect-test.js new file mode 100644 index 0000000..1f4d5e8 --- /dev/null +++ b/example/node/aspect-test.js @@ -0,0 +1,31 @@ +/** + * Created by bona on 2016/12/28. + */ + +var ebus = require('../../lib/eventbus.min'); + +ebus.before("emit", function (event) { + console.log("before-emit,event type:", event); + console.log("closest event path: ", this.getCurrentEvent() ? this.getCurrentEvent().flow.getEventIdsPath() : undefined); + if(event=="ready")return [event,{name:"new object"}]; +}); + +ebus.after("emit",function (event) { + console.log("after-emit,event type:",event); +},true); + +ebus.on("ready",function (event,o) { + console.log("ready",o); +}); + +ebus.redirect("ready","end"); + +ebus.on("end",function (event,o) { + console.log("end event,",event,o); +}); + +ebus.beforeTriggerListener(/end/,function (listener,event,o) { + console.log("beforeTriggerListener,",event,o); +}); + +ebus("ready"); \ No newline at end of file diff --git a/example/node/flow-test.js b/example/node/flow-test.js index 61895b9..5b672f8 100644 --- a/example/node/flow-test.js +++ b/example/node/flow-test.js @@ -10,31 +10,13 @@ var printEventStack = function (event) { console.log("event flow :", event.flow.getEventIdsPath()); }; -ebus.before("emit", function (handler) { - console.log("before emit=>", handler); - // console.log("early event: ", this.getEarlyEvent() ? this.getEarlyEvent().id : undefined); - console.log("closest event path: ", this.getCurrentEvent() ? this.getCurrentEvent().flow.getEventIdsPath() : undefined); - handler.remove(); -}); - -ebus.after("beforeEmit", function (handler, result) { - console.log("after beforeEmit=>", handler); - console.log("current event path: ", this.getCurrentEvent() ? this.getCurrentEvent().flow.getEventIdsPath() : undefined); -}).remove(); - -ebus.before("beforeEmit", function (handler) { - // console.log(handler); - console.log("beforeEmit,current event path: ", this.getCurrentEvent() ? this.getCurrentEvent().flow.getEventIdsPath() : undefined); - handler.remove(); -}); - ebus.on("start", function (event) { console.log("The game is start..."); }) .on("chase", function (event) { console.log("overtaken"); printEventStack(event); - ebus.emit("overtaken"); + ebus("overtaken"); }) .flow( {from: "ready", to: "start"}, diff --git a/lib/eventbus.min.js b/lib/eventbus.min.js index 25d38d7..a50c22e 100644 --- a/lib/eventbus.min.js +++ b/lib/eventbus.min.js @@ -1 +1,3 @@ -(function(a,b){if(typeof exports==="object"&&typeof module==="object"){module.exports=b()}else{if(typeof define==="function"&&define.amd){define("EventBus",[],b)}else{if(typeof exports==="object"){exports.EventBus=b()}else{a.EventBus=b()}}}})(this,function(){function d(m,l){m=m||[];var k={stop:function(i){this.isStopped=true;this.result=i},isStopped:false,result:undefined};for(var j in m){l(j,m[j],m,k);if(k.isStopped){break}}if(k.isStopped){return k.result}}function h(k,j,i){if(j>k.length){return[]}return[].slice.call(k,j===undefined?0:j,i===undefined?k.length:i)||[]}function b(m,j,l,i){if(typeof l=="string"||l instanceof Array){var k=l;if(typeof l=="string"){k=l.trim().split(e.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(k.length>1){d(k,function(n,o){i[0]=o;j.apply(m,i)});return m}else{l=k[0]}}return l}var c=(function(){var i=1000;return function(){return ++i}})();var e={};e=function(){this.listeners={};this.regexListeners=[]};e.prototype={on:function(l,o,k){l=b(this,this.on,l,h(arguments));if(l==this){return this}var n=l instanceof RegExp;var j=n?l.toString():l;var i=h(arguments);if(e.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",i)}var m={id:c(),scope:k||{},callback:o,args:i,regExp:l,eventType:j};if(!n){if(typeof this.listeners[j]!="undefined"){this.listeners[j].push(m)}else{this.listeners[j]=[m]}}else{this.regexListeners.push(m)}return this},off:function(m,n,q){m=b(this,this.off,m,[undefined,n,q]);if(m==this){return this}var k=m instanceof RegExp;var j=k?m.toString():m;var o=[];if(typeof n=="object"){q=n;n=undefined}var l=n==undefined;var p=q==undefined;if(e.DEFAULT.SHOW_LOG){console.log("off=>off event type:",m," all callback:",l," all scope:",p)}function i(r){return(l?true:r.callback==n)&&(p?true:r.scope==q)}if(!k){if(typeof this.listeners[j]!="undefined"){if(!(l&&p)){d(this.listeners[j],function(r,s){if(!i(s)){o.push(s)}else{}})}this.listeners[j]=o}}else{d(this.regexListeners,function(r,s){if(!(s.eventType===j&&i(s))){o.push(s)}else{}});this.regexListeners=o}return this},has:function(m,p,l){var o=m instanceof RegExp;var j=o?m.toString():m;var k=[].concat(this.listeners[j]);if(typeof p=="object"){l=p;p=undefined}if(k.length>0&&!o){var n=k.length;if(p===undefined&&l===undefined){return n>0}var i=d(k,function(q,s,t,r){if((l?s.scope==l:true)&&(p?s.callback==p:true)){r.stop(true)}});if(i){return true}}else{if(o){k=[].concat(this.regexListeners);var i=d(k,function(q,s,t,r){if(s.regExp.toString()==j&&(l?s.scope==l:true)&&(p?s.callback==p:true)){r.stop(true)}});if(i){return true}}}return false},emit:function(n){var j=this.eventFlow=this.eventFlow||[];var k=h(arguments);n=b(this,this.emit,n,k);if(n==this){return this}var o={id:n+"#"+c(),type:n,target:k.length>1?k[1]:{}};k=[o].concat(h(arguments,1));var m=[].concat(typeof this.listeners[n]=="undefined"?[]:this.listeners[n]);var i=this;function p(s){var q=[].concat(j);var r=false;o.stop=function(){r=true};o.isStopped=function(){return r};o.getArg=function(t){if(o.args==undefined||!o.args instanceof Array||o.args.length-1")}};o.getLevel=function(){return q.length-1};d(s,function(u,z,x,w){if(z&&z.callback){var y=[].concat(k);if(e.DEFAULT.SHOW_LOG){console.log("emit=>event listener call arguments:",y)}o.args=[].concat(z.args);if(e.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",z)}try{if(e.DEFAULT.SHOW_LOG){console.log("event flow:",o.flow.getEventIdsPath())}var t=i.beforeEmit;if(t&&typeof t=="function"){t.apply(i,[z].concat(y))}z.callback.apply(z.scope,y);t=i.afterEmit;if(t&&typeof t=="function"){t.apply(i,[z].concat(y))}}catch(v){r=true;i.emit(e.DEFAULT.ERROR_EVENT_TYPE,v,z,y)}if(r){w.stop()}}})}var l=[].concat(this.regexListeners);d(l,function(q,r){if(r.regExp.test(n)){m.push(r)}});j.push(o);p(m);j.pop();return this},getAllEvents:function(){var n="";for(var k in this.listeners){var m=this.listeners[k].length;for(var j=0;jredirect id:",w.id," origin:",k," ==> endpoint:",A)}j.emit.apply(j,y);if(w.isStopped()){z.stop(true)}}})}finally{p.pop()}}else{throw"redirect origin:"+k.toString()+" => endpoint:"+s.toString()+" is looping!"}}}}else{return function(u){if(e.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(n,o,c()),l);return j}});a.plugin(function(k){var j={};function i(m,l,o){var n=j[m]=k.isArray(j[m])?j[m]:[];var p=k.fn[m];var q=k.isFunction(p);k.fn[m]=function(){var t=h(arguments);var r=this;var s;if(l==="before"||l==="around"){s=o.apply(r,[{name:m,orientation:l,args:t}])}if(q){s=p.apply(r,t)}if(l==="after"||l==="around"){s=o.apply(r,[{name:m,orientation:l,args:t},s])}return s};k.fn[m].aspect={orientation:l,next:p};return k}k.aspect=i;k.before=function(l,m){return k.aspect(l,"before",m)};k.after=function(l,m){return k.aspect(l,"after",m)};k.around=function(l,m){return k.aspect(l,"around",m)}});a.plugin(function(i){i.fn.beforeEmit=function(){};i.fn.afterEmit=function(){}});var f=function(i,j){return function(){return j.apply(i,h(arguments))}};d(e.prototype,function(i,j){if(j&&!a.hasOwnProperty(i)&&typeof j=="function"){a[i]=f(g,j)}});a.plugin(function(i){i.slice=h;i.nextId=c;i.iterator=d;i.hit=f;i.isFunction=function(j){return j&&typeof j==="function"};i.isArray=function(j){return j&&j.constructor.name=="Array"}});return a}); \ No newline at end of file +(function(a,b){if(typeof exports==="object"&&typeof module==="object"){module.exports=b()}else{if(typeof define==="function"&&define.amd){define("EventBus",[],b)}else{if(typeof exports==="object"){exports.EventBus=b()}else{a.EventBus=b()}}}})(this,function(){var e;var d=function(l){return l&&typeof l==="function"},i=function(l){return l&&l.constructor.name==="Array"},a=function(l,m){return function(){return m.apply(l,k(arguments))}};function g(o,n){o=o||[];var m={stop:function(p){this.isStopped=true;this.result=p},isStopped:false,result:e};for(var l in o){n(l,o[l],o,m);if(m.isStopped){break}}if(m.isStopped){return m.result}}function k(n,m,l){if(m>n.length){return[]}return[].slice.call(n,m===e?0:m,l===e?n.length:l)||[]}function c(p,m,o,l){if(typeof o=="string"||i(o)){var n=o;if(typeof o=="string"){n=o.trim().split(j.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(n.length>1){g(n,function(q,r){l[0]=r;m.apply(p,l)});return p}else{o=n[0]}}return o}var b=(function(){var l=1000;return function(){return ++l}})();var j={};j=function(){this.listeners={};this.regexListeners=[]};j.prototype={on:function(o,r,n){o=c(this,this.on,o,k(arguments));if(o==this){return this}var q=o instanceof RegExp;var m=q?o.toString():o;var l=k(arguments);if(j.DEFAULT.SHOW_LOG){console.log("on=>listener args is ",l)}var p={id:b(),scope:n||{},callback:r,args:l,regExp:o,eventType:m};if(!q){if(typeof this.listeners[m]!="undefined"){this.listeners[m].push(p)}else{this.listeners[m]=[p]}}else{this.regexListeners.push(p)}return this},off:function(p,q,t){p=c(this,this.off,p,[e,q,t]);if(p==this){return this}var n=p instanceof RegExp;var m=n?p.toString():p;var r=[];if(typeof q=="object"){t=q;q=e}var o=q==e;var s=t==e;if(j.DEFAULT.SHOW_LOG){console.log("off=>off event type:",p," all callback:",o," all scope:",s)}function l(u){return(o?true:u.callback==q)&&(s?true:u.scope==t)}if(!n){if(typeof this.listeners[m]!="undefined"){if(!(o&&s)){g(this.listeners[m],function(u,v){if(!l(v)){r.push(v)}else{}})}this.listeners[m]=r}}else{g(this.regexListeners,function(u,v){if(!(v.eventType===m&&l(v))){r.push(v)}else{}});this.regexListeners=r}return this},has:function(p,s,o){var r=p instanceof RegExp;var m=r?p.toString():p;var n=[].concat(this.listeners[m]);if(typeof s=="object"){o=s;s=e}if(n.length>0&&!r){var q=n.length;if(s===e&&o===e){return q>0}var l=g(n,function(t,v,w,u){if((o?v.scope==o:true)&&(s?v.callback==s:true)){u.stop(true)}});if(l){return true}}else{if(r){n=[].concat(this.regexListeners);var l=g(n,function(t,v,w,u){if(v.regExp.toString()==m&&(o?v.scope==o:true)&&(s?v.callback==s:true)){u.stop(true)}});if(l){return true}}}return false},emit:function(q){var m=this.eventFlow=this.eventFlow||[];var n=k(arguments);q=c(this,this.emit,q,n);if(q==this){return this}var r={id:q+"#"+b(),type:q,target:n.length>1?n[1]:{}};n=[r].concat(k(arguments,1));var p=[].concat(typeof this.listeners[q]=="undefined"?[]:this.listeners[q]);var l=this;function s(v){var t=[].concat(m);var u=false;r.stop=function(){u=true};r.isStopped=function(){return u};r.getArg=function(w){if(!i(r.args)||r.args.length-1")}};r.getLevel=function(){return t.length-1};g(v,function(x,C,A,z){if(C&&C.callback){var B=[].concat(n);if(j.DEFAULT.SHOW_LOG){console.log("emit=>event listener call arguments:",B)}r.args=[].concat(C.args);if(j.DEFAULT.SHOW_LOG){console.log("emit=>fire event listener:",C)}try{if(j.DEFAULT.SHOW_LOG){console.log("event flow:",r.flow.getEventIdsPath())}var w=l.beforeTriggerListener;if(d(w)){w.apply(l,[C].concat(B))}C.callback.apply(C.scope,B);w=l.afterTriggerListener;if(d(w)){w.apply(l,[C].concat(B))}}catch(y){u=true;l.emit(j.DEFAULT.ERROR_EVENT_TYPE,y,C,B)}if(u){z.stop()}}})}var o=[].concat(this.regexListeners);g(o,function(t,u){if(u.regExp.test(q)){p.push(u)}});m.push(r);s(p);m.pop();return this}};var f=new j();var h=function(l){return f.emit.apply(f,k(arguments))};h.fn=j.prototype;h.DEFAULT=j.DEFAULT={SHOW_LOG:false,EVENT_TYPE_SPLIT_EXP:/,|\s/,ERROR_EVENT_TYPE:"EMIT_ERROR",EXCLUDE_NAMES:["aspect","before","after","around","isFunction","isArray","hit","slice","iterator"]};h.plugin=function(l){l(h);g(j.prototype,function(m,n){if(n&& +/*!EventBus["hasOwnProperty"](key) &&*/ +(!{}["hasOwnProperty"](m))&&d(n)&&j.DEFAULT.EXCLUDE_NAMES.indexOf(m)<0){h[m]=a(f,n)}})};h.plugin(function(l){l.fn.bind=l.fn.addEventListener=l.fn.on;l.fn.unbind=l.fn.removeEventListener=l.fn.off;l.fn.trigger=l.fn.dispatch=l.fn.emit;l.fn.hasEventListener=l.fn.has});h.plugin(function(l){l.fn.getCurrentEvent=function(){return[].concat(this.eventFlow).pop()};l.fn.getEarlyEvent=function(){return[].concat(this.eventFlow).shift()};l.fn.getClosestEvent=function(){return this.getCurrentEvent()?this.getCurrentEvent().flow.getClosestEvent():e}});h.plugin(function(l){l.fn.once=function(q,r,p){var m=this;var n=function(s){r.apply(this,k(arguments));m.off(q,n,p)};var o=k(arguments);o[1]=n;return m.on.apply(m,o)}});h.plugin(function(l){l.fn.flow=function(n){var o=k(arguments);if(i(n)){o=n}var m=this;g(o,function(p,q){if(q instanceof Object&&typeof q=="object"&&q.from!=e&&q.to!=e){m.redirect(q.from,q.to,q.where,q.processor)}});return m}});h.plugin(function(l){l.fn.redirect=function(n,q,r,p){var m=this;if(n==e||q==e||n==q){return m}var o=this.redirectScope=this.redirectScope||{};p=d(p)?p:function(s){s.setEmitArgs(h.slice(arguments,1))};this.on(n,(function(v,w,t){if(w==e){w=function(){return true}}if(w instanceof RegExp){var u=w;w=function(x){return u.test(x.type)}}if(d(w)){var s=[];return function(z){var x=k(arguments);if(w.apply(o,x)){var y=d(v)?v.apply(o,x):v;if(s.indexOf(t)<0&&y!=z.type&&y!=e){s.push(t);try{if(typeof y=="string"){y=y.trim().split(j.DEFAULT.EVENT_TYPE_SPLIT_EXP)}if(!(i(y))){y=[y]}g(y,function(A,D,E,C){if(D!=z.type){var B=k([].concat(x),1);z.setEmitArgs=function(F){B=F};z.getEmitArgs=function(){return[].concat(B)};z.getOriginType=function(){return n};z.getEndpoint=function(){return D};z.isRedirect=function(){return true};z.endpoints=z.endpoints||[];z.endpoints.push(D);p.apply(o,x);B=(i(B))?[""].concat(B):[].concat(x);B[0]=D;if(j.DEFAULT.SHOW_LOG){console.log("redirect=>redirect id:",z.id," origin:",n," ==> endpoint:",D)}m.emit.apply(m,B);if(z.isStopped()){C.stop(true)}}})}finally{s.pop()}}else{throw"redirect origin:"+n.toString()+" => endpoint:"+v.toString()+" is looping!"}}}}else{return function(x){if(j.DEFAULT.SHOW_LOG){console.log("redirect=>redirect condition must set function or RegExp!")}}}})(q,r,b()),o);return m}});h.plugin(function(n){function m(v,u,s,t){var x=v[u];var w=u=="around";var y;if(w){var r=s(function(){return x.advice(this,arguments)});y={remove:function(){if(r){r=v=s=null}},advice:function(A,z){return r?r.apply(A,z):x.advice(A,z)}}}else{y={remove:function(){if(y.advice){var A=y.previous;var z=y.next;if(!z&&!A){delete v[u]}else{if(A){A.next=z}else{v[u]=z}if(z){z.previous=A}}v=s=y.advice=null}},id:v.nextId++,advice:s,receiveArguments:t}}if(x&&!w){if(u=="after"){while(x.next&&(x=x.next)){}x.next=y;y.previous=x}else{if(u=="before"){v[u]=y;y.next=x;x.previous=y}}}else{v[u]=y}return y}function l(r){return function(y,s,t,v){var x=y[s],w;if(!x||x.target!=y){y[s]=w=function(){var B=w.nextId;var z=arguments;var C=w.before;while(C){if(C.advice){z=C.advice.apply(this,z)||z}C=C.next}if(w.around){var A=w.around.advice(this,z)}var D=w.after;while(D&&D.id 1) { @@ -230,7 +245,7 @@ return isStop; }; event.getArg = function (index) { - if (event.args == undefined || !event.args instanceof Array || event.args.length - 1 < index)return undefined; + if (!isArray(event.args) || event.args.length - 1 < index)return undefined; return event.args[index]; }; event.flow = { @@ -265,11 +280,11 @@ try { if (EventBusClass.DEFAULT.SHOW_LOG) console.log("event flow:", event.flow.getEventIdsPath()); - var emitAspect = bus["beforeEmit"]; - if (emitAspect && typeof emitAspect == "function") emitAspect.apply(bus, [listener].concat(listenerArgs)); + var emitAspect = bus["beforeTriggerListener"]; + if (isFunction(emitAspect)) emitAspect.apply(bus, [listener].concat(listenerArgs)); listener.callback.apply(listener.scope, listenerArgs); - emitAspect = bus["afterEmit"]; - if (emitAspect && typeof emitAspect == "function") emitAspect.apply(bus, [listener].concat(listenerArgs)); + emitAspect = bus["afterTriggerListener"]; + if (isFunction(emitAspect)) emitAspect.apply(bus, [listener].concat(listenerArgs)); } catch (exception) { isStop = true; bus.emit(EventBusClass.DEFAULT.ERROR_EVENT_TYPE, exception, listener, listenerArgs); @@ -290,23 +305,6 @@ dispatchEvent(listeners); eventFlow.pop(); return this; - }, - getAllEvents: function () { - var str = ""; - for (var type in this.listeners) { - var numOfCallbacks = this.listeners[type].length; - for (var i = 0; i < numOfCallbacks; i++) { - var listener = this.listeners[type][i]; - str += listener.scope && listener.scope.className ? listener.scope.className : "anonymous"; - str += " listen for '" + type + "'\n"; - } - } - - iterator([].concat(this.regexListeners), function (index, listener) { - str += listener.scope && listener.scope.className ? listener.scope.className : "anonymous"; - str += " listen for '" + listener.eventType + "'\n"; - }); - return str; } }; @@ -317,24 +315,18 @@ return _EventBus_.emit.apply(_EventBus_, slice(arguments)); }; - var isFunction = function (fn) { - return fn && typeof fn === "function"; - }, - - isArray = function (array) { - return array && array.constructor.name == "Array"; - }, - - hit = function (object, fn) { - return function () { - return fn.apply(object, slice(arguments)); - } - }; - - //support extend. EventBus.fn = EventBusClass.prototype; + //default config + EventBus.DEFAULT = EventBusClass.DEFAULT = { + SHOW_LOG: false, + EVENT_TYPE_SPLIT_EXP: /,|\s/, + ERROR_EVENT_TYPE: "EMIT_ERROR", + EXCLUDE_NAMES: ["aspect", "before", "after", "around", "isFunction", "isArray", "hit", "slice", "iterator"] + }; + + /** * define EventBus plugin extend * examples: @@ -350,10 +342,13 @@ * }); * @param f */ + EventBus.plugin = function (f) { f(EventBus); iterator(EventBusClass.prototype, function (key, fn) { - if (fn && !EventBus["hasOwnProperty"](key) && isFunction(fn)) + if (fn && /*!EventBus["hasOwnProperty"](key) &&*/(!{}["hasOwnProperty"](key)) && + isFunction(fn) && + EventBusClass.DEFAULT.EXCLUDE_NAMES.indexOf(key) < 0) EventBus[key] = hit(_EventBus_, fn); }); }; @@ -366,13 +361,6 @@ eBus.fn.hasEventListener = eBus.fn.has; }); - //default config - EventBus.DEFAULT = EventBusClass.DEFAULT = { - SHOW_LOG: false, - EVENT_TYPE_SPLIT_EXP: /,|\s/, - ERROR_EVENT_TYPE: "EMIT_ERROR" - }; - EventBus.plugin(function (eBus) { eBus.fn.getCurrentEvent = function () { @@ -420,7 +408,7 @@ */ eBus.fn.flow = function (node) { var nodeMap = slice(arguments); - if (node instanceof Array) nodeMap = node; + if (isArray(node)) nodeMap = node; var bus = this; iterator(nodeMap, function (index, node) { if (node instanceof Object && typeof node == "object" && node['from'] != undefined && node['to'] != undefined) { @@ -449,9 +437,9 @@ var scope = this.redirectScope = this.redirectScope || {}; - processor = typeof processor == "function" ? processor : function (event) { - event.setEmitArgs(EventBus.slice(arguments, 1));//example: set emit endpoint event arguments - }; + processor = isFunction(processor) ? processor : function (event) { + event.setEmitArgs(EventBus.slice(arguments, 1));//example: set emit endpoint event arguments + }; this.on(origin, (function (endpoint, condition, nextId) {//Unified exception handling by emit method. if (condition == undefined) @@ -464,19 +452,19 @@ return exp.test(event.type); } } - if (typeof condition == "function") { + if (isFunction(condition)) { var stack = []; return function (event) {//trigger redirect var args = slice(arguments); if (condition.apply(scope, args)) {//trigger condition check - var eventType = typeof endpoint == "function" ? endpoint.apply(scope, args) : endpoint;//dynamic get endpoint + var eventType = isFunction(endpoint) ? endpoint.apply(scope, args) : endpoint;//dynamic get endpoint if (stack.indexOf(nextId) < 0 && eventType != event.type && eventType != undefined)//check redirect looping { stack.push(nextId); try { if (typeof eventType == "string") eventType = eventType.trim().split(EventBusClass.DEFAULT.EVENT_TYPE_SPLIT_EXP);//support string split by SPACE,COMMA char - if (!(eventType instanceof Array)) { + if (!(isArray(eventType))) { eventType = [eventType]; } iterator(eventType, function (index, type, array, iterator) {//support endpoint array @@ -500,7 +488,7 @@ event.endpoints = event.endpoints || []; event.endpoints.push(type); processor.apply(scope, args); - emitArgs = (emitArgs instanceof Array) ? [""].concat(emitArgs) : [].concat(args); + emitArgs = (isArray(emitArgs)) ? [""].concat(emitArgs) : [].concat(args); emitArgs[0] = type; if (EventBusClass.DEFAULT.SHOW_LOG) console.log("redirect=>redirect id:", event.id, " origin:", origin, " ==> endpoint:", type); @@ -531,136 +519,290 @@ }); EventBus.plugin(function (eBus) { - var aspect_cache = {}, old_fn = {}; - - function aspect(name, orientation, fn) { - var chain = aspect_cache[name] = eBus.isArray(aspect_cache[name]) ? aspect_cache[name] : []; - var old_aspect = eBus.fn[name]; - var isAspect = eBus.isFunction(old_aspect) && old_aspect.aspect; - if (!isAspect) { - old_fn[name] = eBus.fn[name]; - } - var handlerId = [orientation, name, eBus.nextId()].join("-"); - chain.push(handlerId); - - var handler = { - handlerId: handlerId, - fn: fn, - name: name, - orientation: orientation - }; + //remember: aspect code from dojo/aspect module + function advise(dispatcher, type, advice, receiveArguments) { + var previous = dispatcher[type]; + var around = type == "around"; + var signal; + if (around) { + var advised = advice(function () { + return previous.advice(this, arguments); + }); + signal = { + remove: function () { + if (advised) { + advised = dispatcher = advice = null; + } + }, + advice: function (target, args) { + return advised ? + advised.apply(target, args) : // called the advised function + previous.advice(target, args); // cancelled, skip to next one + } + }; + } else { + // create the remove handler + signal = { + remove: function () { + if (signal.advice) { + var previous = signal.previous; + var next = signal.next; + if (!next && !previous) { + delete dispatcher[type]; + } else { + if (previous) { + previous.next = next; + } else { + dispatcher[type] = next; + } + if (next) { + next.previous = previous; + } + } - function removeHandler() { - var index = chain.indexOf(handlerId); - chain.splice(index, 1); - delete aspect_cache[handlerId]; - if (chain.length == 0) { - eBus.fn[this.name] = old_fn[this.name]; - } + // remove the advice to signal that this signal has been removed + dispatcher = advice = signal.advice = null; + } + }, + id: dispatcher.nextId++, + advice: advice, + receiveArguments: receiveArguments + }; } - - function indexHandler(index) { - var old_index = chain.indexOf(this.handlerId); - if (old_index == index)return; - index = chain.length - index; - index = index > chain.length ? chain.length : (index < 0 ? 0 : index); - chain.splice(index, 0, this.handlerId); - old_index = index > old_index ? old_index : old_index + 1; - chain.splice(old_index, 1); + if (previous && !around) { + if (type == "after") { + // add the listener to the end of the list + // note that we had to change this loop a little bit to workaround a bizarre IE10 JIT bug + while (previous.next && (previous = previous.next)) { + } + previous.next = signal; + signal.previous = previous; + } else if (type == "before") { + // add to beginning + dispatcher[type] = signal; + signal.next = previous; + previous.previous = signal; + } + } else { + // around or first one just replaces + dispatcher[type] = signal; } + return signal; + } - handler.remove = eBus.hit(handler, removeHandler); - handler.index = eBus.hit(handler, indexHandler); - - aspect_cache[handlerId] = handler; - - if (!isAspect) { - eBus.fn[name] = function () { - var args = slice(arguments); - var bus = this; - var ret; - var handlerIds = [].concat(chain); - var handlerId; - while (handlerId = handlerIds.pop()) { - var fn = aspect_cache[handlerId].fn; - var orientation = aspect_cache[handlerId].orientation; - if (orientation === "before" || orientation === "around") { - ret = fn.apply(bus, [{ - name: name, - orientation: orientation, - args: args, - handlerId: handlerId, - remove: aspect_cache[handlerId].remove, - index: aspect_cache[handlerId].index - }]); + function aspect(type) { + return function (target, methodName, advice, receiveArguments) { + var existing = target[methodName], dispatcher; + if (!existing || existing.target != target) { + // no dispatcher in place + target[methodName] = dispatcher = function () { + var executionId = dispatcher.nextId; + // before advice + var args = arguments; + var before = dispatcher.before; + while (before) { + if (before.advice) { + args = before.advice.apply(this, args) || args; + } + before = before.next; } - - if (handlerIds.length == 0 && eBus.isFunction(old_fn[name])) - ret = old_fn[name].apply(bus, args); - - if (orientation === "after" || orientation === "around") { - ret = fn.apply(bus, [{ - name: name, - orientation: orientation, - args: args, - handlerId: handlerId, - remove: aspect_cache[handlerId].remove, - index: aspect_cache[handlerId].index - }, ret]); + // around advice + if (dispatcher.around) { + var results = dispatcher.around.advice(this, args); + } + // after advice + var after = dispatcher.after; + while (after && after.id < executionId) { + if (after.advice) { + if (after.receiveArguments) { + var newResults = after.advice.apply(this, args); + // change the return value only if a new value was returned + results = newResults === undefined ? results : newResults; + } else { + results = after.advice.call(this, results, args); + } + } + after = after.next; } - return ret; + return results; + }; + if (existing) { + dispatcher.around = { + advice: function (target, args) { + return existing.apply(target, args); + } + }; } - }; - - eBus.fn[name].aspect = { - orientation: orientation, - next: handler - }; - } - return handler; + dispatcher.target = target; + dispatcher.nextId = dispatcher.nextId || 0; + } + var results = advise((dispatcher || existing), type, advice, receiveArguments); + advice = null; + return results; + }; } - eBus.aspect = aspect; + var after = aspect("after"); + /*===== + after = function(target, methodName, advice, receiveArguments){ + // summary: + // The "after" export of the aspect module is a function that can be used to attach + // "after" advice to a method. This function will be executed after the original method + // is executed. By default the function will be called with a single argument, the return + // value of the original method, or the the return value of the last executed advice (if a previous one exists). + // The fourth (optional) argument can be set to true to so the function receives the original + // arguments (from when the original method was called) rather than the return value. + // If there are multiple "after" advisors, they are executed in the order they were registered. + // target: Object + // This is the target object + // methodName: String + // This is the name of the method to attach to. + // advice: Function + // This is function to be called after the original method + // receiveArguments: Boolean? + // If this is set to true, the advice function receives the original arguments (from when the original mehtod + // was called) rather than the return value of the original/previous method. + // returns: + // A signal object that can be used to cancel the advice. If remove() is called on this signal object, it will + // stop the advice function from being executed. + }; + =====*/ + + var before = aspect("before"); + /*===== + before = function(target, methodName, advice){ + // summary: + // The "before" export of the aspect module is a function that can be used to attach + // "before" advice to a method. This function will be executed before the original method + // is executed. This function will be called with the arguments used to call the method. + // This function may optionally return an array as the new arguments to use to call + // the original method (or the previous, next-to-execute before advice, if one exists). + // If the before method doesn't return anything (returns undefined) the original arguments + // will be preserved. + // If there are multiple "before" advisors, they are executed in the reverse order they were registered. + // target: Object + // This is the target object + // methodName: String + // This is the name of the method to attach to. + // advice: Function + // This is function to be called before the original method + }; + =====*/ + + var around = aspect("around"); + /*===== + around = function(target, methodName, advice){ + // summary: + // The "around" export of the aspect module is a function that can be used to attach + // "around" advice to a method. The advisor function is immediately executed when + // the around() is called, is passed a single argument that is a function that can be + // called to continue execution of the original method (or the next around advisor). + // The advisor function should return a function, and this function will be called whenever + // the method is called. It will be called with the arguments used to call the method. + // Whatever this function returns will be returned as the result of the method call (unless after advise changes it). + // example: + // If there are multiple "around" advisors, the most recent one is executed first, + // which can then delegate to the next one and so on. For example: + // | around(obj, "foo", function(originalFoo){ + // | return function(){ + // | var start = new Date().getTime(); + // | var results = originalFoo.apply(this, arguments); // call the original + // | var end = new Date().getTime(); + // | console.log("foo execution took " + (end - start) + " ms"); + // | return results; + // | }; + // | }); + // target: Object + // This is the target object + // methodName: String + // This is the name of the method to attach to. + // advice: Function + // This is function to be called around the original method + }; + =====*/ /** - * the handler called before named method invocation - * @param name - * @param handler - * @return {EventBus} + * The provided advising function will be called before the main method is called + * @param methodName + * @param advisingFunction + * @return {Handler} */ - eBus.before = function (name, handler) { - return eBus.aspect(name, "before", handler); + eBus.before = function (methodName, advisingFunction) { + return before(_EventBus_, methodName, advisingFunction); }; /** - * the handler called after named method invocation - * @param name - * @param handler - * @return {EventBus} + * The provided advising function will be called after the main method is called + * @param methodName + * @param advisingFunction + * @param receiveArguments + * @return {Handler} */ - eBus.after = function (name, handler) { - return eBus.aspect(name, "after", handler); + eBus.after = function (methodName, advisingFunction, receiveArguments) { + return after(_EventBus_, methodName, advisingFunction, receiveArguments); }; /** - * the handler called before and after named method invocation + * the advisingFactory called before and after named method invocation * @param name - * @param handler - * @return {EventBus} + * @param advisingFactory + * @return {Handler} */ - eBus.around = function (name, handler) { - return eBus.aspect(name, "around", handler); + eBus.around = function (name, advisingFactory) { + return eBus.aspect(_EventBus_, name, advisingFactory); }; + + eBus.aspect = { + around: around, + before: before, + after: after + } }); EventBus.plugin(function (eBus) { - eBus.fn.beforeEmit = function () { + /** + * the stub called before listener trigger + * @param listener + * @param event + * @param otherListenerArg.. + */ + eBus.fn.beforeTriggerListener = function (listener, event, otherListenerArg) { + + }; + /** + * the stub called after listener trigger + * @param listener + * @param event + * @param otherListenerArg.. + */ + eBus.fn.afterTriggerListener = function (listener, event, otherListenerArg) { }; - eBus.fn.afterEmit = function () { + eBus.DEFAULT.EXCLUDE_NAMES.push("beforeTriggerListener", "afterTriggerListener"); + + function isMatch(eventType, event, condition, args) { + if (typeof eventType == "string") { + eventType = new RegExp(eventType); + } + return eBus.isFunction(condition) ? + (eventType.test(event.type) && condition.apply(this, args)) : + eventType.test(event.type) + } + + eBus.beforeTriggerListener = function (eventType, fn, condition) { + return eBus.before("beforeTriggerListener", function (listener, event) { + if (isMatch(eventType, event, condition, slice(arguments))) + return fn.apply(this, eBus.slice(arguments)); + }); + }; + eBus.afterTriggerListener = function (eventType, fn, condition) { + return eBus.before("afterTriggerListener", function (listener, event) { + if (isMatch(eventType, event, condition, slice(arguments))) + return fn.apply(this, eBus.slice(arguments)); + }); }; }); From 5e860b16b25a9f13617be6e9707d73ca28025f0f Mon Sep 17 00:00:00 2001 From: tony_shen Date: Wed, 28 Dec 2016 17:01:19 +0800 Subject: [PATCH 20/20] update README.md --- README.md | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e062a5d..183c8d5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ### In a browser -Download [eventbus.min.js](https://raw.githubusercontent.com/krasimir/EventBus/master/lib/eventbus.min.js) and add it to your page. +Download [eventbus.min.js](https://raw.githubusercontent.com/bonashen/EventBus/master/lib/eventbus.min.js) and add it to your page. ### In Node @@ -102,13 +102,6 @@ EventBus.flow({from:'click',to:'onClick'},{from:'onClick',to:'labelClick',where: }}); ``` -### `getEvents` - -For debugging purpose, it prints out the added listeners. - -```js -EventBus.getEvents() -``` ## Usage @@ -137,6 +130,8 @@ EventBus.dispatch("my_function_event"); EventBus.trigger("my_function_event"); //or EventBus.emit("my_function_event"); +//or +EventBus("my_function_event"); ``` ## Keeping the scope @@ -294,4 +289,38 @@ EventBus.on("onClick",function(event) { }); EventBus.emit("click"); +``` + +## Example of usage EventBus.plugin +EventBus support define plugin. +```javascript +EventBus.plugin(function(eBus) { + eBus.fn.newFeature = function() { + return this; + }; + + //define static method + eBus.newStaticMethod = function() { + + }; + +}); +``` + +## Example of usage EventBus aspect +EventBus support before after and around aspect. The aspect code from dojo/aspect module. +```javascript +EventBus.plugin(function(eBus){ + //advice EventBus emit + eBus.before("emit",function(event){ + if(event=="ready") + return eBus.slice(arguments).concat([{name:"new object"}]);//append new object to emit + }); +}); +//aspect utils example +var scope = {name:"bona",sayHello:function(message){console.log(this.name,message)}}; +var handler = EventBus.aspect.before(scope,"sayHello",function(message) { + return [[",",message,"!"].join("")]; +}); +scope.sayHello("hello world"); ``` \ No newline at end of file