diff --git a/example/amd/js/libs/postal/postal.js b/example/amd/js/libs/postal/postal.js index 828811c..5945bac 100755 --- a/example/amd/js/libs/postal/postal.js +++ b/example/amd/js/libs/postal/postal.js @@ -42,7 +42,7 @@ }; var DistinctPredicate = function () { var previous = []; - + return function ( data ) { var isDistinct = !_.any( previous, function ( p ) { if ( _.isObject( data ) || _.isArray( data ) ) { @@ -59,17 +59,19 @@ var ChannelDefinition = function ( channelName ) { this.channel = channelName || DEFAULT_CHANNEL; }; - + ChannelDefinition.prototype.subscribe = function () { return arguments.length === 1 ? new SubscriptionDefinition( this.channel, arguments[0].topic, arguments[0].callback ) : new SubscriptionDefinition( this.channel, arguments[0], arguments[1] ); }; - + ChannelDefinition.prototype.publish = function () { var envelope = arguments.length === 1 ? - (Object.prototype.toString.call(arguments[0]) === '[object String]' ? - { topic: arguments[0] } : arguments[0]) : { topic : arguments[0], data : arguments[1] }; + (Object.prototype.toString.call(arguments[0]) === '[object String]' ? + { topic: arguments[0] } : + arguments[0]) : + { topic : arguments[0], data : arguments[1] }; envelope.channel = this.channel; return postal.configuration.bus.publish( envelope ); }; @@ -90,22 +92,24 @@ } ); postal.configuration.bus.subscribe( this ); }; - + SubscriptionDefinition.prototype = { unsubscribe : function () { - this.inactive = true; - postal.configuration.bus.unsubscribe( this ); - postal.configuration.bus.publish( { - channel : SYSTEM_CHANNEL, - topic : "subscription.removed", - data : { - event : "subscription.removed", - channel : this.channel, - topic : this.topic - } - } ); + if(!this.inactive) { + this.inactive = true; + postal.configuration.bus.unsubscribe( this ); + postal.configuration.bus.publish( { + channel : SYSTEM_CHANNEL, + topic : "subscription.removed", + data : { + event : "subscription.removed", + channel : this.channel, + topic : this.topic + } + } ); + } }, - + defer : function () { var fn = this.callback; this.callback = function ( data ) { @@ -115,7 +119,7 @@ }; return this; }, - + disposeAfter : function ( maxCalls ) { if ( _.isNaN( maxCalls ) || maxCalls <= 0 ) { throw "The value provided to disposeAfter (maxCalls) must be a number greater than zero."; @@ -124,29 +128,29 @@ var dispose = _.after( maxCalls, _.bind( function () { this.unsubscribe(); }, this ) ); - + this.callback = function () { fn.apply( this.context, arguments ); dispose(); }; return this; }, - + distinctUntilChanged : function () { this.withConstraint( new ConsecutiveDistinctPredicate() ); return this; }, - + distinct : function () { this.withConstraint( new DistinctPredicate() ); return this; }, - + once : function () { this.disposeAfter( 1 ); return this; }, - + withConstraint : function ( predicate ) { if ( !_.isFunction( predicate ) ) { throw "Predicate constraint must be a function"; @@ -154,7 +158,7 @@ this.constraints.push( predicate ); return this; }, - + withConstraints : function ( predicates ) { var self = this; if ( _.isArray( predicates ) ) { @@ -164,12 +168,12 @@ } return self; }, - + withContext : function ( context ) { this.context = context; return this; }, - + withDebounce : function ( milliseconds ) { if ( _.isNaN( milliseconds ) ) { throw "Milliseconds must be a number"; @@ -178,7 +182,7 @@ this.callback = _.debounce( fn, milliseconds ); return this; }, - + withDelay : function ( milliseconds ) { if ( _.isNaN( milliseconds ) ) { throw "Milliseconds must be a number"; @@ -191,7 +195,7 @@ }; return this; }, - + withThrottle : function ( milliseconds ) { if ( _.isNaN( milliseconds ) ) { throw "Milliseconds must be a number"; @@ -200,7 +204,7 @@ this.callback = _.throttle( fn, milliseconds ); return this; }, - + subscribe : function ( callback ) { this.callback = callback; return this; @@ -209,7 +213,7 @@ var bindingsResolver = { cache : {}, regex : {}, - + compare : function ( binding, topic ) { var pattern, rgx, prevSegment, result = (this.cache[topic] && this.cache[topic][binding]); if(typeof result !== "undefined") { @@ -237,32 +241,32 @@ this.cache[topic][binding] = result = rgx.test( topic ); return result; }, - + reset : function () { this.cache = {}; this.regex = {}; } }; - var fireSub = function(subDef, envelope) { - if ( !subDef.inactive && postal.configuration.resolver.compare( subDef.topic, envelope.topic ) ) { - if ( _.all( subDef.constraints, function ( constraint ) { - return constraint.call( subDef.context, envelope.data, envelope ); - } ) ) { - if ( typeof subDef.callback === 'function' ) { - subDef.callback.call( subDef.context, envelope.data, envelope ); - } - } - } + var fireSub = function ( subDef, envelope ) { + if ( !subDef.inactive && postal.configuration.resolver.compare( subDef.topic, envelope.topic ) ) { + if ( _.all( subDef.constraints, function ( constraint ) { + return constraint.call( subDef.context, envelope.data, envelope ); + } ) ) { + if ( typeof subDef.callback === 'function' ) { + subDef.callback.call( subDef.context, envelope.data, envelope ); + } + } + } }; - + var pubInProgress = 0; var unSubQueue = []; - var clearUnSubQueue = function() { - while(unSubQueue.length) { + var clearUnSubQueue = function () { + while ( unSubQueue.length ) { unSubQueue.shift().unsubscribe(); } }; - + var localBus = { addWireTap : function ( callback ) { var self = this; @@ -274,7 +278,7 @@ } }; }, - + publish : function ( envelope ) { ++pubInProgress; envelope.timeStamp = new Date(); @@ -291,12 +295,12 @@ } } ); } - if (--pubInProgress == 0) { + if ( --pubInProgress === 0 ) { clearUnSubQueue(); } return envelope; }, - + reset : function () { if ( this.subscriptions ) { _.each( this.subscriptions, function ( channel ) { @@ -309,7 +313,7 @@ this.subscriptions = {}; } }, - + subscribe : function ( subDef ) { var idx, found, fn, channel = this.subscriptions[subDef.channel], subs; if ( !channel ) { @@ -322,20 +326,20 @@ subs.push( subDef ); return subDef; }, - + subscriptions : {}, - + wireTaps : [], - + unsubscribe : function ( config ) { - if (pubInProgress) { - unSubQueue.push(config); + if ( pubInProgress ) { + unSubQueue.push( config ); return; } if ( this.subscriptions[config.channel][config.topic] ) { var len = this.subscriptions[config.channel][config.topic].length, idx = 0; - while(idx < len) { + while ( idx < len ) { if ( this.subscriptions[config.channel][config.topic][idx] === config ) { this.subscriptions[config.channel][config.topic].splice( idx, 1 ); break; @@ -353,27 +357,27 @@ DEFAULT_CHANNEL : DEFAULT_CHANNEL, SYSTEM_CHANNEL : SYSTEM_CHANNEL }, - + ChannelDefinition : ChannelDefinition, SubscriptionDefinition : SubscriptionDefinition, - + channel : function ( channelName ) { return new ChannelDefinition( channelName ); }, - + subscribe : function ( options ) { return new SubscriptionDefinition( options.channel || DEFAULT_CHANNEL, options.topic, options.callback ); }, - + publish : function ( envelope ) { envelope.channel = envelope.channel || DEFAULT_CHANNEL; return postal.configuration.bus.publish( envelope ); }, - + addWireTap : function ( callback ) { return this.configuration.bus.addWireTap( callback ); }, - + linkChannels : function ( sources, destinations ) { var result = []; sources = !_.isArray( sources ) ? [sources] : sources; @@ -399,7 +403,7 @@ } ); return result; }, - + utils : { getSubscribersFor : function () { var channel = arguments[ 0 ], @@ -414,7 +418,7 @@ } return []; }, - + reset : function () { postal.configuration.bus.reset(); postal.configuration.resolver.reset(); diff --git a/example/amd/js/libs/postal/postal.min.js b/example/amd/js/libs/postal/postal.min.js index 17d610c..7d045ec 100755 --- a/example/amd/js/libs/postal/postal.min.js +++ b/example/amd/js/libs/postal/postal.min.js @@ -4,4 +4,4 @@ License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license) Version 0.8.5 */ -(function(t,n){"object"==typeof module&&module.exports?module.exports=function(t){return t=t||require("underscore"),n(t)}:"function"==typeof define&&define.amd?define(["underscore"],function(i){return n(i,t)}):t.postal=n(t._,t)})(this,function(t){var n="/",i="postal",s=function(){var n;return function(i){var s=!1;return t.isString(i)?(s=i===n,n=i):(s=t.isEqual(i,n),n=t.clone(i)),!s}},e=function(){var n=[];return function(i){var s=!t.any(n,function(n){return t.isObject(i)||t.isArray(i)?t.isEqual(i,n):i===n});return s&&n.push(i),s}},c=function(t){this.channel=t||n};c.prototype.subscribe=function(){return 1===arguments.length?new r(this.channel,arguments[0].topic,arguments[0].callback):new r(this.channel,arguments[0],arguments[1])},c.prototype.publish=function(){var t=1===arguments.length?"[object String]"===Object.prototype.toString.call(arguments[0])?{topic:arguments[0]}:arguments[0]:{topic:arguments[0],data:arguments[1]};return t.channel=this.channel,p.configuration.bus.publish(t)};var r=function(t,n,s){this.channel=t,this.topic=n,this.callback=s,this.constraints=[],this.context=null,p.configuration.bus.publish({channel:i,topic:"subscription.created",data:{event:"subscription.created",channel:t,topic:n}}),p.configuration.bus.subscribe(this)};r.prototype={unsubscribe:function(){this.inactive=!0,p.configuration.bus.unsubscribe(this),p.configuration.bus.publish({channel:i,topic:"subscription.removed",data:{event:"subscription.removed",channel:this.channel,topic:this.topic}})},defer:function(){var t=this.callback;return this.callback=function(n){setTimeout(function(){t(n)},0)},this},disposeAfter:function(n){if(t.isNaN(n)||0>=n)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var i=this.callback,s=t.after(n,t.bind(function(){this.unsubscribe()},this));return this.callback=function(){i.apply(this.context,arguments),s()},this},distinctUntilChanged:function(){return this.withConstraint(new s),this},distinct:function(){return this.withConstraint(new e),this},once:function(){return this.disposeAfter(1),this},withConstraint:function(n){if(!t.isFunction(n))throw"Predicate constraint must be a function";return this.constraints.push(n),this},withConstraints:function(n){var i=this;return t.isArray(n)&&t.each(n,function(t){i.withConstraint(t)}),i},withContext:function(t){return this.context=t,this},withDebounce:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.debounce(i,n),this},withDelay:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=function(t){setTimeout(function(){i(t)},n)},this},withThrottle:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.throttle(i,n),this},subscribe:function(t){return this.callback=t,this}};var o={cache:{},regex:{},compare:function(n,i){var s,e,c,r=this.cache[i]&&this.cache[i][n];return r!==undefined?r:((e=this.regex[n])||(s="^"+t.map(n.split("."),function(t){var n="";return c&&(n="#"!==c?"\\.\\b":"\\b"),n+="#"===t?"[\\s\\S]*":"*"===t?"[^.]+":t,c=t,n}).join("")+"$",e=this.regex[n]=RegExp(s)),this.cache[i]=this.cache[i]||{},this.cache[i][n]=r=e.test(i),r)},reset:function(){this.cache={},this.regex={}}},u=function(n,i){!n.inactive&&p.configuration.resolver.compare(n.topic,i.topic)&&t.all(n.constraints,function(t){return t.call(n.context,i.data,i)})&&"function"==typeof n.callback&&n.callback.call(n.context,i.data,i)},a=!1,h=[],l={addWireTap:function(t){var n=this;return n.wireTaps.push(t),function(){var i=n.wireTaps.indexOf(t);-1!==i&&n.wireTaps.splice(i,1)}},publish:function(n){return a=!0,n.timeStamp=new Date,t.each(this.wireTaps,function(t){t(n.data,n)}),this.subscriptions[n.channel]&&t.each(this.subscriptions[n.channel],function(t){for(var i,s=0,e=t.length;e>s;)(i=t[s++])&&u(i,n)}),a=!1,n},reset:function(){this.subscriptions&&(t.each(this.subscriptions,function(n){t.each(n,function(t){for(;t.length;)t.pop().unsubscribe()})}),this.subscriptions={})},subscribe:function(t){var n,i=this.subscriptions[t.channel];return i||(i=this.subscriptions[t.channel]={}),n=this.subscriptions[t.channel][t.topic],n||(n=this.subscriptions[t.channel][t.topic]=[]),n.push(t),t},subscriptions:{},wireTaps:[],unsubscribe:function(t){if(a)return h.push(t),undefined;if(this.subscriptions[t.channel][t.topic])for(var n=this.subscriptions[t.channel][t.topic].length,i=0;n>i;){if(this.subscriptions[t.channel][t.topic][i]===t){this.subscriptions[t.channel][t.topic].splice(i,1);break}i+=1}}};l.subscriptions[i]={};var p={configuration:{bus:l,resolver:o,DEFAULT_CHANNEL:n,SYSTEM_CHANNEL:i},ChannelDefinition:c,SubscriptionDefinition:r,channel:function(t){return new c(t)},subscribe:function(t){return new r(t.channel||n,t.topic,t.callback)},publish:function(t){return t.channel=t.channel||n,p.configuration.bus.publish(t)},addWireTap:function(t){return this.configuration.bus.addWireTap(t)},linkChannels:function(i,s){var e=[];return i=t.isArray(i)?i:[i],s=t.isArray(s)?s:[s],t.each(i,function(i){i.topic||"#",t.each(s,function(s){var c=s.channel||n;e.push(p.subscribe({channel:i.channel||n,topic:i.topic||"#",callback:function(n,i){var e=t.clone(i);e.topic=t.isFunction(s.topic)?s.topic(i.topic):s.topic||i.topic,e.channel=c,e.data=n,p.publish(e)}}))})}),e},utils:{getSubscribersFor:function(){var t=arguments[0],n=arguments[1];return 1===arguments.length&&(t=arguments[0].channel||p.configuration.DEFAULT_CHANNEL,n=arguments[0].topic),p.configuration.bus.subscriptions[t]&&Object.prototype.hasOwnProperty.call(p.configuration.bus.subscriptions[t],n)?p.configuration.bus.subscriptions[t][n]:[]},reset:function(){p.configuration.bus.reset(),p.configuration.resolver.reset()}}};return p}); \ No newline at end of file +(function(t,n){"object"==typeof module&&module.exports?module.exports=function(t){return t=t||require("underscore"),n(t)}:"function"==typeof define&&define.amd?define(["underscore"],function(i){return n(i,t)}):t.postal=n(t._,t)})(this,function(t){var n="/",i="postal",s=function(){var n;return function(i){var s=!1;return t.isString(i)?(s=i===n,n=i):(s=t.isEqual(i,n),n=t.clone(i)),!s}},e=function(){var n=[];return function(i){var s=!t.any(n,function(n){return t.isObject(i)||t.isArray(i)?t.isEqual(i,n):i===n});return s&&n.push(i),s}},c=function(t){this.channel=t||n};c.prototype.subscribe=function(){return 1===arguments.length?new r(this.channel,arguments[0].topic,arguments[0].callback):new r(this.channel,arguments[0],arguments[1])},c.prototype.publish=function(){var t=1===arguments.length?"[object String]"===Object.prototype.toString.call(arguments[0])?{topic:arguments[0]}:arguments[0]:{topic:arguments[0],data:arguments[1]};return t.channel=this.channel,b.configuration.bus.publish(t)};var r=function(t,n,s){this.channel=t,this.topic=n,this.callback=s,this.constraints=[],this.context=null,b.configuration.bus.publish({channel:i,topic:"subscription.created",data:{event:"subscription.created",channel:t,topic:n}}),b.configuration.bus.subscribe(this)};r.prototype={unsubscribe:function(){this.inactive||(this.inactive=!0,b.configuration.bus.unsubscribe(this),b.configuration.bus.publish({channel:i,topic:"subscription.removed",data:{event:"subscription.removed",channel:this.channel,topic:this.topic}}))},defer:function(){var t=this.callback;return this.callback=function(n){setTimeout(function(){t(n)},0)},this},disposeAfter:function(n){if(t.isNaN(n)||0>=n)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var i=this.callback,s=t.after(n,t.bind(function(){this.unsubscribe()},this));return this.callback=function(){i.apply(this.context,arguments),s()},this},distinctUntilChanged:function(){return this.withConstraint(new s),this},distinct:function(){return this.withConstraint(new e),this},once:function(){return this.disposeAfter(1),this},withConstraint:function(n){if(!t.isFunction(n))throw"Predicate constraint must be a function";return this.constraints.push(n),this},withConstraints:function(n){var i=this;return t.isArray(n)&&t.each(n,function(t){i.withConstraint(t)}),i},withContext:function(t){return this.context=t,this},withDebounce:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.debounce(i,n),this},withDelay:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=function(t){setTimeout(function(){i(t)},n)},this},withThrottle:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.throttle(i,n),this},subscribe:function(t){return this.callback=t,this}};var o={cache:{},regex:{},compare:function(n,i){var s,e,c,r=this.cache[i]&&this.cache[i][n];return r!==undefined?r:((e=this.regex[n])||(s="^"+t.map(n.split("."),function(t){var n="";return c&&(n="#"!==c?"\\.\\b":"\\b"),n+="#"===t?"[\\s\\S]*":"*"===t?"[^.]+":t,c=t,n}).join("")+"$",e=this.regex[n]=RegExp(s)),this.cache[i]=this.cache[i]||{},this.cache[i][n]=r=e.test(i),r)},reset:function(){this.cache={},this.regex={}}},u=function(n,i){!n.inactive&&b.configuration.resolver.compare(n.topic,i.topic)&&t.all(n.constraints,function(t){return t.call(n.context,i.data,i)})&&"function"==typeof n.callback&&n.callback.call(n.context,i.data,i)},a=0,h=[],l=function(){for(;h.length;)h.shift().unsubscribe()},p={addWireTap:function(t){var n=this;return n.wireTaps.push(t),function(){var i=n.wireTaps.indexOf(t);-1!==i&&n.wireTaps.splice(i,1)}},publish:function(n){return++a,n.timeStamp=new Date,t.each(this.wireTaps,function(t){t(n.data,n)}),this.subscriptions[n.channel]&&t.each(this.subscriptions[n.channel],function(t){for(var i,s=0,e=t.length;e>s;)(i=t[s++])&&u(i,n)}),0===--a&&l(),n},reset:function(){this.subscriptions&&(t.each(this.subscriptions,function(n){t.each(n,function(t){for(;t.length;)t.pop().unsubscribe()})}),this.subscriptions={})},subscribe:function(t){var n,i=this.subscriptions[t.channel];return i||(i=this.subscriptions[t.channel]={}),n=this.subscriptions[t.channel][t.topic],n||(n=this.subscriptions[t.channel][t.topic]=[]),n.push(t),t},subscriptions:{},wireTaps:[],unsubscribe:function(t){if(a)return h.push(t),undefined;if(this.subscriptions[t.channel][t.topic])for(var n=this.subscriptions[t.channel][t.topic].length,i=0;n>i;){if(this.subscriptions[t.channel][t.topic][i]===t){this.subscriptions[t.channel][t.topic].splice(i,1);break}i+=1}}};p.subscriptions[i]={};var b={configuration:{bus:p,resolver:o,DEFAULT_CHANNEL:n,SYSTEM_CHANNEL:i},ChannelDefinition:c,SubscriptionDefinition:r,channel:function(t){return new c(t)},subscribe:function(t){return new r(t.channel||n,t.topic,t.callback)},publish:function(t){return t.channel=t.channel||n,b.configuration.bus.publish(t)},addWireTap:function(t){return this.configuration.bus.addWireTap(t)},linkChannels:function(i,s){var e=[];return i=t.isArray(i)?i:[i],s=t.isArray(s)?s:[s],t.each(i,function(i){i.topic||"#",t.each(s,function(s){var c=s.channel||n;e.push(b.subscribe({channel:i.channel||n,topic:i.topic||"#",callback:function(n,i){var e=t.clone(i);e.topic=t.isFunction(s.topic)?s.topic(i.topic):s.topic||i.topic,e.channel=c,e.data=n,b.publish(e)}}))})}),e},utils:{getSubscribersFor:function(){var t=arguments[0],n=arguments[1];return 1===arguments.length&&(t=arguments[0].channel||b.configuration.DEFAULT_CHANNEL,n=arguments[0].topic),b.configuration.bus.subscriptions[t]&&Object.prototype.hasOwnProperty.call(b.configuration.bus.subscriptions[t],n)?b.configuration.bus.subscriptions[t][n]:[]},reset:function(){b.configuration.bus.reset(),b.configuration.resolver.reset()}}};return b}); \ No newline at end of file diff --git a/example/standard/js/postal.js b/example/standard/js/postal.js index 83ca5a1..5945bac 100755 --- a/example/standard/js/postal.js +++ b/example/standard/js/postal.js @@ -68,8 +68,10 @@ ChannelDefinition.prototype.publish = function () { var envelope = arguments.length === 1 ? - (Object.prototype.toString.call(arguments[0]) === '[object String]' ? - { topic: arguments[0] } : arguments[0]) : { topic : arguments[0], data : arguments[1] }; + (Object.prototype.toString.call(arguments[0]) === '[object String]' ? + { topic: arguments[0] } : + arguments[0]) : + { topic : arguments[0], data : arguments[1] }; envelope.channel = this.channel; return postal.configuration.bus.publish( envelope ); }; @@ -93,17 +95,19 @@ SubscriptionDefinition.prototype = { unsubscribe : function () { - this.inactive = true; - postal.configuration.bus.unsubscribe( this ); - postal.configuration.bus.publish( { - channel : SYSTEM_CHANNEL, - topic : "subscription.removed", - data : { - event : "subscription.removed", - channel : this.channel, - topic : this.topic - } - } ); + if(!this.inactive) { + this.inactive = true; + postal.configuration.bus.unsubscribe( this ); + postal.configuration.bus.publish( { + channel : SYSTEM_CHANNEL, + topic : "subscription.removed", + data : { + event : "subscription.removed", + channel : this.channel, + topic : this.topic + } + } ); + } }, defer : function () { @@ -243,22 +247,22 @@ this.regex = {}; } }; - var fireSub = function(subDef, envelope) { - if ( !subDef.inactive && postal.configuration.resolver.compare( subDef.topic, envelope.topic ) ) { - if ( _.all( subDef.constraints, function ( constraint ) { - return constraint.call( subDef.context, envelope.data, envelope ); - } ) ) { - if ( typeof subDef.callback === 'function' ) { - subDef.callback.call( subDef.context, envelope.data, envelope ); - } - } - } + var fireSub = function ( subDef, envelope ) { + if ( !subDef.inactive && postal.configuration.resolver.compare( subDef.topic, envelope.topic ) ) { + if ( _.all( subDef.constraints, function ( constraint ) { + return constraint.call( subDef.context, envelope.data, envelope ); + } ) ) { + if ( typeof subDef.callback === 'function' ) { + subDef.callback.call( subDef.context, envelope.data, envelope ); + } + } + } }; var pubInProgress = 0; var unSubQueue = []; - var clearUnSubQueue = function() { - while(unSubQueue.length) { + var clearUnSubQueue = function () { + while ( unSubQueue.length ) { unSubQueue.shift().unsubscribe(); } }; @@ -291,7 +295,7 @@ } } ); } - if (--pubInProgress == 0) { + if ( --pubInProgress === 0 ) { clearUnSubQueue(); } return envelope; @@ -328,14 +332,14 @@ wireTaps : [], unsubscribe : function ( config ) { - if (pubInProgress) { - unSubQueue.push(config); + if ( pubInProgress ) { + unSubQueue.push( config ); return; } if ( this.subscriptions[config.channel][config.topic] ) { var len = this.subscriptions[config.channel][config.topic].length, idx = 0; - while(idx < len) { + while ( idx < len ) { if ( this.subscriptions[config.channel][config.topic][idx] === config ) { this.subscriptions[config.channel][config.topic].splice( idx, 1 ); break; diff --git a/example/standard/js/postal.min.js b/example/standard/js/postal.min.js index 17d610c..7d045ec 100755 --- a/example/standard/js/postal.min.js +++ b/example/standard/js/postal.min.js @@ -4,4 +4,4 @@ License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license) Version 0.8.5 */ -(function(t,n){"object"==typeof module&&module.exports?module.exports=function(t){return t=t||require("underscore"),n(t)}:"function"==typeof define&&define.amd?define(["underscore"],function(i){return n(i,t)}):t.postal=n(t._,t)})(this,function(t){var n="/",i="postal",s=function(){var n;return function(i){var s=!1;return t.isString(i)?(s=i===n,n=i):(s=t.isEqual(i,n),n=t.clone(i)),!s}},e=function(){var n=[];return function(i){var s=!t.any(n,function(n){return t.isObject(i)||t.isArray(i)?t.isEqual(i,n):i===n});return s&&n.push(i),s}},c=function(t){this.channel=t||n};c.prototype.subscribe=function(){return 1===arguments.length?new r(this.channel,arguments[0].topic,arguments[0].callback):new r(this.channel,arguments[0],arguments[1])},c.prototype.publish=function(){var t=1===arguments.length?"[object String]"===Object.prototype.toString.call(arguments[0])?{topic:arguments[0]}:arguments[0]:{topic:arguments[0],data:arguments[1]};return t.channel=this.channel,p.configuration.bus.publish(t)};var r=function(t,n,s){this.channel=t,this.topic=n,this.callback=s,this.constraints=[],this.context=null,p.configuration.bus.publish({channel:i,topic:"subscription.created",data:{event:"subscription.created",channel:t,topic:n}}),p.configuration.bus.subscribe(this)};r.prototype={unsubscribe:function(){this.inactive=!0,p.configuration.bus.unsubscribe(this),p.configuration.bus.publish({channel:i,topic:"subscription.removed",data:{event:"subscription.removed",channel:this.channel,topic:this.topic}})},defer:function(){var t=this.callback;return this.callback=function(n){setTimeout(function(){t(n)},0)},this},disposeAfter:function(n){if(t.isNaN(n)||0>=n)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var i=this.callback,s=t.after(n,t.bind(function(){this.unsubscribe()},this));return this.callback=function(){i.apply(this.context,arguments),s()},this},distinctUntilChanged:function(){return this.withConstraint(new s),this},distinct:function(){return this.withConstraint(new e),this},once:function(){return this.disposeAfter(1),this},withConstraint:function(n){if(!t.isFunction(n))throw"Predicate constraint must be a function";return this.constraints.push(n),this},withConstraints:function(n){var i=this;return t.isArray(n)&&t.each(n,function(t){i.withConstraint(t)}),i},withContext:function(t){return this.context=t,this},withDebounce:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.debounce(i,n),this},withDelay:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=function(t){setTimeout(function(){i(t)},n)},this},withThrottle:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.throttle(i,n),this},subscribe:function(t){return this.callback=t,this}};var o={cache:{},regex:{},compare:function(n,i){var s,e,c,r=this.cache[i]&&this.cache[i][n];return r!==undefined?r:((e=this.regex[n])||(s="^"+t.map(n.split("."),function(t){var n="";return c&&(n="#"!==c?"\\.\\b":"\\b"),n+="#"===t?"[\\s\\S]*":"*"===t?"[^.]+":t,c=t,n}).join("")+"$",e=this.regex[n]=RegExp(s)),this.cache[i]=this.cache[i]||{},this.cache[i][n]=r=e.test(i),r)},reset:function(){this.cache={},this.regex={}}},u=function(n,i){!n.inactive&&p.configuration.resolver.compare(n.topic,i.topic)&&t.all(n.constraints,function(t){return t.call(n.context,i.data,i)})&&"function"==typeof n.callback&&n.callback.call(n.context,i.data,i)},a=!1,h=[],l={addWireTap:function(t){var n=this;return n.wireTaps.push(t),function(){var i=n.wireTaps.indexOf(t);-1!==i&&n.wireTaps.splice(i,1)}},publish:function(n){return a=!0,n.timeStamp=new Date,t.each(this.wireTaps,function(t){t(n.data,n)}),this.subscriptions[n.channel]&&t.each(this.subscriptions[n.channel],function(t){for(var i,s=0,e=t.length;e>s;)(i=t[s++])&&u(i,n)}),a=!1,n},reset:function(){this.subscriptions&&(t.each(this.subscriptions,function(n){t.each(n,function(t){for(;t.length;)t.pop().unsubscribe()})}),this.subscriptions={})},subscribe:function(t){var n,i=this.subscriptions[t.channel];return i||(i=this.subscriptions[t.channel]={}),n=this.subscriptions[t.channel][t.topic],n||(n=this.subscriptions[t.channel][t.topic]=[]),n.push(t),t},subscriptions:{},wireTaps:[],unsubscribe:function(t){if(a)return h.push(t),undefined;if(this.subscriptions[t.channel][t.topic])for(var n=this.subscriptions[t.channel][t.topic].length,i=0;n>i;){if(this.subscriptions[t.channel][t.topic][i]===t){this.subscriptions[t.channel][t.topic].splice(i,1);break}i+=1}}};l.subscriptions[i]={};var p={configuration:{bus:l,resolver:o,DEFAULT_CHANNEL:n,SYSTEM_CHANNEL:i},ChannelDefinition:c,SubscriptionDefinition:r,channel:function(t){return new c(t)},subscribe:function(t){return new r(t.channel||n,t.topic,t.callback)},publish:function(t){return t.channel=t.channel||n,p.configuration.bus.publish(t)},addWireTap:function(t){return this.configuration.bus.addWireTap(t)},linkChannels:function(i,s){var e=[];return i=t.isArray(i)?i:[i],s=t.isArray(s)?s:[s],t.each(i,function(i){i.topic||"#",t.each(s,function(s){var c=s.channel||n;e.push(p.subscribe({channel:i.channel||n,topic:i.topic||"#",callback:function(n,i){var e=t.clone(i);e.topic=t.isFunction(s.topic)?s.topic(i.topic):s.topic||i.topic,e.channel=c,e.data=n,p.publish(e)}}))})}),e},utils:{getSubscribersFor:function(){var t=arguments[0],n=arguments[1];return 1===arguments.length&&(t=arguments[0].channel||p.configuration.DEFAULT_CHANNEL,n=arguments[0].topic),p.configuration.bus.subscriptions[t]&&Object.prototype.hasOwnProperty.call(p.configuration.bus.subscriptions[t],n)?p.configuration.bus.subscriptions[t][n]:[]},reset:function(){p.configuration.bus.reset(),p.configuration.resolver.reset()}}};return p}); \ No newline at end of file +(function(t,n){"object"==typeof module&&module.exports?module.exports=function(t){return t=t||require("underscore"),n(t)}:"function"==typeof define&&define.amd?define(["underscore"],function(i){return n(i,t)}):t.postal=n(t._,t)})(this,function(t){var n="/",i="postal",s=function(){var n;return function(i){var s=!1;return t.isString(i)?(s=i===n,n=i):(s=t.isEqual(i,n),n=t.clone(i)),!s}},e=function(){var n=[];return function(i){var s=!t.any(n,function(n){return t.isObject(i)||t.isArray(i)?t.isEqual(i,n):i===n});return s&&n.push(i),s}},c=function(t){this.channel=t||n};c.prototype.subscribe=function(){return 1===arguments.length?new r(this.channel,arguments[0].topic,arguments[0].callback):new r(this.channel,arguments[0],arguments[1])},c.prototype.publish=function(){var t=1===arguments.length?"[object String]"===Object.prototype.toString.call(arguments[0])?{topic:arguments[0]}:arguments[0]:{topic:arguments[0],data:arguments[1]};return t.channel=this.channel,b.configuration.bus.publish(t)};var r=function(t,n,s){this.channel=t,this.topic=n,this.callback=s,this.constraints=[],this.context=null,b.configuration.bus.publish({channel:i,topic:"subscription.created",data:{event:"subscription.created",channel:t,topic:n}}),b.configuration.bus.subscribe(this)};r.prototype={unsubscribe:function(){this.inactive||(this.inactive=!0,b.configuration.bus.unsubscribe(this),b.configuration.bus.publish({channel:i,topic:"subscription.removed",data:{event:"subscription.removed",channel:this.channel,topic:this.topic}}))},defer:function(){var t=this.callback;return this.callback=function(n){setTimeout(function(){t(n)},0)},this},disposeAfter:function(n){if(t.isNaN(n)||0>=n)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var i=this.callback,s=t.after(n,t.bind(function(){this.unsubscribe()},this));return this.callback=function(){i.apply(this.context,arguments),s()},this},distinctUntilChanged:function(){return this.withConstraint(new s),this},distinct:function(){return this.withConstraint(new e),this},once:function(){return this.disposeAfter(1),this},withConstraint:function(n){if(!t.isFunction(n))throw"Predicate constraint must be a function";return this.constraints.push(n),this},withConstraints:function(n){var i=this;return t.isArray(n)&&t.each(n,function(t){i.withConstraint(t)}),i},withContext:function(t){return this.context=t,this},withDebounce:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.debounce(i,n),this},withDelay:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=function(t){setTimeout(function(){i(t)},n)},this},withThrottle:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.throttle(i,n),this},subscribe:function(t){return this.callback=t,this}};var o={cache:{},regex:{},compare:function(n,i){var s,e,c,r=this.cache[i]&&this.cache[i][n];return r!==undefined?r:((e=this.regex[n])||(s="^"+t.map(n.split("."),function(t){var n="";return c&&(n="#"!==c?"\\.\\b":"\\b"),n+="#"===t?"[\\s\\S]*":"*"===t?"[^.]+":t,c=t,n}).join("")+"$",e=this.regex[n]=RegExp(s)),this.cache[i]=this.cache[i]||{},this.cache[i][n]=r=e.test(i),r)},reset:function(){this.cache={},this.regex={}}},u=function(n,i){!n.inactive&&b.configuration.resolver.compare(n.topic,i.topic)&&t.all(n.constraints,function(t){return t.call(n.context,i.data,i)})&&"function"==typeof n.callback&&n.callback.call(n.context,i.data,i)},a=0,h=[],l=function(){for(;h.length;)h.shift().unsubscribe()},p={addWireTap:function(t){var n=this;return n.wireTaps.push(t),function(){var i=n.wireTaps.indexOf(t);-1!==i&&n.wireTaps.splice(i,1)}},publish:function(n){return++a,n.timeStamp=new Date,t.each(this.wireTaps,function(t){t(n.data,n)}),this.subscriptions[n.channel]&&t.each(this.subscriptions[n.channel],function(t){for(var i,s=0,e=t.length;e>s;)(i=t[s++])&&u(i,n)}),0===--a&&l(),n},reset:function(){this.subscriptions&&(t.each(this.subscriptions,function(n){t.each(n,function(t){for(;t.length;)t.pop().unsubscribe()})}),this.subscriptions={})},subscribe:function(t){var n,i=this.subscriptions[t.channel];return i||(i=this.subscriptions[t.channel]={}),n=this.subscriptions[t.channel][t.topic],n||(n=this.subscriptions[t.channel][t.topic]=[]),n.push(t),t},subscriptions:{},wireTaps:[],unsubscribe:function(t){if(a)return h.push(t),undefined;if(this.subscriptions[t.channel][t.topic])for(var n=this.subscriptions[t.channel][t.topic].length,i=0;n>i;){if(this.subscriptions[t.channel][t.topic][i]===t){this.subscriptions[t.channel][t.topic].splice(i,1);break}i+=1}}};p.subscriptions[i]={};var b={configuration:{bus:p,resolver:o,DEFAULT_CHANNEL:n,SYSTEM_CHANNEL:i},ChannelDefinition:c,SubscriptionDefinition:r,channel:function(t){return new c(t)},subscribe:function(t){return new r(t.channel||n,t.topic,t.callback)},publish:function(t){return t.channel=t.channel||n,b.configuration.bus.publish(t)},addWireTap:function(t){return this.configuration.bus.addWireTap(t)},linkChannels:function(i,s){var e=[];return i=t.isArray(i)?i:[i],s=t.isArray(s)?s:[s],t.each(i,function(i){i.topic||"#",t.each(s,function(s){var c=s.channel||n;e.push(b.subscribe({channel:i.channel||n,topic:i.topic||"#",callback:function(n,i){var e=t.clone(i);e.topic=t.isFunction(s.topic)?s.topic(i.topic):s.topic||i.topic,e.channel=c,e.data=n,b.publish(e)}}))})}),e},utils:{getSubscribersFor:function(){var t=arguments[0],n=arguments[1];return 1===arguments.length&&(t=arguments[0].channel||b.configuration.DEFAULT_CHANNEL,n=arguments[0].topic),b.configuration.bus.subscriptions[t]&&Object.prototype.hasOwnProperty.call(b.configuration.bus.subscriptions[t],n)?b.configuration.bus.subscriptions[t][n]:[]},reset:function(){b.configuration.bus.reset(),b.configuration.resolver.reset()}}};return b}); \ No newline at end of file diff --git a/lib/postal.js b/lib/postal.js index 828811c..5945bac 100755 --- a/lib/postal.js +++ b/lib/postal.js @@ -42,7 +42,7 @@ }; var DistinctPredicate = function () { var previous = []; - + return function ( data ) { var isDistinct = !_.any( previous, function ( p ) { if ( _.isObject( data ) || _.isArray( data ) ) { @@ -59,17 +59,19 @@ var ChannelDefinition = function ( channelName ) { this.channel = channelName || DEFAULT_CHANNEL; }; - + ChannelDefinition.prototype.subscribe = function () { return arguments.length === 1 ? new SubscriptionDefinition( this.channel, arguments[0].topic, arguments[0].callback ) : new SubscriptionDefinition( this.channel, arguments[0], arguments[1] ); }; - + ChannelDefinition.prototype.publish = function () { var envelope = arguments.length === 1 ? - (Object.prototype.toString.call(arguments[0]) === '[object String]' ? - { topic: arguments[0] } : arguments[0]) : { topic : arguments[0], data : arguments[1] }; + (Object.prototype.toString.call(arguments[0]) === '[object String]' ? + { topic: arguments[0] } : + arguments[0]) : + { topic : arguments[0], data : arguments[1] }; envelope.channel = this.channel; return postal.configuration.bus.publish( envelope ); }; @@ -90,22 +92,24 @@ } ); postal.configuration.bus.subscribe( this ); }; - + SubscriptionDefinition.prototype = { unsubscribe : function () { - this.inactive = true; - postal.configuration.bus.unsubscribe( this ); - postal.configuration.bus.publish( { - channel : SYSTEM_CHANNEL, - topic : "subscription.removed", - data : { - event : "subscription.removed", - channel : this.channel, - topic : this.topic - } - } ); + if(!this.inactive) { + this.inactive = true; + postal.configuration.bus.unsubscribe( this ); + postal.configuration.bus.publish( { + channel : SYSTEM_CHANNEL, + topic : "subscription.removed", + data : { + event : "subscription.removed", + channel : this.channel, + topic : this.topic + } + } ); + } }, - + defer : function () { var fn = this.callback; this.callback = function ( data ) { @@ -115,7 +119,7 @@ }; return this; }, - + disposeAfter : function ( maxCalls ) { if ( _.isNaN( maxCalls ) || maxCalls <= 0 ) { throw "The value provided to disposeAfter (maxCalls) must be a number greater than zero."; @@ -124,29 +128,29 @@ var dispose = _.after( maxCalls, _.bind( function () { this.unsubscribe(); }, this ) ); - + this.callback = function () { fn.apply( this.context, arguments ); dispose(); }; return this; }, - + distinctUntilChanged : function () { this.withConstraint( new ConsecutiveDistinctPredicate() ); return this; }, - + distinct : function () { this.withConstraint( new DistinctPredicate() ); return this; }, - + once : function () { this.disposeAfter( 1 ); return this; }, - + withConstraint : function ( predicate ) { if ( !_.isFunction( predicate ) ) { throw "Predicate constraint must be a function"; @@ -154,7 +158,7 @@ this.constraints.push( predicate ); return this; }, - + withConstraints : function ( predicates ) { var self = this; if ( _.isArray( predicates ) ) { @@ -164,12 +168,12 @@ } return self; }, - + withContext : function ( context ) { this.context = context; return this; }, - + withDebounce : function ( milliseconds ) { if ( _.isNaN( milliseconds ) ) { throw "Milliseconds must be a number"; @@ -178,7 +182,7 @@ this.callback = _.debounce( fn, milliseconds ); return this; }, - + withDelay : function ( milliseconds ) { if ( _.isNaN( milliseconds ) ) { throw "Milliseconds must be a number"; @@ -191,7 +195,7 @@ }; return this; }, - + withThrottle : function ( milliseconds ) { if ( _.isNaN( milliseconds ) ) { throw "Milliseconds must be a number"; @@ -200,7 +204,7 @@ this.callback = _.throttle( fn, milliseconds ); return this; }, - + subscribe : function ( callback ) { this.callback = callback; return this; @@ -209,7 +213,7 @@ var bindingsResolver = { cache : {}, regex : {}, - + compare : function ( binding, topic ) { var pattern, rgx, prevSegment, result = (this.cache[topic] && this.cache[topic][binding]); if(typeof result !== "undefined") { @@ -237,32 +241,32 @@ this.cache[topic][binding] = result = rgx.test( topic ); return result; }, - + reset : function () { this.cache = {}; this.regex = {}; } }; - var fireSub = function(subDef, envelope) { - if ( !subDef.inactive && postal.configuration.resolver.compare( subDef.topic, envelope.topic ) ) { - if ( _.all( subDef.constraints, function ( constraint ) { - return constraint.call( subDef.context, envelope.data, envelope ); - } ) ) { - if ( typeof subDef.callback === 'function' ) { - subDef.callback.call( subDef.context, envelope.data, envelope ); - } - } - } + var fireSub = function ( subDef, envelope ) { + if ( !subDef.inactive && postal.configuration.resolver.compare( subDef.topic, envelope.topic ) ) { + if ( _.all( subDef.constraints, function ( constraint ) { + return constraint.call( subDef.context, envelope.data, envelope ); + } ) ) { + if ( typeof subDef.callback === 'function' ) { + subDef.callback.call( subDef.context, envelope.data, envelope ); + } + } + } }; - + var pubInProgress = 0; var unSubQueue = []; - var clearUnSubQueue = function() { - while(unSubQueue.length) { + var clearUnSubQueue = function () { + while ( unSubQueue.length ) { unSubQueue.shift().unsubscribe(); } }; - + var localBus = { addWireTap : function ( callback ) { var self = this; @@ -274,7 +278,7 @@ } }; }, - + publish : function ( envelope ) { ++pubInProgress; envelope.timeStamp = new Date(); @@ -291,12 +295,12 @@ } } ); } - if (--pubInProgress == 0) { + if ( --pubInProgress === 0 ) { clearUnSubQueue(); } return envelope; }, - + reset : function () { if ( this.subscriptions ) { _.each( this.subscriptions, function ( channel ) { @@ -309,7 +313,7 @@ this.subscriptions = {}; } }, - + subscribe : function ( subDef ) { var idx, found, fn, channel = this.subscriptions[subDef.channel], subs; if ( !channel ) { @@ -322,20 +326,20 @@ subs.push( subDef ); return subDef; }, - + subscriptions : {}, - + wireTaps : [], - + unsubscribe : function ( config ) { - if (pubInProgress) { - unSubQueue.push(config); + if ( pubInProgress ) { + unSubQueue.push( config ); return; } if ( this.subscriptions[config.channel][config.topic] ) { var len = this.subscriptions[config.channel][config.topic].length, idx = 0; - while(idx < len) { + while ( idx < len ) { if ( this.subscriptions[config.channel][config.topic][idx] === config ) { this.subscriptions[config.channel][config.topic].splice( idx, 1 ); break; @@ -353,27 +357,27 @@ DEFAULT_CHANNEL : DEFAULT_CHANNEL, SYSTEM_CHANNEL : SYSTEM_CHANNEL }, - + ChannelDefinition : ChannelDefinition, SubscriptionDefinition : SubscriptionDefinition, - + channel : function ( channelName ) { return new ChannelDefinition( channelName ); }, - + subscribe : function ( options ) { return new SubscriptionDefinition( options.channel || DEFAULT_CHANNEL, options.topic, options.callback ); }, - + publish : function ( envelope ) { envelope.channel = envelope.channel || DEFAULT_CHANNEL; return postal.configuration.bus.publish( envelope ); }, - + addWireTap : function ( callback ) { return this.configuration.bus.addWireTap( callback ); }, - + linkChannels : function ( sources, destinations ) { var result = []; sources = !_.isArray( sources ) ? [sources] : sources; @@ -399,7 +403,7 @@ } ); return result; }, - + utils : { getSubscribersFor : function () { var channel = arguments[ 0 ], @@ -414,7 +418,7 @@ } return []; }, - + reset : function () { postal.configuration.bus.reset(); postal.configuration.resolver.reset(); diff --git a/lib/postal.min.js b/lib/postal.min.js index 17d610c..7d045ec 100755 --- a/lib/postal.min.js +++ b/lib/postal.min.js @@ -4,4 +4,4 @@ License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license) Version 0.8.5 */ -(function(t,n){"object"==typeof module&&module.exports?module.exports=function(t){return t=t||require("underscore"),n(t)}:"function"==typeof define&&define.amd?define(["underscore"],function(i){return n(i,t)}):t.postal=n(t._,t)})(this,function(t){var n="/",i="postal",s=function(){var n;return function(i){var s=!1;return t.isString(i)?(s=i===n,n=i):(s=t.isEqual(i,n),n=t.clone(i)),!s}},e=function(){var n=[];return function(i){var s=!t.any(n,function(n){return t.isObject(i)||t.isArray(i)?t.isEqual(i,n):i===n});return s&&n.push(i),s}},c=function(t){this.channel=t||n};c.prototype.subscribe=function(){return 1===arguments.length?new r(this.channel,arguments[0].topic,arguments[0].callback):new r(this.channel,arguments[0],arguments[1])},c.prototype.publish=function(){var t=1===arguments.length?"[object String]"===Object.prototype.toString.call(arguments[0])?{topic:arguments[0]}:arguments[0]:{topic:arguments[0],data:arguments[1]};return t.channel=this.channel,p.configuration.bus.publish(t)};var r=function(t,n,s){this.channel=t,this.topic=n,this.callback=s,this.constraints=[],this.context=null,p.configuration.bus.publish({channel:i,topic:"subscription.created",data:{event:"subscription.created",channel:t,topic:n}}),p.configuration.bus.subscribe(this)};r.prototype={unsubscribe:function(){this.inactive=!0,p.configuration.bus.unsubscribe(this),p.configuration.bus.publish({channel:i,topic:"subscription.removed",data:{event:"subscription.removed",channel:this.channel,topic:this.topic}})},defer:function(){var t=this.callback;return this.callback=function(n){setTimeout(function(){t(n)},0)},this},disposeAfter:function(n){if(t.isNaN(n)||0>=n)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var i=this.callback,s=t.after(n,t.bind(function(){this.unsubscribe()},this));return this.callback=function(){i.apply(this.context,arguments),s()},this},distinctUntilChanged:function(){return this.withConstraint(new s),this},distinct:function(){return this.withConstraint(new e),this},once:function(){return this.disposeAfter(1),this},withConstraint:function(n){if(!t.isFunction(n))throw"Predicate constraint must be a function";return this.constraints.push(n),this},withConstraints:function(n){var i=this;return t.isArray(n)&&t.each(n,function(t){i.withConstraint(t)}),i},withContext:function(t){return this.context=t,this},withDebounce:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.debounce(i,n),this},withDelay:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=function(t){setTimeout(function(){i(t)},n)},this},withThrottle:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.throttle(i,n),this},subscribe:function(t){return this.callback=t,this}};var o={cache:{},regex:{},compare:function(n,i){var s,e,c,r=this.cache[i]&&this.cache[i][n];return r!==undefined?r:((e=this.regex[n])||(s="^"+t.map(n.split("."),function(t){var n="";return c&&(n="#"!==c?"\\.\\b":"\\b"),n+="#"===t?"[\\s\\S]*":"*"===t?"[^.]+":t,c=t,n}).join("")+"$",e=this.regex[n]=RegExp(s)),this.cache[i]=this.cache[i]||{},this.cache[i][n]=r=e.test(i),r)},reset:function(){this.cache={},this.regex={}}},u=function(n,i){!n.inactive&&p.configuration.resolver.compare(n.topic,i.topic)&&t.all(n.constraints,function(t){return t.call(n.context,i.data,i)})&&"function"==typeof n.callback&&n.callback.call(n.context,i.data,i)},a=!1,h=[],l={addWireTap:function(t){var n=this;return n.wireTaps.push(t),function(){var i=n.wireTaps.indexOf(t);-1!==i&&n.wireTaps.splice(i,1)}},publish:function(n){return a=!0,n.timeStamp=new Date,t.each(this.wireTaps,function(t){t(n.data,n)}),this.subscriptions[n.channel]&&t.each(this.subscriptions[n.channel],function(t){for(var i,s=0,e=t.length;e>s;)(i=t[s++])&&u(i,n)}),a=!1,n},reset:function(){this.subscriptions&&(t.each(this.subscriptions,function(n){t.each(n,function(t){for(;t.length;)t.pop().unsubscribe()})}),this.subscriptions={})},subscribe:function(t){var n,i=this.subscriptions[t.channel];return i||(i=this.subscriptions[t.channel]={}),n=this.subscriptions[t.channel][t.topic],n||(n=this.subscriptions[t.channel][t.topic]=[]),n.push(t),t},subscriptions:{},wireTaps:[],unsubscribe:function(t){if(a)return h.push(t),undefined;if(this.subscriptions[t.channel][t.topic])for(var n=this.subscriptions[t.channel][t.topic].length,i=0;n>i;){if(this.subscriptions[t.channel][t.topic][i]===t){this.subscriptions[t.channel][t.topic].splice(i,1);break}i+=1}}};l.subscriptions[i]={};var p={configuration:{bus:l,resolver:o,DEFAULT_CHANNEL:n,SYSTEM_CHANNEL:i},ChannelDefinition:c,SubscriptionDefinition:r,channel:function(t){return new c(t)},subscribe:function(t){return new r(t.channel||n,t.topic,t.callback)},publish:function(t){return t.channel=t.channel||n,p.configuration.bus.publish(t)},addWireTap:function(t){return this.configuration.bus.addWireTap(t)},linkChannels:function(i,s){var e=[];return i=t.isArray(i)?i:[i],s=t.isArray(s)?s:[s],t.each(i,function(i){i.topic||"#",t.each(s,function(s){var c=s.channel||n;e.push(p.subscribe({channel:i.channel||n,topic:i.topic||"#",callback:function(n,i){var e=t.clone(i);e.topic=t.isFunction(s.topic)?s.topic(i.topic):s.topic||i.topic,e.channel=c,e.data=n,p.publish(e)}}))})}),e},utils:{getSubscribersFor:function(){var t=arguments[0],n=arguments[1];return 1===arguments.length&&(t=arguments[0].channel||p.configuration.DEFAULT_CHANNEL,n=arguments[0].topic),p.configuration.bus.subscriptions[t]&&Object.prototype.hasOwnProperty.call(p.configuration.bus.subscriptions[t],n)?p.configuration.bus.subscriptions[t][n]:[]},reset:function(){p.configuration.bus.reset(),p.configuration.resolver.reset()}}};return p}); \ No newline at end of file +(function(t,n){"object"==typeof module&&module.exports?module.exports=function(t){return t=t||require("underscore"),n(t)}:"function"==typeof define&&define.amd?define(["underscore"],function(i){return n(i,t)}):t.postal=n(t._,t)})(this,function(t){var n="/",i="postal",s=function(){var n;return function(i){var s=!1;return t.isString(i)?(s=i===n,n=i):(s=t.isEqual(i,n),n=t.clone(i)),!s}},e=function(){var n=[];return function(i){var s=!t.any(n,function(n){return t.isObject(i)||t.isArray(i)?t.isEqual(i,n):i===n});return s&&n.push(i),s}},c=function(t){this.channel=t||n};c.prototype.subscribe=function(){return 1===arguments.length?new r(this.channel,arguments[0].topic,arguments[0].callback):new r(this.channel,arguments[0],arguments[1])},c.prototype.publish=function(){var t=1===arguments.length?"[object String]"===Object.prototype.toString.call(arguments[0])?{topic:arguments[0]}:arguments[0]:{topic:arguments[0],data:arguments[1]};return t.channel=this.channel,b.configuration.bus.publish(t)};var r=function(t,n,s){this.channel=t,this.topic=n,this.callback=s,this.constraints=[],this.context=null,b.configuration.bus.publish({channel:i,topic:"subscription.created",data:{event:"subscription.created",channel:t,topic:n}}),b.configuration.bus.subscribe(this)};r.prototype={unsubscribe:function(){this.inactive||(this.inactive=!0,b.configuration.bus.unsubscribe(this),b.configuration.bus.publish({channel:i,topic:"subscription.removed",data:{event:"subscription.removed",channel:this.channel,topic:this.topic}}))},defer:function(){var t=this.callback;return this.callback=function(n){setTimeout(function(){t(n)},0)},this},disposeAfter:function(n){if(t.isNaN(n)||0>=n)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var i=this.callback,s=t.after(n,t.bind(function(){this.unsubscribe()},this));return this.callback=function(){i.apply(this.context,arguments),s()},this},distinctUntilChanged:function(){return this.withConstraint(new s),this},distinct:function(){return this.withConstraint(new e),this},once:function(){return this.disposeAfter(1),this},withConstraint:function(n){if(!t.isFunction(n))throw"Predicate constraint must be a function";return this.constraints.push(n),this},withConstraints:function(n){var i=this;return t.isArray(n)&&t.each(n,function(t){i.withConstraint(t)}),i},withContext:function(t){return this.context=t,this},withDebounce:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.debounce(i,n),this},withDelay:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=function(t){setTimeout(function(){i(t)},n)},this},withThrottle:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.throttle(i,n),this},subscribe:function(t){return this.callback=t,this}};var o={cache:{},regex:{},compare:function(n,i){var s,e,c,r=this.cache[i]&&this.cache[i][n];return r!==undefined?r:((e=this.regex[n])||(s="^"+t.map(n.split("."),function(t){var n="";return c&&(n="#"!==c?"\\.\\b":"\\b"),n+="#"===t?"[\\s\\S]*":"*"===t?"[^.]+":t,c=t,n}).join("")+"$",e=this.regex[n]=RegExp(s)),this.cache[i]=this.cache[i]||{},this.cache[i][n]=r=e.test(i),r)},reset:function(){this.cache={},this.regex={}}},u=function(n,i){!n.inactive&&b.configuration.resolver.compare(n.topic,i.topic)&&t.all(n.constraints,function(t){return t.call(n.context,i.data,i)})&&"function"==typeof n.callback&&n.callback.call(n.context,i.data,i)},a=0,h=[],l=function(){for(;h.length;)h.shift().unsubscribe()},p={addWireTap:function(t){var n=this;return n.wireTaps.push(t),function(){var i=n.wireTaps.indexOf(t);-1!==i&&n.wireTaps.splice(i,1)}},publish:function(n){return++a,n.timeStamp=new Date,t.each(this.wireTaps,function(t){t(n.data,n)}),this.subscriptions[n.channel]&&t.each(this.subscriptions[n.channel],function(t){for(var i,s=0,e=t.length;e>s;)(i=t[s++])&&u(i,n)}),0===--a&&l(),n},reset:function(){this.subscriptions&&(t.each(this.subscriptions,function(n){t.each(n,function(t){for(;t.length;)t.pop().unsubscribe()})}),this.subscriptions={})},subscribe:function(t){var n,i=this.subscriptions[t.channel];return i||(i=this.subscriptions[t.channel]={}),n=this.subscriptions[t.channel][t.topic],n||(n=this.subscriptions[t.channel][t.topic]=[]),n.push(t),t},subscriptions:{},wireTaps:[],unsubscribe:function(t){if(a)return h.push(t),undefined;if(this.subscriptions[t.channel][t.topic])for(var n=this.subscriptions[t.channel][t.topic].length,i=0;n>i;){if(this.subscriptions[t.channel][t.topic][i]===t){this.subscriptions[t.channel][t.topic].splice(i,1);break}i+=1}}};p.subscriptions[i]={};var b={configuration:{bus:p,resolver:o,DEFAULT_CHANNEL:n,SYSTEM_CHANNEL:i},ChannelDefinition:c,SubscriptionDefinition:r,channel:function(t){return new c(t)},subscribe:function(t){return new r(t.channel||n,t.topic,t.callback)},publish:function(t){return t.channel=t.channel||n,b.configuration.bus.publish(t)},addWireTap:function(t){return this.configuration.bus.addWireTap(t)},linkChannels:function(i,s){var e=[];return i=t.isArray(i)?i:[i],s=t.isArray(s)?s:[s],t.each(i,function(i){i.topic||"#",t.each(s,function(s){var c=s.channel||n;e.push(b.subscribe({channel:i.channel||n,topic:i.topic||"#",callback:function(n,i){var e=t.clone(i);e.topic=t.isFunction(s.topic)?s.topic(i.topic):s.topic||i.topic,e.channel=c,e.data=n,b.publish(e)}}))})}),e},utils:{getSubscribersFor:function(){var t=arguments[0],n=arguments[1];return 1===arguments.length&&(t=arguments[0].channel||b.configuration.DEFAULT_CHANNEL,n=arguments[0].topic),b.configuration.bus.subscriptions[t]&&Object.prototype.hasOwnProperty.call(b.configuration.bus.subscriptions[t],n)?b.configuration.bus.subscriptions[t][n]:[]},reset:function(){b.configuration.bus.reset(),b.configuration.resolver.reset()}}};return b}); \ No newline at end of file diff --git a/spec/Postal.spec.js b/spec/Postal.spec.js index e02154f..14d16be 100644 --- a/spec/Postal.spec.js +++ b/spec/Postal.spec.js @@ -112,6 +112,41 @@ describe( "Postal", function () { expect( results[2] ).to.be("2 received message"); }); }); + describe( "With nested publishing", function() { + var subscription1, subscription2, sysub, results = []; + before( function () { + channel = postal.channel(); + sysub = postal.subscribe({ + channel: postal.configuration.SYSTEM_CHANNEL, + topic : "subscription.removed", + callback : function(d, e) { + results.push("unsubscribed"); + } + }); + subscription1 = channel.subscribe('nest.test', function() { + results.push('1 received message'); + channel.publish("nest.test2", "Hai"); + }).once(); + + subscription2 = channel.subscribe('nest.test2', function() { + results.push('2 received message'); + }); + channel.publish('nest.test'); + channel.publish('nest.test'); + }); + after( function () { + //subscription2.unsubscribe(); + sysub.unsubscribe(); + postal.utils.reset(); + }); + it( "should produce expected messages", function() { + console.log(results); + expect( results.length ).to.be(3); + expect( results[0] ).to.be("1 received message"); + expect( results[1] ).to.be("2 received message"); + expect( results[2] ).to.be("unsubscribed"); + }); + }); } ); describe( "When publishing a message", function () { var msgReceivedCnt = 0, diff --git a/src/ChannelDefinition.js b/src/ChannelDefinition.js index 9007329..7792f87 100644 --- a/src/ChannelDefinition.js +++ b/src/ChannelDefinition.js @@ -10,8 +10,10 @@ ChannelDefinition.prototype.subscribe = function () { ChannelDefinition.prototype.publish = function () { var envelope = arguments.length === 1 ? - (Object.prototype.toString.call(arguments[0]) === '[object String]' ? - { topic: arguments[0] } : arguments[0]) : { topic : arguments[0], data : arguments[1] }; + (Object.prototype.toString.call(arguments[0]) === '[object String]' ? + { topic: arguments[0] } : + arguments[0]) : + { topic : arguments[0], data : arguments[1] }; envelope.channel = this.channel; return postal.configuration.bus.publish( envelope ); }; \ No newline at end of file diff --git a/src/LocalBus.js b/src/LocalBus.js index fccdfc6..c75d4ac 100644 --- a/src/LocalBus.js +++ b/src/LocalBus.js @@ -1,19 +1,19 @@ -var fireSub = function(subDef, envelope) { - if ( !subDef.inactive && postal.configuration.resolver.compare( subDef.topic, envelope.topic ) ) { - if ( _.all( subDef.constraints, function ( constraint ) { - return constraint.call( subDef.context, envelope.data, envelope ); - } ) ) { - if ( typeof subDef.callback === 'function' ) { - subDef.callback.call( subDef.context, envelope.data, envelope ); - } - } - } +var fireSub = function ( subDef, envelope ) { + if ( !subDef.inactive && postal.configuration.resolver.compare( subDef.topic, envelope.topic ) ) { + if ( _.all( subDef.constraints, function ( constraint ) { + return constraint.call( subDef.context, envelope.data, envelope ); + } ) ) { + if ( typeof subDef.callback === 'function' ) { + subDef.callback.call( subDef.context, envelope.data, envelope ); + } + } + } }; var pubInProgress = 0; var unSubQueue = []; -var clearUnSubQueue = function() { - while(unSubQueue.length) { +var clearUnSubQueue = function () { + while ( unSubQueue.length ) { unSubQueue.shift().unsubscribe(); } }; @@ -46,7 +46,7 @@ var localBus = { } } ); } - if (--pubInProgress == 0) { + if ( --pubInProgress === 0 ) { clearUnSubQueue(); } return envelope; @@ -83,14 +83,14 @@ var localBus = { wireTaps : [], unsubscribe : function ( config ) { - if (pubInProgress) { - unSubQueue.push(config); + if ( pubInProgress ) { + unSubQueue.push( config ); return; } if ( this.subscriptions[config.channel][config.topic] ) { var len = this.subscriptions[config.channel][config.topic].length, idx = 0; - while(idx < len) { + while ( idx < len ) { if ( this.subscriptions[config.channel][config.topic][idx] === config ) { this.subscriptions[config.channel][config.topic].splice( idx, 1 ); break; diff --git a/src/SubscriptionDefinition.js b/src/SubscriptionDefinition.js index 6adfc0d..77776d8 100644 --- a/src/SubscriptionDefinition.js +++ b/src/SubscriptionDefinition.js @@ -18,17 +18,19 @@ var SubscriptionDefinition = function ( channel, topic, callback ) { SubscriptionDefinition.prototype = { unsubscribe : function () { - this.inactive = true; - postal.configuration.bus.unsubscribe( this ); - postal.configuration.bus.publish( { - channel : SYSTEM_CHANNEL, - topic : "subscription.removed", - data : { - event : "subscription.removed", - channel : this.channel, - topic : this.topic - } - } ); + if(!this.inactive) { + this.inactive = true; + postal.configuration.bus.unsubscribe( this ); + postal.configuration.bus.publish( { + channel : SYSTEM_CHANNEL, + topic : "subscription.removed", + data : { + event : "subscription.removed", + channel : this.channel, + topic : this.topic + } + } ); + } }, defer : function () {