diff --git a/CHANGELOG.md b/CHANGELOG.md index d84e5f3..f1f11c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # CHANGELOG +## v3.4.0 +- Add static method `PubSub.noConflict()` to roll back the global `PubSub` identifier. Used in a normal browser global namespace environment to avoid conflicts, etc. + ## v3.3.0 - If there is no subscriber for a topic, delete topic property when unsubscribing. Used to leave it as an empty array before. - The result of `subscribers` and `subscribersByTopic` methods is just a copy of the original object or array accordingly. diff --git a/README.md b/README.md index 93431e3..6e62a91 100644 --- a/README.md +++ b/README.md @@ -30,35 +30,34 @@ $ 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) * [new PubSub()](#new_PubSub_new) - * [.subscribe(topic, callback, [once])](#PubSub+subscribe) ⇒ number - * [.subscribeOnce(topic, callback)](#PubSub+subscribeOnce) ⇒ number - * [.publish(topic, [data])](#PubSub+publish) ⇒ boolean - * [.publishSync(topic, [data])](#PubSub+publishSync) ⇒ boolean - * [.unsubscribe(topic)](#PubSub+unsubscribe) ⇒ boolean \| string - * [.unsubscribeAll()](#PubSub+unsubscribeAll) ⇒ [PubSub](#PubSub) - * [.hasSubscribers([topic])](#PubSub+hasSubscribers) ⇒ boolean - * [.subscribers()](#PubSub+subscribers) ⇒ object - * [.subscribersByTopic(topic)](#PubSub+subscribersByTopic) ⇒ array - * [.alias(aliasMap)](#PubSub+alias) ⇒ [PubSub](#PubSub) + * _instance_ + * [.subscribe(topic, callback, [once])](#PubSub+subscribe) ⇒ number + * [.subscribeOnce(topic, callback)](#PubSub+subscribeOnce) ⇒ number + * [.publish(topic, [...data])](#PubSub+publish) ⇒ boolean + * [.publishSync(topic, [...data])](#PubSub+publishSync) ⇒ boolean + * [.unsubscribe(topic)](#PubSub+unsubscribe) ⇒ boolean \| string + * [.unsubscribeAll()](#PubSub+unsubscribeAll) ⇒ [PubSub](#PubSub) + * [.hasSubscribers([topic])](#PubSub+hasSubscribers) ⇒ boolean + * [.subscribers()](#PubSub+subscribers) ⇒ object + * [.subscribersByTopic(topic)](#PubSub+subscribersByTopic) ⇒ array + * [.alias(aliasMap)](#PubSub+alias) ⇒ [PubSub](#PubSub) + * _static_ + * [.noConflict()](#PubSub.noConflict) ⇒ [PubSub](#PubSub) ### new PubSub() Creates a PubSub instance. -### Methods +## Instance Methods -### .subscribe(topic, callback, [once]) ⇒ number +### pubSub.subscribe(topic, callback, [once]) ⇒ number Subscribe to events of interest with a specific topic name and a callback function, to be executed when the topic/event is observed. @@ -82,7 +81,7 @@ var onUserAdd = pubsub.subscribe('user_add', function (data, topic) { ``` -### .subscribeOnce(topic, callback) ⇒ number +### pubSub.subscribeOnce(topic, callback) ⇒ number Subscribe to events of interest setting a flag indicating the event will be published only one time. @@ -103,7 +102,7 @@ var onUserAdd = pubsub.subscribeOnce('user_add', function (data, topic) { ``` -### .publish(topic, [data]) ⇒ boolean +### pubSub.publish(topic, [data]) ⇒ boolean Publishes a topic **asynchronously**, passing the data to its subscribers. Asynchronous publication helps in that the originator of the topics will not be blocked while consumers process them. For synchronous topic publication check `publishSync`. @@ -126,7 +125,7 @@ pubsub.publish('user_add', { ``` -### .publishSync(topic, [data]) ⇒ boolean +### pubSub.publishSync(topic, [data]) ⇒ boolean Publishes a topic **synchronously**, passing the data to its subscribers. **Kind**: instance method of [PubSub](#PubSub) @@ -147,7 +146,7 @@ pubsub.publishSync('user_add', { ``` -### .unsubscribe(topic) ⇒ boolean \| string +### pubSub.unsubscribe(topic) ⇒ boolean \| string Unsubscribes from a specific topic, based on the topic name, or based on a tokenized reference to the subscription. @@ -168,7 +167,7 @@ pubsub.unsubscribe(onUserAdd); ``` -### .unsubscribeAll() ⇒ [PubSub](#PubSub) +### pubSub.unsubscribeAll() ⇒ [PubSub](#PubSub) Clears all subscriptions whatsoever. **Kind**: instance method of [PubSub](#PubSub) @@ -184,7 +183,7 @@ pubsub.hasSubscribers(); // -> false ``` -### .hasSubscribers([topic]) ⇒ boolean +### pubSub.hasSubscribers([topic]) ⇒ boolean Checks if there are subscribers for a specific topic. If `topic` is not provided, checks if there is at least one subscriber. @@ -207,14 +206,13 @@ pubsub.hasSubscribers('message'); ``` -### .subscribers() ⇒ object +### pubSub.subscribers() ⇒ object Gets all the subscribers as a set of key value pairs that represent the topic's name and the event listener(s) bound. -**NOTE**: Mutating the result of this method does not affect the real subscribers. This is for reference only. - **Kind**: instance method of [PubSub](#PubSub) **Returns**: object - A readonly object with all subscribers. +**Note**: Mutating the result of this method does not affect the real subscribers. This is for reference only. **Example** ```js var pubsub = new PubSub(); @@ -228,13 +226,12 @@ pubsub.subscribers(); ``` -### .subscribersByTopic(topic) ⇒ array +### pubSub.subscribersByTopic(topic) ⇒ array Gets subscribers for a specific topic. -**NOTE**: Mutating the result of this method does not affect the real subscribers. This is for reference only. - **Kind**: instance method of [PubSub](#PubSub) **Returns**: array - A copy array of all subscribers for a topic if exist; otherwise an empty array +**Note**: Mutating the result of this method does not affect the real subscribers. This is for reference only. | Param | Type | Description | | --- | --- | --- | @@ -259,7 +256,7 @@ pubsub.subscribersByTopic('some_message_not_existing'); ``` -### .alias(aliasMap) ⇒ [PubSub](#PubSub) +### pubSub.alias(aliasMap) ⇒ [PubSub](#PubSub) Creates aliases for public methods. **Kind**: instance method of [PubSub](#PubSub) @@ -281,6 +278,24 @@ var pubsub = new PubSub().alias({ }); ``` +## Static methods + + + +### PubSub.noConflict() ⇒ [PubSub](#PubSub) +Rolls back the global `PubSub` identifier and returns the current constructor function. +This can be used to keep the global namespace clean, or it can be used to have multiple simultaneous libraries +(including separate versions/copies of `PubSub`) in the same project without conflicts over the `PubSub` global identifier. + +**Kind**: static method of [PubSub](#PubSub) +**Returns**: [PubSub](#PubSub) - The PubSub constructor. +**Note**: The `PubSub.noConflict()` static method only makes sense when used in a normal browser global namespace environment. It should not be used with CommonJS or AMD style modules. +**Example** +```js +var EventEmitter = PubSub.noConflict(); +var emitter = new EventEmitter(); +``` + ## Minify source code ```sh @@ -296,6 +311,10 @@ To run the tests: $ npm test ``` +## Changelog + +For API updates and breaking changes, check the [CHANGELOG](https://github.com/georapbox/PubSub/blob/master/CHANGELOG.md). + ## More about Publish/Subscribe pattern - [The Observer Pattern - Addy Osmani](https://addyosmani.com/resources/essentialjsdesignpatterns/book/#observerpatternjavascript) diff --git a/src/pubsub.js b/src/pubsub.js index b12e5d1..115c311 100644 --- a/src/pubsub.js +++ b/src/pubsub.js @@ -2,7 +2,7 @@ * PubSub.js * Javascript implementation of the Publish/Subscribe pattern. * - * @version 3.3.0 + * @version 3.4.0 * @author George Raptis (georapbox.github.io) * @homepage https://github.com/georapbox/PubSub#readme * @repository https://github.com/georapbox/PubSub.git @@ -16,11 +16,14 @@ } else if (typeof module !== 'undefined' && module.exports) { module.exports = definition(); } else { - context[name] = definition(); + context[name] = definition(name, context); } -}('PubSub', this, function () { +}('PubSub', this, function (name, context) { 'use strict'; + var VERSION = '3.4.0'; + var OLD_PUBLIC_API = (context || {})[name]; + function forOwn(obj, callback, thisArg) { var key; @@ -408,5 +411,33 @@ return this; }; + /** + * Rolls back the global `PubSub` identifier and returns the current constructor function. + * This can be used to keep the global namespace clean, or it can be used to have multiple simultaneous libraries + * (including separate versions/copies of `PubSub`) in the same project without conflicts over the `PubSub` global identifier. + * + * @NOTE The `PubSub.noConflict()` static method only makes sense when used in a normal browser global namespace environment. + * It should not be used with CommonJS or AMD style modules. + * + * @memberof PubSub + * @return {PubSub} The PubSub constructor. + * @example + * + * var EventEmitter = PubSub.noConflict(); + * var emitter = new EventEmitter(); + */ + PubSub.noConflict = function noConflict() { + if (context) { + context[name] = OLD_PUBLIC_API; + } + return PubSub; + }; + + /** + * PubSub version + * @type {String} + */ + PubSub.version = VERSION; + return PubSub; })); diff --git a/tests/pubsub.specs.js b/tests/pubsub.specs.js index 549a092..d616c94 100644 --- a/tests/pubsub.specs.js +++ b/tests/pubsub.specs.js @@ -327,3 +327,14 @@ describe('Ensure that listeners registered on the same topic are invoked in the expect(arr).toEqual(['A', 'B', 'C']); }); }); + +// noConflict functionality +describe('noConflict static method', function () { + it('should roll back the global PubSub identifier and return the current constructor function', function () { + var EventEmitter = PubSub.noConflict(); + var emitter = new EventEmitter(); + + expect(PubSub).toBeUndefined(); + expect(emitter instanceof EventEmitter).toBe(true); + }); +});