diff --git a/CHANGELOG.md b/CHANGELOG.md index 8928f27..13c91cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,40 @@ # CHANGELOG +## v3.0.0 + +### Breaking changes + +The default API method aliases are deprecated and removed from v3.0.0 onwards. However there is a new method `alias` introduced, that allows to create your own aliases. Therefore, if you already use those aliases in a project you can use the `alias` method to provide your own. + +Below is a map of the default aliases that existed prior to version 3.0.0: + +| Original method | Alias method | +| --------------- | ------------- | +| `subscribe` | `on` | +| `subscribeOnce` | `once` | +| `publishSync` | `triggerSync` | +| `unsubscribe` | `off` | +| `hasSubscribers` | `has` | + +To create your own aliases: + +```js +var pubsub = new PubSub().alias({ + subscribe: 'on', + subscribeOnce: 'once', + publish: 'trigger', + publishSync: 'triggerSync', + unsubscribe: 'off', + hasSubscribers: 'has' +}); +``` + +### Other updates + +- Add public method `unsubscribeAll` to clear all subscriptions whatsoever. +- Add public method `alias` to create your own method aliases. (See above) +- Provide source-map for the minified library. + ## v2.1.0 - Add support for publishing events synchronously using `publishSync` method. - Add public method `hasSubscribers` to check if there are subscribers for a specific topic. diff --git a/Gruntfile.js b/Gruntfile.js index 8472e67..c4d8cb1 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -6,6 +6,7 @@ module.exports = function (grunt) { uglify: { options: { + sourceMap: 'dist/', banner: '/**\n' + ' * <%= pkg.name %>\n' + ' * <%= pkg.description %>\n' + diff --git a/README.md b/README.md index db52ff1..c80633d 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,10 @@ $ npm install PubSub $ bower install georapbox.pubsub.js ``` +## Changelog + +For API updates and breaking changes, check the [CHANGELOG](https://github.com/georapbox/PubSub/blob/master/CHANGELOG.md). + ## API * [PubSub](#PubSub) @@ -35,6 +39,8 @@ $ bower install georapbox.pubsub.js * [.publishSync(topic, [data])](#PubSub+publishSync) ⇒ boolean * [.unsubscribe(topic)](#PubSub+unsubscribe) ⇒ boolean | string * [.hasSubscribers(topic)](#PubSub+hasSubscribers) ⇒ Boolean + * [.unsubscribeAll()](#PubSub+unsubscribeAll) ⇒ [PubSub](#PubSub) + * [.alias(aliasMap)](#PubSub+alias) ⇒ [PubSub](#PubSub) @@ -177,15 +183,45 @@ pubsub.on('message', function (data) { pubsub.hasSubscribers('message'); // -> true ``` + + +### pubSub.unsubscribeAll() ⇒ [PubSub](#PubSub) +Clears all subscriptions whatsoever. + +**Kind**: instance method of [PubSub](#PubSub) +**Returns**: [PubSub](#PubSub) - The PubSub instance. +**this**: {PubSub} +**Example** +```js +var pubsub = new PubSub(); +... +... +pubsub.unsubscribeAll(); +``` + +### pubSub.alias(aliasMap) ⇒ [PubSub](#PubSub) +Creates aliases for public methods. -### Methods aliases -- `on` - `subscribe` -- `once` - `subscribeOnce` -- `trigger` - `publish` -- `triggerSync` - `publishSync` -- `off` - `unsubscribe` -- `has` - `hasSubscribers` +**Kind**: instance method of [PubSub](#PubSub) +**Returns**: [PubSub](#PubSub) - The PubSub instance. +**this**: {PubSub} + +| Param | Type | Description | +| --- | --- | --- | +| aliasMap | object | A plain object that maps the public methods to their aliases. | + +**Example** +```js +var pubsub = new PubSub().alias({ + subscribe: 'on', + subscribeOnce: 'once', + publish: 'trigger', + publishSync: 'triggerSync', + unsubscribe: 'off', + hasSubscribers: 'has' +}); +``` ## Minify diff --git a/dist/pubsub.min.js b/dist/pubsub.min.js index 3fe5b66..e1e9513 100644 --- a/dist/pubsub.min.js +++ b/dist/pubsub.min.js @@ -2,10 +2,12 @@ * PubSub * Javascript implementation of the Publish/Subscribe pattern. * - * @version 2.1.0 + * @version 3.0.0 * @author George Raptis (georapbox.github.io) * @homepage https://github.com/georapbox/PubSub#readme * @repository git+https://github.com/georapbox/PubSub.git * @license MIT */ -!function(a,b,c){"use strict";"function"==typeof define&&define.amd?define(c):"undefined"!=typeof module&&module.exports?module.exports=c():b[a]=c()}("PubSub",this,function(){"use strict";function a(a){return function(){return this[a].apply(this,arguments)}}function b(a,b,c){for(var d,e,f=a.topics[b],g=f?f.length:0;g;)g-=1,e=f[g].token,d=f[g],d.callback(c,{name:b,token:e}),d.once===!0&&a.unsubscribe(e)}function c(a,c,d,e){return!!a.topics[c]&&(e?b(a,c,d):setTimeout(function(){b(a,c,d)},0),!0)}function d(){this.topics={},this.subUid=-1}return d.prototype.subscribe=function(a,b,c){var d=this.subUid+=1,e={};if("function"!=typeof b)throw new TypeError("When subscribing for an event, a callback function must be defined.");return this.topics[a]||(this.topics[a]=[]),e.token=d,e.callback=b,e.once=!!c,this.topics[a].push(e),d},d.prototype.subscribeOnce=function(a,b){return this.subscribe(a,b,!0)},d.prototype.publish=function(a,b){return c(this,a,b,!1)},d.prototype.publishSync=function(a,b){return c(this,a,b,!0)},d.prototype.unsubscribe=function(a){var b,c,d=!1;for(b in this.topics)if(Object.hasOwnProperty.call(this.topics,b)&&this.topics[b]){for(c=this.topics[b].length;c;){if(c-=1,this.topics[b][c].token===a)return this.topics[b].splice(c,1),a;b===a&&(this.topics[b].splice(c,1),d=!0)}if(d===!0)return a}return!1},d.prototype.hasSubscribers=function(a){var b=this.topics;return!!(Object.hasOwnProperty.call(b,a)&&b[a].length>0)},d.prototype.on=a("subscribe"),d.prototype.once=a("subscribeOnce"),d.prototype.trigger=a("publish"),d.prototype.triggerSync=a("publishSync"),d.prototype.off=a("unsubscribe"),d.prototype.has=a("hasSubscribers"),d}); \ No newline at end of file + +!function(a,b,c){"use strict";"function"==typeof define&&define.amd?define(c):"undefined"!=typeof module&&module.exports?module.exports=c():b[a]=c()}("PubSub",this,function(){"use strict";function a(a){return function(){return this[a].apply(this,arguments)}}function b(a,b,c){for(var d,e,f=a.topics[b],g=f?f.length:0;g;)g-=1,e=f[g].token,d=f[g],d.callback(c,{name:b,token:e}),d.once===!0&&a.unsubscribe(e)}function c(a,c,d,e){return!!a.topics[c]&&(e?b(a,c,d):setTimeout(function(){b(a,c,d)},0),!0)}function d(){return this.topics={},this.subUid=-1,this}return d.prototype.subscribe=function(a,b,c){var d=this.subUid+=1,e={};if("function"!=typeof b)throw new TypeError("When subscribing for an event, a callback function must be defined.");return this.topics[a]||(this.topics[a]=[]),e.token=d,e.callback=b,e.once=!!c,this.topics[a].push(e),d},d.prototype.subscribeOnce=function(a,b){return this.subscribe(a,b,!0)},d.prototype.publish=function(a,b){return c(this,a,b,!1)},d.prototype.publishSync=function(a,b){return c(this,a,b,!0)},d.prototype.unsubscribe=function(a){var b,c,d=!1;for(b in this.topics)if(Object.hasOwnProperty.call(this.topics,b)&&this.topics[b]){for(c=this.topics[b].length;c;){if(c-=1,this.topics[b][c].token===a)return this.topics[b].splice(c,1),a;b===a&&(this.topics[b].splice(c,1),d=!0)}if(d===!0)return a}return!1},d.prototype.hasSubscribers=function(a){var b=this.topics;return!!(Object.hasOwnProperty.call(b,a)&&b[a].length>0)},d.prototype.unsubscribeAll=function(){var a;for(a in this.topics)Object.hasOwnProperty.call(this.topics,a)&&(this.topics[a]=[]);return this},d.prototype.alias=function(b){var c;for(c in b)Object.hasOwnProperty.call(b,c)&&d.prototype[c]&&(d.prototype[b[c]]=a(c));return this},d}); +//# sourceMappingURL=pubsub.min.js.map \ No newline at end of file diff --git a/dist/pubsub.min.js.map b/dist/pubsub.min.js.map new file mode 100644 index 0000000..ee119ce --- /dev/null +++ b/dist/pubsub.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/pubsub.js"],"names":["name","context","definition","define","amd","module","exports","this","alias","fn","apply","arguments","deliverTopic","instance","topic","data","currentSubscriber","token","subscribers","topics","len","length","callback","once","unsubscribe","publish","sync","setTimeout","PubSub","subUid","prototype","subscribe","obj","TypeError","push","subscribeOnce","publishSync","prop","tf","Object","hasOwnProperty","call","splice","hasSubscribers","unsubscribeAll","aliasMap"],"mappings":";;;;;;;;;;;CAUC,SAAUA,EAAMC,EAASC,GACxB,YACsB,mBAAXC,SAAyBA,OAAOC,IACzCD,OAAOD,GACoB,mBAAXG,SAA0BA,OAAOC,QACjDD,OAAOC,QAAUJ,IAEjBD,EAAQD,GAAQE,KAElB,SAAUK,KAAM,WAChB,YAEA,SAASC,GAAMC,GACb,MAAO,YACL,MAAOF,MAAKE,GAAIC,MAAMH,KAAMI,YAIhC,QAASC,GAAaC,EAAUC,EAAOC,GAKrC,IAJA,GAEEC,GAAmBC,EAFjBC,EAAcL,EAASM,OAAOL,GAChCM,EAAMF,EAAcA,EAAYG,OAAS,EAGpCD,GACLA,GAAO,EACPH,EAAQC,EAAYE,GAAKH,MACzBD,EAAoBE,EAAYE,GAEhCJ,EAAkBM,SAASP,GACzBf,KAAMc,EACNG,MAAOA,IAKLD,EAAkBO,QAAS,GAC7BV,EAASW,YAAYP,GAK3B,QAASQ,GAAQZ,EAAUC,EAAOC,EAAMW,GACtC,QAAKb,EAASM,OAAOL,KAIrBY,EAAOd,EAAaC,EAAUC,EAAOC,GAAQY,WAAW,WACtDf,EAAaC,EAAUC,EAAOC,IAC7B,IAEI,GAOT,QAASa,KAGP,MAFArB,MAAKY,UACLZ,KAAKsB,QAAS,EACPtB,KAkPT,MA1NAqB,GAAOE,UAAUC,UAAY,SAAUjB,EAAOQ,EAAUC,GACtD,GAAIN,GAAQV,KAAKsB,QAAU,EACzBG,IAEF,IAAwB,kBAAbV,GACT,KAAM,IAAIW,WAAU,sEAatB,OAVK1B,MAAKY,OAAOL,KACfP,KAAKY,OAAOL,OAGdkB,EAAIf,MAAQA,EACZe,EAAIV,SAAWA,EACfU,EAAIT,OAASA,EAEbhB,KAAKY,OAAOL,GAAOoB,KAAKF,GAEjBf,GAqBTW,EAAOE,UAAUK,cAAgB,SAAUrB,EAAOQ,GAChD,MAAOf,MAAKwB,UAAUjB,EAAOQ,GAAU,IAmBzCM,EAAOE,UAAUL,QAAU,SAAUX,EAAOC,GAC1C,MAAOU,GAAQlB,KAAMO,EAAOC,GAAM,IAmBpCa,EAAOE,UAAUM,YAAc,SAAUtB,EAAOC,GAC9C,MAAOU,GAAQlB,KAAMO,EAAOC,GAAM,IAmBpCa,EAAOE,UAAUN,YAAc,SAAUV,GACvC,GACEuB,GAAMjB,EADJkB,GAAK,CAGT,KAAKD,IAAQ9B,MAAKY,OAChB,GAAIoB,OAAOC,eAAeC,KAAKlC,KAAKY,OAAQkB,IACtC9B,KAAKY,OAAOkB,GAAO,CAGrB,IAFAjB,EAAMb,KAAKY,OAAOkB,GAAMhB,OAEjBD,GAAK,CAIV,GAHAA,GAAO,EAGHb,KAAKY,OAAOkB,GAAMjB,GAAKH,QAAUH,EAEnC,MADAP,MAAKY,OAAOkB,GAAMK,OAAOtB,EAAK,GACvBN,CAILuB,KAASvB,IACXP,KAAKY,OAAOkB,GAAMK,OAAOtB,EAAK,GAC9BkB,GAAK,GAIT,GAAIA,KAAO,EACT,MAAOxB,GAMf,OAAO,GAoBTc,EAAOE,UAAUa,eAAiB,SAAU7B,GAC1C,GAAIK,GAASZ,KAAKY,MAElB,UAAIoB,OAAOC,eAAeC,KAAKtB,EAAQL,IAAUK,EAAOL,GAAOO,OAAS,IAoB1EO,EAAOE,UAAUc,eAAiB,WAChC,GAAIP,EAEJ,KAAKA,IAAQ9B,MAAKY,OACZoB,OAAOC,eAAeC,KAAKlC,KAAKY,OAAQkB,KAC1C9B,KAAKY,OAAOkB,MAIhB,OAAO9B,OAqBTqB,EAAOE,UAAUtB,MAAQ,SAAUqC,GACjC,GAAIR,EAEJ,KAAKA,IAAQQ,GACPN,OAAOC,eAAeC,KAAKI,EAAUR,IACnCT,EAAOE,UAAUO,KACnBT,EAAOE,UAAUe,EAASR,IAAS7B,EAAM6B,GAK/C,OAAO9B,OAGFqB","file":"pubsub.min.js"} \ No newline at end of file diff --git a/package.json b/package.json index 6791e87..0139db2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "PubSub", - "version": "2.1.0", + "version": "3.0.0", "description": "Javascript implementation of the Publish/Subscribe pattern.", "main": "src/pubsub.js", "scripts": { diff --git a/src/pubsub.js b/src/pubsub.js index 8fbb2d3..b6929d6 100644 --- a/src/pubsub.js +++ b/src/pubsub.js @@ -2,7 +2,7 @@ * PubSub.js * Javascript implementation of the Publish/Subscribe pattern. * - * @version 2.1.0 + * @version 3.0.0 * @author George Raptis (georapbox.github.io) * @homepage https://github.com/georapbox/PubSub#readme * @repository git+https://github.com/georapbox/PubSub.git @@ -68,6 +68,7 @@ function PubSub() { this.topics = {}; // Storage for topics that can be broadcast or listened to. this.subUid = -1; // A topic identifier. + return this; } /** @@ -252,13 +253,62 @@ return false; }; - // Alias for public methods. - PubSub.prototype.on = alias('subscribe'); - PubSub.prototype.once = alias('subscribeOnce'); - PubSub.prototype.trigger = alias('publish'); - PubSub.prototype.triggerSync = alias('publishSync'); - PubSub.prototype.off = alias('unsubscribe'); - PubSub.prototype.has = alias('hasSubscribers'); + /** + * Clears all subscriptions whatsoever. + * + * @memberof PubSub + * @this {PubSub} + * @return {PubSub} The PubSub instance. + * @example + * + * var pubsub = new PubSub(); + * ... + * ... + * pubsub.unsubscribeAll(); + */ + PubSub.prototype.unsubscribeAll = function () { + var prop; + + for (prop in this.topics) { + if (Object.hasOwnProperty.call(this.topics, prop)) { + this.topics[prop] = []; + } + } + + return this; + }; + + /** + * Creates aliases for public methods. + * + * @memberof PubSub + * @this {PubSub} + * @param {object} aliasMap A plain object that maps the public methods to their aliases. + * @return {PubSub} The PubSub instance. + * @example + * + * var pubsub = new PubSub().alias({ + * subscribe: 'on', + * subscribeOnce: 'once', + * publish: 'trigger', + * publishSync: 'triggerSync', + * unsubscribe: 'off', + * hasSubscribers: 'has' + * }); + */ + PubSub.prototype.alias = function (aliasMap) { + var prop; + + for (prop in aliasMap) { + if (Object.hasOwnProperty.call(aliasMap, prop)) { + if (PubSub.prototype[prop]) { + PubSub.prototype[aliasMap[prop]] = alias(prop); + } + } + } + + return this; + }; return PubSub; })); diff --git a/tests/pubsub.specs.js b/tests/pubsub.specs.js index a2d6bc6..753a053 100644 --- a/tests/pubsub.specs.js +++ b/tests/pubsub.specs.js @@ -104,3 +104,39 @@ describe('Check if there are subscribers for a specific topic.', function () { expect(ps.hasSubscribers('message')).toBe(false); }); }); + +// Clear all subscriptions at once. +describe('Clears all subscriptions at once', function () { + it('Should unsubscribe from all subscriptions', function () { + var ps = new PubSub(); + var listener = function listener() {} + + // Subscribe to some events + ps.subscribe('eventA', listener); + ps.subscribe('eventB', listener); + ps.subscribe('eventC', listener); + ps.subscribeOnce('eventA', listener); + ps.subscribeOnce('eventB', listener); + ps.subscribeOnce('eventC', listener); + + // Unsubscribe from all + ps.unsubscribeAll(); + + expect(ps.hasSubscribers('eventA')).toBe(false); + expect(ps.hasSubscribers('eventB')).toBe(false); + expect(ps.hasSubscribers('eventC')).toBe(false); + }); +}); + +// Alias methods +describe('Public methods alias', function () { + it('Should create aliases "on" and "off" for "subscribe" and "unsubscribe" methods respectively', function () { + var ps = new PubSub().alias({ + subscribe: 'on', + unsubscribe: 'off' + }); + + expect(PubSub.prototype.on).not.toBeUndefined(); + expect(PubSub.prototype.off).not.toBeUndefined(); + }); +});