diff --git a/README.md b/README.md index b5005c8..7ee9f12 100644 --- a/README.md +++ b/README.md @@ -22,13 +22,16 @@ JavaScript: ```javascript // The world's simplest subscription -var channel = postal.channel("Name.Changed"); +// doesn't specify a channel name, so it defaults to "/" (DEFAULT_CHANNEL) +var channel = postal.channel( { topic: "Name.Changed" } ); // subscribe -var subscription = channel.subscribe(function(data) { $("#example1").html("Name: " + data.name); }); +var subscription = channel.subscribe( function( data, envelope ) { + $( "#example1" ).html( "Name: " + data.name ); +}); // And someone publishes a first name change: -channel.publish({ name: "Dr. Who" }); +channel.publish( { name: "Dr. Who" } ); subscription.unsubscribe(); ``` @@ -37,14 +40,14 @@ subscription.unsubscribe(); The `#` symbol represents "one word" in a topic (i.e - the text between two periods of a topic). By subscribing to `"#.Changed"`, the binding will match `Name.Changed` & `Location.Changed` but *not* for `Changed.Companion` ```javascript -var hashChannel = postal.channel("#.Changed"), - chgSubscription = hashChannel.subscribe(function(data) { - $('
  • ' + data.type + " Changed: " + data.value + '
  • ').appendTo("#example2"); +var hashChannel = postal.channel( { topic: "#.Changed" } ), + chgSubscription = hashChannel.subscribe( function( data ) { + $( '
  • ' + data.type + " Changed: " + data.value + '
  • ' ).appendTo( "#example2" ); }); -postal.channel("Name.Changed") - .publish({ type: "Name", value:"John Smith" }); -postal.channel("Location.Changed") - .publish({ type: "Location", value: "Early 20th Century England" }); +postal.channel( { topic: "Name.Changed" } ) + .publish( { type: "Name", value:"John Smith" } ); +postal.channel( "Location.Changed" ) + .publish( { type: "Location", value: "Early 20th Century England" } ); chgSubscription.unsubscribe(); ``` @@ -53,40 +56,38 @@ chgSubscription.unsubscribe(); The `*` symbol represents any number of characters/words in a topic string. By subscribing to ``"DrWho.*.Changed"``, the binding will match `DrWho.NinthDoctor.Companion.Changed` & `DrWho.Location.Changed` but *not* `Changed` ```javascript -var starChannel = postal.channel("DrWho.*.Changed"), - starSubscription = starChannel.subscribe(function(data) { - $('
  • ' + data.type + " Changed: " + data.value + '
  • ').appendTo("#example3"); +var starChannel = postal.channel( { channel: "Doctor.Who", topic: "DrWho.*.Changed" } ), + starSubscription = starChannel.subscribe( function( data ) { + $( '
  • ' + data.type + " Changed: " + data.value + '
  • ' ).appendTo( "#example3" ); }); -postal.channel("DrWho.NinthDoctor.Companion.Changed") - .publish({ type: "Name", value:"Rose" }); -postal.channel("DrWho.TenthDoctor.Companion.Changed") - .publish({ type: "Name", value:"Martha" }); -postal.channel("DrWho.Eleventh.Companion.Changed") - .publish({ type: "Name", value:"Amy" }); -postal.channel("DrWho.Location.Changed") - .publish({ type: "Location", value: "The Library" }); -postal.channel("TheMaster.DrumBeat.Changed") - .publish({ type: "DrumBeat", value: "This won't trigger any subscriptions" }); -postal.channel("Changed") - .publish({ type: "Useless", value: "This won't trigger any subscriptions either" }); +// demonstrating how we're re-using the channel delcared above to publish, but overriding the topic in the second argument +starChannel.publish( { type: "Name", value:"Rose" }, { topic: "DrWho.NinthDoctor.Companion.Changed" } ); +starChannel.publish( { type: "Name", value:"Martha" }, { topic: "DrWho.TenthDoctor.Companion.Changed" } ); +starChannel.publish( { type: "Name", value:"Amy" }, { topic: "DrWho.Eleventh.Companion.Changed" } ); +starChannel.publish( { type: "Location", value: "The Library" }, { topic: "DrWho.Location.Changed" } ); +starChannel.publish( { type: "DrumBeat", value: "This won't trigger any subscriptions" }, { topic: "TheMaster.DrumBeat.Changed" } ); +starChannel.publish( { type: "Useless", value: "This won't trigger any subscriptions either" }, { topic: "Changed" } ); + starSubscription.unsubscribe(); ``` ### Applying ignoreDuplicates to a subscription ```javascript -var dupChannel = postal.channel("WeepingAngel.*"), - dupSubscription = dupChannel.subscribe(function(data) { - $('
  • ' + data.value + '
  • ').appendTo("#example4"); +var dupChannel = postal.channel( { topic: "WeepingAngel.*" } ), + dupSubscription = dupChannel.subscribe( function( data ) { + $( '
  • ' + data.value + '
  • ' ).appendTo( "#example4" ); }).ignoreDuplicates(); -postal.channel("WeepingAngel.DontBlink") - .publish({ value:"Don't Blink" }); -postal.channel("WeepingAngel.DontBlink") - .publish({ value:"Don't Blink" }); -postal.channel("WeepingAngel.DontEvenBlink") - .publish({ value:"Don't Even Blink" }); -postal.channel("WeepingAngel.DontBlink") - .publish({ value:"Don't Close Your Eyes" }); +// demonstrating multiple channels per topic being used +// You can do it this way if you like, but the example above has nicer syntax (and less overhead) +postal.channel( { topic: "WeepingAngel.DontBlink" } ) + .publish( { value:"Don't Blink" } ); +postal.channel( { topic: "WeepingAngel.DontBlink" } ) + .publish( { value:"Don't Blink" } ); +postal.channel( { topic: "WeepingAngel.DontEvenBlink" } ) + .publish( { value:"Don't Even Blink" } ); +postal.channel( { topic: "WeepingAngel.DontBlink" } ) + .publish( { value:"Don't Close Your Eyes" } ); dupSubscription.unsubscribe(); ``` @@ -104,7 +105,5 @@ Please - by all means! While I hope the API is relatively stable, I'm open to p ## Roadmap for the Future Here's where Postal is headed: -* The original proof-of-concept version of postal supported the ability to capture messages and replay them. This functionality will be added soon. -* The ability to 'join' two (or more) subscriptions, so that the original subscription will only fire once the second "joined" subscription has also fired. Think of it as a message-based version of a compound promise. * I haven't yet thoroughly tested Postal on Node.js - that is high on my list as well. * What else would you like to see? \ No newline at end of file diff --git a/build-all.sh b/build-all.sh index 98f53cb..fb02833 100755 --- a/build-all.sh +++ b/build-all.sh @@ -2,12 +2,14 @@ anvil -b build-browser-standard.json anvil -b build-browser-standard-diags.json -anvil -b build-browser-amd.json -anvil -b build-browser-amd-diags.json -anvil -b build-node.json -anvil -b build-node-diags.json -cp ./lib/browser/amd/postal.js ./example/amd/js/libs/postal/ -cp ./lib/browser/amd/postal.diagnostics.js ./example/amd/js/libs/postal/ +cp ./lib/browser/standard/postal.js ./example/amd/js/libs/postal/ +cp ./lib/browser/standard/postal.diagnostics.js ./example/amd/js/libs/postal/ cp ./lib/browser/standard/postal.js ./example/standard/js/ -cp ./lib/browser/standard/postal.diagnostics.js ./example/standard/js/ \ No newline at end of file +cp ./lib/browser/standard/postal.diagnostics.js ./example/standard/js/ + +mv ./lib/browser/standard/postal.node.js ./lib/node/postal.js +rm ./lib/browser/standard/postal.node* + +mv ./lib/browser/standard/postal.diagnostics.node.js ./lib/node/postal.diagnostics.js +rm ./lib/browser/standard/postal.diagnostics.node* \ No newline at end of file diff --git a/build-browser-amd-diags.json b/build-browser-amd-diags.json deleted file mode 100644 index 42430de..0000000 --- a/build-browser-amd-diags.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "source": "src/diags", - "output": "lib/browser/amd", - "lint": {}, - "uglify": {}, - "gzip": {}, - "extensions": { "uglify": "min", "gzip": "gz" }, - "wrap": { - "prefix": "define(['postal', 'underscore'], function(postal, _) {", - "suffix": "});" - } -} \ No newline at end of file diff --git a/build-browser-amd.json b/build-browser-amd.json deleted file mode 100644 index 6817679..0000000 --- a/build-browser-amd.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "source": "src/main", - "output": "lib/browser/amd", - "lint": {}, - "uglify": {}, - "gzip": {}, - "extensions": { "uglify": "min", "gzip": "gz" }, - "wrap": { - "prefix": "define(['underscore'], function(_) {", - "suffix": "return postal; });" - } -} \ No newline at end of file diff --git a/build-browser-standard.json b/build-browser-standard.json index cb413ca..63711c5 100644 --- a/build-browser-standard.json +++ b/build-browser-standard.json @@ -4,9 +4,5 @@ "lint": {}, "uglify": {}, "gzip": {}, - "extensions": { "uglify": "min", "gzip": "gz" }, - "wrap": { - "prefix": "(function(global, undefined) {", - "suffix": "global.postal = postal; })(window);" - } + "extensions": { "uglify": "min", "gzip": "gz" } } \ No newline at end of file diff --git a/build-node-diags.json b/build-node-diags.json index 5085ed7..20f1560 100644 --- a/build-node-diags.json +++ b/build-node-diags.json @@ -1,9 +1,5 @@ { "source": "src/diags", "output": "lib/node", - "lint": {}, - "wrap": { - "prefix": "module.exports = function(postal) {", - "suffix": "};" - } + "lint": {} } \ No newline at end of file diff --git a/build-node.json b/build-node.json index 7b4d7b4..c7f9289 100644 --- a/build-node.json +++ b/build-node.json @@ -1,9 +1,5 @@ { "source": "src/main", "output": "lib/node", - "lint": {}, - "wrap": { - "prefix": "var _ = require('underscore');", - "suffix": "module.exports = postal;" - } + "lint": {} } \ No newline at end of file diff --git a/example/amd/js/libs/postal/postal.diagnostics.js b/example/amd/js/libs/postal/postal.diagnostics.js index 9f9ee66..5defd32 100644 --- a/example/amd/js/libs/postal/postal.diagnostics.js +++ b/example/amd/js/libs/postal/postal.diagnostics.js @@ -1,20 +1,33 @@ -define(['postal', 'underscore'], function(postal, _) { -postal.addWireTap(function(data, envelope) { - var all = _.extend(envelope, { data: data }); - if(!JSON) { - throw "This browser or environment does not provide JSON support"; - } - try { - console.log(JSON.stringify(all)); - } - catch(exception) { - try { - all.data = "ERROR: " + exception.message; - console.log(JSON.stringify(all)); - } - catch(ex) { - console.log("Unable to parse data to JSON: " + exception); - } - } -}); -}); \ No newline at end of file +(function(root, doc, factory) { + if (typeof define === "function" && define.amd) { + // AMD. Register as an anonymous module. + define(["postal", "underscore"], function(postal, _) { + return factory(postal, _, root, doc); + }); + } else { + // Browser globals + factory(root.postal, root._, root, doc); + } +}(this, document, function(postal, _, global, document, undefined) { + + // this returns a callback that, if invoked, removes the wireTap + return postal.addWireTap(function(data, envelope) { + var all = _.extend(envelope, { data: data }); + if(!JSON) { + throw "This browser or environment does not provide JSON support"; + } + try { + console.log(JSON.stringify(all)); + } + catch(exception) { + try { + all.data = "ERROR: " + exception.message; + console.log(JSON.stringify(all)); + } + catch(ex) { + console.log("Unable to parse data to JSON: " + exception); + } + } + }); + +})); \ No newline at end of file diff --git a/example/amd/js/libs/postal/postal.js b/example/amd/js/libs/postal/postal.js index f8037cc..7fe0a44 100644 --- a/example/amd/js/libs/postal/postal.js +++ b/example/amd/js/libs/postal/postal.js @@ -1,4 +1,3 @@ -define(['underscore'], function(_) { /* postal.js Author: Jim Cowart @@ -6,6 +5,18 @@ define(['underscore'], function(_) { Version 0.4.0 */ +(function(root, doc, factory) { + if (typeof define === "function" && define.amd) { + // AMD. Register as an anonymous module. + define(["underscore"], function(_) { + return factory(_, root, doc); + }); + } else { + // Browser globals + factory(root._, root, doc); + } +}(this, document, function(_, global, document, undefined) { + var DEFAULT_CHANNEL = "/", DEFAULT_PRIORITY = 50, DEFAULT_DISPOSEAFTER = 0, @@ -34,8 +45,14 @@ var ChannelDefinition = function(channelName, defaultTopic) { }; ChannelDefinition.prototype = { - subscribe: function(callback) { - return new SubscriptionDefinition(this.channel, this.topic, callback); + subscribe: function() { + var len = arguments.length; + if(len === 1) { + return new SubscriptionDefinition(this.channel, this.topic, arguments[0]); + } + else if (len === 2) { + return new SubscriptionDefinition(this.channel, arguments[0], arguments[1]); + } }, publish: function(data, envelope) { @@ -43,142 +60,140 @@ ChannelDefinition.prototype = { env.channel = this.channel; env.timeStamp = new Date(); env.topic = env.topic || this.topic; - postal.configuration.bus.publish(env, data); + postal.configuration.bus.publish(data, env); } }; var SubscriptionDefinition = function(channel, topic, callback) { - this.channel = channel; - this.topic = topic; - this.callback = callback; - this.priority = DEFAULT_PRIORITY; - this.constraints = new Array(0); - this.maxCalls = DEFAULT_DISPOSEAFTER; - this.onHandled = NO_OP; - this.context = null; + this.channel = channel; + this.topic = topic; + this.callback = callback; + this.priority = DEFAULT_PRIORITY; + this.constraints = new Array(0); + this.maxCalls = DEFAULT_DISPOSEAFTER; + this.onHandled = NO_OP; + this.context = null; + postal.publish({ + event: "subscription.created", + channel: channel, + topic: topic + },{ + channel: SYSTEM_CHANNEL, + topic: "subscription.created" + }); postal.configuration.bus.subscribe(this); - postal.publish({ - channel: SYSTEM_CHANNEL, - topic: "subscription.created" - }, - { - event: "subscription.created", - channel: channel, - topic: topic - }); }; SubscriptionDefinition.prototype = { - unsubscribe: function() { - postal.configuration.bus.unsubscribe(this); - postal.publish({ - channel: SYSTEM_CHANNEL, - topic: "subscription.removed" - }, - { - event: "subscription.removed", - channel: this.channel, - topic: this.topic - }); - }, + unsubscribe: function() { + postal.configuration.bus.unsubscribe(this); + postal.publish({ + event: "subscription.removed", + channel: this.channel, + topic: this.topic + },{ + channel: SYSTEM_CHANNEL, + topic: "subscription.removed" + }); + }, - defer: function() { - var fn = this.callback; - this.callback = function(data) { - setTimeout(fn,0,data); - }; - return this; - }, + defer: function() { + var fn = this.callback; + this.callback = function(data) { + setTimeout(fn,0,data); + }; + return this; + }, - disposeAfter: function(maxCalls) { - if(_.isNaN(maxCalls) || maxCalls <= 0) { - throw "The value provided to disposeAfter (maxCalls) must be a number greater than zero."; - } + disposeAfter: function(maxCalls) { + if(_.isNaN(maxCalls) || maxCalls <= 0) { + throw "The value provided to disposeAfter (maxCalls) must be a number greater than zero."; + } - var fn = this.onHandled; - var dispose = _.after(maxCalls, _.bind(function() { - this.unsubscribe(this); - }, this)); + var fn = this.onHandled; + var dispose = _.after(maxCalls, _.bind(function() { + this.unsubscribe(this); + }, this)); - this.onHandled = function() { - fn.apply(this.context, arguments); - dispose(); - }; - return this; - }, + this.onHandled = function() { + fn.apply(this.context, arguments); + dispose(); + }; + return this; + }, - ignoreDuplicates: function() { - this.withConstraint(new DistinctPredicate()); - return this; - }, + ignoreDuplicates: function() { + this.withConstraint(new DistinctPredicate()); + return this; + }, - whenHandledThenExecute: function(callback) { - if(! _.isFunction(callback)) { - throw "Value provided to 'whenHandledThenExecute' must be a function"; - } - this.onHandled = callback; - return this; - }, + whenHandledThenExecute: function(callback) { + if(! _.isFunction(callback)) { + throw "Value provided to 'whenHandledThenExecute' must be a function"; + } + this.onHandled = callback; + return this; + }, - withConstraint: function(predicate) { - if(! _.isFunction(predicate)) { - throw "Predicate constraint must be a function"; - } - this.constraints.push(predicate); - return this; - }, + withConstraint: function(predicate) { + if(! _.isFunction(predicate)) { + throw "Predicate constraint must be a function"; + } + this.constraints.push(predicate); + return this; + }, - withConstraints: function(predicates) { - var self = this; - if(_.isArray(predicates)) { - _.each(predicates, function(predicate) { self.withConstraint(predicate); } ); - } - return self; - }, + withConstraints: function(predicates) { + var self = this; + if(_.isArray(predicates)) { + _.each(predicates, function(predicate) { self.withConstraint(predicate); } ); + } + return self; + }, - withContext: function(context) { - this.context = context; - return this; - }, + withContext: function(context) { + this.context = context; + return this; + }, - withDebounce: function(milliseconds) { - if(_.isNaN(milliseconds)) { - throw "Milliseconds must be a number"; - } - var fn = this.callback; - this.callback = _.debounce(fn, milliseconds); - return this; - }, + withDebounce: function(milliseconds) { + if(_.isNaN(milliseconds)) { + throw "Milliseconds must be a number"; + } + var fn = this.callback; + this.callback = _.debounce(fn, milliseconds); + return this; + }, - withDelay: function(milliseconds) { - if(_.isNaN(milliseconds)) { - throw "Milliseconds must be a number"; - } - var fn = this.callback; - this.callback = function(data) { - setTimeout(fn, milliseconds, data); - }; - return this; - }, + withDelay: function(milliseconds) { + if(_.isNaN(milliseconds)) { + throw "Milliseconds must be a number"; + } + var fn = this.callback; + this.callback = function(data) { + setTimeout(fn, milliseconds, data); + }; + return this; + }, - withPriority: function(priority) { - if(_.isNaN(priority)) { - throw "Priority must be a number"; - } - this.priority = priority; - return this; - }, + withPriority: function(priority) { + if(_.isNaN(priority)) { + throw "Priority must be a number"; + } + this.priority = priority; + return this; + }, - withThrottle: function(milliseconds) { - if(_.isNaN(milliseconds)) { - throw "Milliseconds must be a number"; - } - var fn = this.callback; - this.callback = _.throttle(fn, milliseconds); - return this; - } + withThrottle: function(milliseconds) { + if(_.isNaN(milliseconds)) { + throw "Milliseconds must be a number"; + } + var fn = this.callback; + this.callback = _.throttle(fn, milliseconds); + return this; + } }; var bindingsResolver = { @@ -209,9 +224,9 @@ var localBus = { wireTaps: new Array(0), - publish: function(envelope, data) { + publish: function(data, envelope) { _.each(this.wireTaps,function(tap) { - tap(envelope, data); + tap(data, envelope); }); _.each(this.subscriptions[envelope.channel], function(topic) { @@ -279,14 +294,14 @@ var localBus = { }; var publishPicker = { - "2" : function(envelope, payload) { + "2" : function(data, envelope) { if(!envelope.channel) { envelope.channel = DEFAULT_CHANNEL; } - postal.configuration.bus.publish(envelope, payload); + postal.configuration.bus.publish(data, envelope); }, "3" : function(channel, topic, payload) { - postal.configuration.bus.publish({ channel: channel, topic: topic }, payload); + postal.configuration.bus.publish(payload, { channel: channel, topic: topic }); } }; @@ -343,7 +358,7 @@ var postal = { var newEnv = env; newEnv.topic = _.isFunction(destination.topic) ? destination.topic(env.topic) : destination.topic || env.topic; newEnv.channel = destChannel; - postal.publish(newEnv, msg); + postal.publish(msg, newEnv); } }) ); @@ -352,5 +367,8 @@ var postal = { return result; } }; - -return postal; }); \ No newline at end of file + + + global.postal = postal; + return postal; +})); \ No newline at end of file diff --git a/example/standard/js/postal.diagnostics.js b/example/standard/js/postal.diagnostics.js index f1d0516..5defd32 100644 --- a/example/standard/js/postal.diagnostics.js +++ b/example/standard/js/postal.diagnostics.js @@ -1,18 +1,33 @@ -postal.addWireTap(function(data, envelope) { - var all = _.extend(envelope, { data: data }); - if(!JSON) { - throw "This browser or environment does not provide JSON support"; - } - try { - console.log(JSON.stringify(all)); - } - catch(exception) { - try { - all.data = "ERROR: " + exception.message; - console.log(JSON.stringify(all)); - } - catch(ex) { - console.log("Unable to parse data to JSON: " + exception); - } - } -}); \ No newline at end of file +(function(root, doc, factory) { + if (typeof define === "function" && define.amd) { + // AMD. Register as an anonymous module. + define(["postal", "underscore"], function(postal, _) { + return factory(postal, _, root, doc); + }); + } else { + // Browser globals + factory(root.postal, root._, root, doc); + } +}(this, document, function(postal, _, global, document, undefined) { + + // this returns a callback that, if invoked, removes the wireTap + return postal.addWireTap(function(data, envelope) { + var all = _.extend(envelope, { data: data }); + if(!JSON) { + throw "This browser or environment does not provide JSON support"; + } + try { + console.log(JSON.stringify(all)); + } + catch(exception) { + try { + all.data = "ERROR: " + exception.message; + console.log(JSON.stringify(all)); + } + catch(ex) { + console.log("Unable to parse data to JSON: " + exception); + } + } + }); + +})); \ No newline at end of file diff --git a/example/standard/js/postal.js b/example/standard/js/postal.js index 66cd36a..7fe0a44 100644 --- a/example/standard/js/postal.js +++ b/example/standard/js/postal.js @@ -1,4 +1,3 @@ -(function(global, undefined) { /* postal.js Author: Jim Cowart @@ -6,6 +5,18 @@ Version 0.4.0 */ +(function(root, doc, factory) { + if (typeof define === "function" && define.amd) { + // AMD. Register as an anonymous module. + define(["underscore"], function(_) { + return factory(_, root, doc); + }); + } else { + // Browser globals + factory(root._, root, doc); + } +}(this, document, function(_, global, document, undefined) { + var DEFAULT_CHANNEL = "/", DEFAULT_PRIORITY = 50, DEFAULT_DISPOSEAFTER = 0, @@ -34,8 +45,14 @@ var ChannelDefinition = function(channelName, defaultTopic) { }; ChannelDefinition.prototype = { - subscribe: function(callback) { - return new SubscriptionDefinition(this.channel, this.topic, callback); + subscribe: function() { + var len = arguments.length; + if(len === 1) { + return new SubscriptionDefinition(this.channel, this.topic, arguments[0]); + } + else if (len === 2) { + return new SubscriptionDefinition(this.channel, arguments[0], arguments[1]); + } }, publish: function(data, envelope) { @@ -43,142 +60,140 @@ ChannelDefinition.prototype = { env.channel = this.channel; env.timeStamp = new Date(); env.topic = env.topic || this.topic; - postal.configuration.bus.publish(env, data); + postal.configuration.bus.publish(data, env); } }; var SubscriptionDefinition = function(channel, topic, callback) { - this.channel = channel; - this.topic = topic; - this.callback = callback; - this.priority = DEFAULT_PRIORITY; - this.constraints = new Array(0); - this.maxCalls = DEFAULT_DISPOSEAFTER; - this.onHandled = NO_OP; - this.context = null; + this.channel = channel; + this.topic = topic; + this.callback = callback; + this.priority = DEFAULT_PRIORITY; + this.constraints = new Array(0); + this.maxCalls = DEFAULT_DISPOSEAFTER; + this.onHandled = NO_OP; + this.context = null; + postal.publish({ + event: "subscription.created", + channel: channel, + topic: topic + },{ + channel: SYSTEM_CHANNEL, + topic: "subscription.created" + }); postal.configuration.bus.subscribe(this); - postal.publish({ - channel: SYSTEM_CHANNEL, - topic: "subscription.created" - }, - { - event: "subscription.created", - channel: channel, - topic: topic - }); }; SubscriptionDefinition.prototype = { - unsubscribe: function() { - postal.configuration.bus.unsubscribe(this); - postal.publish({ - channel: SYSTEM_CHANNEL, - topic: "subscription.removed" - }, - { - event: "subscription.removed", - channel: this.channel, - topic: this.topic - }); - }, + unsubscribe: function() { + postal.configuration.bus.unsubscribe(this); + postal.publish({ + event: "subscription.removed", + channel: this.channel, + topic: this.topic + },{ + channel: SYSTEM_CHANNEL, + topic: "subscription.removed" + }); + }, - defer: function() { - var fn = this.callback; - this.callback = function(data) { - setTimeout(fn,0,data); - }; - return this; - }, + defer: function() { + var fn = this.callback; + this.callback = function(data) { + setTimeout(fn,0,data); + }; + return this; + }, - disposeAfter: function(maxCalls) { - if(_.isNaN(maxCalls) || maxCalls <= 0) { - throw "The value provided to disposeAfter (maxCalls) must be a number greater than zero."; - } + disposeAfter: function(maxCalls) { + if(_.isNaN(maxCalls) || maxCalls <= 0) { + throw "The value provided to disposeAfter (maxCalls) must be a number greater than zero."; + } - var fn = this.onHandled; - var dispose = _.after(maxCalls, _.bind(function() { - this.unsubscribe(this); - }, this)); + var fn = this.onHandled; + var dispose = _.after(maxCalls, _.bind(function() { + this.unsubscribe(this); + }, this)); - this.onHandled = function() { - fn.apply(this.context, arguments); - dispose(); - }; - return this; - }, + this.onHandled = function() { + fn.apply(this.context, arguments); + dispose(); + }; + return this; + }, - ignoreDuplicates: function() { - this.withConstraint(new DistinctPredicate()); - return this; - }, + ignoreDuplicates: function() { + this.withConstraint(new DistinctPredicate()); + return this; + }, - whenHandledThenExecute: function(callback) { - if(! _.isFunction(callback)) { - throw "Value provided to 'whenHandledThenExecute' must be a function"; - } - this.onHandled = callback; - return this; - }, + whenHandledThenExecute: function(callback) { + if(! _.isFunction(callback)) { + throw "Value provided to 'whenHandledThenExecute' must be a function"; + } + this.onHandled = callback; + return this; + }, - withConstraint: function(predicate) { - if(! _.isFunction(predicate)) { - throw "Predicate constraint must be a function"; - } - this.constraints.push(predicate); - return this; - }, + withConstraint: function(predicate) { + if(! _.isFunction(predicate)) { + throw "Predicate constraint must be a function"; + } + this.constraints.push(predicate); + return this; + }, - withConstraints: function(predicates) { - var self = this; - if(_.isArray(predicates)) { - _.each(predicates, function(predicate) { self.withConstraint(predicate); } ); - } - return self; - }, + withConstraints: function(predicates) { + var self = this; + if(_.isArray(predicates)) { + _.each(predicates, function(predicate) { self.withConstraint(predicate); } ); + } + return self; + }, - withContext: function(context) { - this.context = context; - return this; - }, + withContext: function(context) { + this.context = context; + return this; + }, - withDebounce: function(milliseconds) { - if(_.isNaN(milliseconds)) { - throw "Milliseconds must be a number"; - } - var fn = this.callback; - this.callback = _.debounce(fn, milliseconds); - return this; - }, + withDebounce: function(milliseconds) { + if(_.isNaN(milliseconds)) { + throw "Milliseconds must be a number"; + } + var fn = this.callback; + this.callback = _.debounce(fn, milliseconds); + return this; + }, - withDelay: function(milliseconds) { - if(_.isNaN(milliseconds)) { - throw "Milliseconds must be a number"; - } - var fn = this.callback; - this.callback = function(data) { - setTimeout(fn, milliseconds, data); - }; - return this; - }, + withDelay: function(milliseconds) { + if(_.isNaN(milliseconds)) { + throw "Milliseconds must be a number"; + } + var fn = this.callback; + this.callback = function(data) { + setTimeout(fn, milliseconds, data); + }; + return this; + }, - withPriority: function(priority) { - if(_.isNaN(priority)) { - throw "Priority must be a number"; - } - this.priority = priority; - return this; - }, + withPriority: function(priority) { + if(_.isNaN(priority)) { + throw "Priority must be a number"; + } + this.priority = priority; + return this; + }, - withThrottle: function(milliseconds) { - if(_.isNaN(milliseconds)) { - throw "Milliseconds must be a number"; - } - var fn = this.callback; - this.callback = _.throttle(fn, milliseconds); - return this; - } + withThrottle: function(milliseconds) { + if(_.isNaN(milliseconds)) { + throw "Milliseconds must be a number"; + } + var fn = this.callback; + this.callback = _.throttle(fn, milliseconds); + return this; + } }; var bindingsResolver = { @@ -209,9 +224,9 @@ var localBus = { wireTaps: new Array(0), - publish: function(envelope, data) { + publish: function(data, envelope) { _.each(this.wireTaps,function(tap) { - tap(envelope, data); + tap(data, envelope); }); _.each(this.subscriptions[envelope.channel], function(topic) { @@ -279,14 +294,14 @@ var localBus = { }; var publishPicker = { - "2" : function(envelope, payload) { + "2" : function(data, envelope) { if(!envelope.channel) { envelope.channel = DEFAULT_CHANNEL; } - postal.configuration.bus.publish(envelope, payload); + postal.configuration.bus.publish(data, envelope); }, "3" : function(channel, topic, payload) { - postal.configuration.bus.publish({ channel: channel, topic: topic }, payload); + postal.configuration.bus.publish(payload, { channel: channel, topic: topic }); } }; @@ -343,7 +358,7 @@ var postal = { var newEnv = env; newEnv.topic = _.isFunction(destination.topic) ? destination.topic(env.topic) : destination.topic || env.topic; newEnv.channel = destChannel; - postal.publish(newEnv, msg); + postal.publish(msg, newEnv); } }) ); @@ -352,5 +367,8 @@ var postal = { return result; } }; - -global.postal = postal; })(window); \ No newline at end of file + + + global.postal = postal; + return postal; +})); \ No newline at end of file diff --git a/lib/browser/amd/postal.diagnostics.js b/lib/browser/amd/postal.diagnostics.js deleted file mode 100644 index 9f9ee66..0000000 --- a/lib/browser/amd/postal.diagnostics.js +++ /dev/null @@ -1,20 +0,0 @@ -define(['postal', 'underscore'], function(postal, _) { -postal.addWireTap(function(data, envelope) { - var all = _.extend(envelope, { data: data }); - if(!JSON) { - throw "This browser or environment does not provide JSON support"; - } - try { - console.log(JSON.stringify(all)); - } - catch(exception) { - try { - all.data = "ERROR: " + exception.message; - console.log(JSON.stringify(all)); - } - catch(ex) { - console.log("Unable to parse data to JSON: " + exception); - } - } -}); -}); \ No newline at end of file diff --git a/lib/browser/amd/postal.diagnostics.min.gz.js b/lib/browser/amd/postal.diagnostics.min.gz.js deleted file mode 100644 index be522d3..0000000 Binary files a/lib/browser/amd/postal.diagnostics.min.gz.js and /dev/null differ diff --git a/lib/browser/amd/postal.diagnostics.min.js b/lib/browser/amd/postal.diagnostics.min.js deleted file mode 100644 index 674a524..0000000 --- a/lib/browser/amd/postal.diagnostics.min.js +++ /dev/null @@ -1 +0,0 @@ -define(["postal","underscore"],function(a,b){a.addWireTap(function(a,c){var d=b.extend(c,{data:a});if(!JSON)throw"This browser or environment does not provide JSON support";try{console.log(JSON.stringify(d))}catch(e){try{d.data="ERROR: "+e.message,console.log(JSON.stringify(d))}catch(f){console.log("Unable to parse data to JSON: "+e)}}})}) \ No newline at end of file diff --git a/lib/browser/amd/postal.js b/lib/browser/amd/postal.js deleted file mode 100644 index f8037cc..0000000 --- a/lib/browser/amd/postal.js +++ /dev/null @@ -1,356 +0,0 @@ -define(['underscore'], function(_) { -/* - postal.js - Author: Jim Cowart - License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license) - Version 0.4.0 -*/ - -var DEFAULT_CHANNEL = "/", - DEFAULT_PRIORITY = 50, - DEFAULT_DISPOSEAFTER = 0, - SYSTEM_CHANNEL = "postal", - NO_OP = function() { }; - -var DistinctPredicate = function() { - var previous; - return function(data) { - var eq = false; - if(_.isString(data)) { - eq = data === previous; - previous = data; - } - else { - eq = _.isEqual(data, previous); - previous = _.clone(data); - } - return !eq; - }; -}; - -var ChannelDefinition = function(channelName, defaultTopic) { - this.channel = channelName; - this.topic = defaultTopic || ""; -}; - -ChannelDefinition.prototype = { - subscribe: function(callback) { - return new SubscriptionDefinition(this.channel, this.topic, callback); - }, - - publish: function(data, envelope) { - var env = envelope || {}; - env.channel = this.channel; - env.timeStamp = new Date(); - env.topic = env.topic || this.topic; - postal.configuration.bus.publish(env, data); - } -}; - -var SubscriptionDefinition = function(channel, topic, callback) { - this.channel = channel; - this.topic = topic; - this.callback = callback; - this.priority = DEFAULT_PRIORITY; - this.constraints = new Array(0); - this.maxCalls = DEFAULT_DISPOSEAFTER; - this.onHandled = NO_OP; - this.context = null; - - postal.configuration.bus.subscribe(this); - - postal.publish({ - channel: SYSTEM_CHANNEL, - topic: "subscription.created" - }, - { - event: "subscription.created", - channel: channel, - topic: topic - }); -}; - -SubscriptionDefinition.prototype = { - unsubscribe: function() { - postal.configuration.bus.unsubscribe(this); - postal.publish({ - channel: SYSTEM_CHANNEL, - topic: "subscription.removed" - }, - { - event: "subscription.removed", - channel: this.channel, - topic: this.topic - }); - }, - - defer: function() { - var fn = this.callback; - this.callback = function(data) { - setTimeout(fn,0,data); - }; - return this; - }, - - disposeAfter: function(maxCalls) { - if(_.isNaN(maxCalls) || maxCalls <= 0) { - throw "The value provided to disposeAfter (maxCalls) must be a number greater than zero."; - } - - var fn = this.onHandled; - var dispose = _.after(maxCalls, _.bind(function() { - this.unsubscribe(this); - }, this)); - - this.onHandled = function() { - fn.apply(this.context, arguments); - dispose(); - }; - return this; - }, - - ignoreDuplicates: function() { - this.withConstraint(new DistinctPredicate()); - return this; - }, - - whenHandledThenExecute: function(callback) { - if(! _.isFunction(callback)) { - throw "Value provided to 'whenHandledThenExecute' must be a function"; - } - this.onHandled = callback; - return this; - }, - - withConstraint: function(predicate) { - if(! _.isFunction(predicate)) { - throw "Predicate constraint must be a function"; - } - this.constraints.push(predicate); - return this; - }, - - withConstraints: function(predicates) { - var self = this; - if(_.isArray(predicates)) { - _.each(predicates, function(predicate) { self.withConstraint(predicate); } ); - } - return self; - }, - - withContext: function(context) { - this.context = context; - return this; - }, - - withDebounce: function(milliseconds) { - if(_.isNaN(milliseconds)) { - throw "Milliseconds must be a number"; - } - var fn = this.callback; - this.callback = _.debounce(fn, milliseconds); - return this; - }, - - withDelay: function(milliseconds) { - if(_.isNaN(milliseconds)) { - throw "Milliseconds must be a number"; - } - var fn = this.callback; - this.callback = function(data) { - setTimeout(fn, milliseconds, data); - }; - return this; - }, - - withPriority: function(priority) { - if(_.isNaN(priority)) { - throw "Priority must be a number"; - } - this.priority = priority; - return this; - }, - - withThrottle: function(milliseconds) { - if(_.isNaN(milliseconds)) { - throw "Milliseconds must be a number"; - } - var fn = this.callback; - this.callback = _.throttle(fn, milliseconds); - return this; - } -}; - -var bindingsResolver = { - cache: { }, - - compare: function(binding, topic) { - if(this.cache[topic] && this.cache[topic][binding]) { - return true; - } - // binding.replace(/\./g,"\\.") // escape actual periods - // .replace(/\*/g, ".*") // asterisks match any value - // .replace(/#/g, "[A-Z,a-z,0-9]*"); // hash matches any alpha-numeric 'word' - var rgx = new RegExp("^" + binding.replace(/\./g,"\\.").replace(/\*/g, ".*").replace(/#/g, "[A-Z,a-z,0-9]*") + "$"), - result = rgx.test(topic); - if(result) { - if(!this.cache[topic]) { - this.cache[topic] = {}; - } - this.cache[topic][binding] = true; - } - return result; - } -}; - -var localBus = { - - subscriptions: {}, - - wireTaps: new Array(0), - - publish: function(envelope, data) { - _.each(this.wireTaps,function(tap) { - tap(envelope, data); - }); - - _.each(this.subscriptions[envelope.channel], function(topic) { - _.each(topic, function(binding){ - if(postal.configuration.resolver.compare(binding.topic, envelope.topic)) { - if(_.all(binding.constraints, function(constraint) { return constraint(data); })) { - if(typeof binding.callback === 'function') { - binding.callback.apply(binding.context, [data, envelope]); - binding.onHandled(); - } - } - } - }); - }); - }, - - subscribe: function(subDef) { - var idx, found, fn, channel = this.subscriptions[subDef.channel], subs; - - if(!channel) { - channel = this.subscriptions[subDef.channel] = {}; - } - subs = this.subscriptions[subDef.channel][subDef.topic]; - if(!subs) { - subs = this.subscriptions[subDef.channel][subDef.topic] = new Array(0); - } - - idx = subs.length - 1; - for(; idx >= 0; idx--) { - if(subs[idx].priority <= subDef.priority) { - subs.splice(idx + 1, 0, subDef); - found = true; - break; - } - } - if(!found) { - subs.unshift(subDef); - } - return subDef; - }, - - unsubscribe: function(config) { - if(this.subscriptions[config.channel][config.topic]) { - var len = this.subscriptions[config.channel][config.topic].length, - idx = 0; - for ( ; idx < len; idx++ ) { - if (this.subscriptions[config.channel][config.topic][idx] === config) { - this.subscriptions[config.channel][config.topic].splice( idx, 1 ); - break; - } - } - } - }, - - addWireTap: function(callback) { - var self = this; - self.wireTaps.push(callback); - return function() { - var idx = self.wireTaps.indexOf(callback); - if(idx !== -1) { - self.wireTaps.splice(idx,1); - } - }; - } -}; - -var publishPicker = { - "2" : function(envelope, payload) { - if(!envelope.channel) { - envelope.channel = DEFAULT_CHANNEL; - } - postal.configuration.bus.publish(envelope, payload); - }, - "3" : function(channel, topic, payload) { - postal.configuration.bus.publish({ channel: channel, topic: topic }, payload); - } -}; - -// save some setup time, albeit tiny -localBus.subscriptions[SYSTEM_CHANNEL] = {}; - -var postal = { - configuration: { - bus: localBus, - resolver: bindingsResolver - }, - - channel: function(options) { - var channel = options.channel || DEFAULT_CHANNEL, - tpc = options.topic; - return new ChannelDefinition(channel, tpc); - }, - - subscribe: function(options) { - var callback = options.callback, - topic = options.topic, - channel = options.channel || DEFAULT_CHANNEL; - return new SubscriptionDefinition(channel, topic, callback); - }, - - publish: function() { - var len = arguments.length; - if(publishPicker[len]) { - publishPicker[len].apply(this, arguments); - } - }, - - addWireTap: function(callback) { - return this.configuration.bus.addWireTap(callback); - }, - - linkChannels: function(sources, destinations) { - var result = []; - if(!_.isArray(sources)) { - sources = [sources]; - } - if(!_.isArray(destinations)) { - destinations = [destinations]; - } - _.each(sources, function(source){ - var sourceTopic = source.topic || "*"; - _.each(destinations, function(destination) { - var destChannel = destination.channel || DEFAULT_CHANNEL; - result.push( - postal.subscribe({ - channel: source.channel || DEFAULT_CHANNEL, - topic: source.topic || "*", - callback : function(msg, env) { - var newEnv = env; - newEnv.topic = _.isFunction(destination.topic) ? destination.topic(env.topic) : destination.topic || env.topic; - newEnv.channel = destChannel; - postal.publish(newEnv, msg); - } - }) - ); - }); - }); - return result; - } -}; - -return postal; }); \ No newline at end of file diff --git a/lib/browser/amd/postal.min.gz.js b/lib/browser/amd/postal.min.gz.js deleted file mode 100644 index 6f0e3e1..0000000 Binary files a/lib/browser/amd/postal.min.gz.js and /dev/null differ diff --git a/lib/browser/amd/postal.min.js b/lib/browser/amd/postal.min.js deleted file mode 100644 index 5022587..0000000 --- a/lib/browser/amd/postal.min.js +++ /dev/null @@ -1 +0,0 @@ -define(["underscore"],function(a){var b="/",c=50,d=0,e="postal",f=function(){},g=function(){var b;return function(c){var d=!1;return a.isString(c)?(d=c===b,b=c):(d=a.isEqual(c,b),b=a.clone(c)),!d}},h=function(a,b){this.channel=a,this.topic=b||""};h.prototype={subscribe:function(a){return new i(this.channel,this.topic,a)},publish:function(a,b){var c=b||{};c.channel=this.channel,c.timeStamp=new Date,c.topic=c.topic||this.topic,m.configuration.bus.publish(c,a)}};var i=function(a,b,g){this.channel=a,this.topic=b,this.callback=g,this.priority=c,this.constraints=new Array(0),this.maxCalls=d,this.onHandled=f,this.context=null,m.configuration.bus.subscribe(this),m.publish({channel:e,topic:"subscription.created"},{event:"subscription.created",channel:a,topic:b})};i.prototype={unsubscribe:function(){m.configuration.bus.unsubscribe(this),m.publish({channel:e,topic:"subscription.removed"},{event:"subscription.removed",channel:this.channel,topic:this.topic})},defer:function(){var a=this.callback;return this.callback=function(b){setTimeout(a,0,b)},this},disposeAfter:function(b){if(a.isNaN(b)||b<=0)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var c=this.onHandled,d=a.after(b,a.bind(function(){this.unsubscribe(this)},this));return this.onHandled=function(){c.apply(this.context,arguments),d()},this},ignoreDuplicates:function(){return this.withConstraint(new g),this},whenHandledThenExecute:function(b){if(!a.isFunction(b))throw"Value provided to 'whenHandledThenExecute' must be a function";return this.onHandled=b,this},withConstraint:function(b){if(!a.isFunction(b))throw"Predicate constraint must be a function";return this.constraints.push(b),this},withConstraints:function(b){var c=this;return a.isArray(b)&&a.each(b,function(a){c.withConstraint(a)}),c},withContext:function(a){return this.context=a,this},withDebounce:function(b){if(a.isNaN(b))throw"Milliseconds must be a number";var c=this.callback;return this.callback=a.debounce(c,b),this},withDelay:function(b){if(a.isNaN(b))throw"Milliseconds must be a number";var c=this.callback;return this.callback=function(a){setTimeout(c,b,a)},this},withPriority:function(b){if(a.isNaN(b))throw"Priority must be a number";return this.priority=b,this},withThrottle:function(b){if(a.isNaN(b))throw"Milliseconds must be a number";var c=this.callback;return this.callback=a.throttle(c,b),this}};var j={cache:{},compare:function(a,b){if(this.cache[b]&&this.cache[b][a])return!0;var c=new RegExp("^"+a.replace(/\./g,"\\.").replace(/\*/g,".*").replace(/#/g,"[A-Z,a-z,0-9]*")+"$"),d=c.test(b);return d&&(this.cache[b]||(this.cache[b]={}),this.cache[b][a]=!0),d}},k={subscriptions:{},wireTaps:new Array(0),publish:function(b,c){a.each(this.wireTaps,function(a){a(b,c)}),a.each(this.subscriptions[b.channel],function(d){a.each(d,function(d){m.configuration.resolver.compare(d.topic,b.topic)&&a.all(d.constraints,function(a){return a(c)})&&typeof d.callback=="function"&&(d.callback.apply(d.context,[c,b]),d.onHandled())})})},subscribe:function(a){var b,c,d,e=this.subscriptions[a.channel],f;e||(e=this.subscriptions[a.channel]={}),f=this.subscriptions[a.channel][a.topic],f||(f=this.subscriptions[a.channel][a.topic]=new Array(0)),b=f.length-1;for(;b>=0;b--)if(f[b].priority<=a.priority){f.splice(b+1,0,a),c=!0;break}return c||f.unshift(a),a},unsubscribe:function(a){if(this.subscriptions[a.channel][a.topic]){var b=this.subscriptions[a.channel][a.topic].length,c=0;for(;c=0;b--)if(f[b].priority<=a.priority){f.splice(b+1,0,a),c=!0;break}return c||f.unshift(a),a},unsubscribe:function(a){if(this.subscriptions[a.channel][a.topic]){var b=this.subscriptions[a.channel][a.topic].length,c=0;for(;c=0;b--)if(f[b].priority<=a.priority){f.splice(b+1,0,a),c=!0;break}return c||f.unshift(a),a},unsubscribe:function(a){if(this.subscriptions[a.channel][a.topic]){var b=this.subscriptions[a.channel][a.topic].length,c=0;for(;c