Skip to content

Commit

Permalink
Improve jQuery module
Browse files Browse the repository at this point in the history
Added a better jQuery module.  Still half done though.

Added new documentation about the browser code.
  • Loading branch information
ssimpo committed Oct 5, 2017
1 parent a480fcb commit 4a77774
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 8 deletions.
38 changes: 36 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,40 @@ pubsub.broadcast('/', "My message to everyone!");

This module uses babel in build process to ensure it works on everything above node v4.0 (sorry, we cannot do less than that without rewriting dependencies). The lead developer spent most of his early programming career working on Lotus Notes Systems and building intranets for IE8! We therefore, understand the need for legacy suport and will endeavour to keep this module backwards compatible.

# Browser
# jQuery

The build code will also create a browser version of this module. The browser version is still in flux so check back for documentation later. If you need to use it now it can be found in the build folder after build.
The browser module will automatically export a new function to jQuery if present. To create a new PubSub instance, simply call the function on a dom query with unique name.

```javascript
jQuery("div.my-app").pubsub("my-app-topics");
```

Here a new PubSub instance is created called **my-app-topics**. This instance will be connected to all of the elements in the jQuery query. So, you can subscribe, publish and broadcast to the above:

```javascript
jQuery("div.my-app").pubsub("my-app-topics").subscribe("/my-channel", event=>{
// do something
});

jQuery("div.my-app").pubsub("my-app-topics").publish("/my-channel", "hello");

jQuery("div.my-app").pubsub("my-app-topics").broadcast("/", "Global message");
```

You can also subscribe, publish and broadcast to any PubSub instance attached to elements in a search by omitting the name.

```javascript
jQuery("div").pubsub().subscribe("/my-channel", event=>{
// subscribed to any pubsubs attached to "div"
});
```

**Note** The browser code is still in beta testing and subject to changes. It is not 100% unit tested yet and other features need adding. New features to add include unsubscribe functionality.

## Angular

There is an angular factory in the **TopSubscribe** module called *pubsub* that is automatically exported if angular is detected. This module is still in beta.

## Browser code

All the browser code is in beta but new features should be added if you watch this space. We wish to have an Angular 2/4 module and a global export too. Also, we want some way of selecting what is exported.
44 changes: 41 additions & 3 deletions lib/jquery.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,49 @@
//removeIf(node)
if (window.jQuery || window.$) {
const $ = window.jQuery || window.$;
const lookups = new WeakMap();
const pubsubs = new Map();
const names = new WeakMap();

$.pubsub = function(name, ...params) {
if (!pubsubs.has(name)) pubsubs.set(name, new PubSub(...params));
return pubsubs.get(name);
function weakMapAddSet(weakmap, ref, value) {
if (!weakmap.has(ref)) weakmap.set(ref, new Set());
if (value !== undefined) weakmap.get(ref).add(value);
return weakmap.get(ref);
}

$.fn.pubsub = function(name, ...params) {
if (name) {
if (!pubsubs.has(name)) pubsubs.set(name, new PubSub(...params));
weakMapAddSet(names, pubsubs.get(name), name);
this.each((n, item)=>weakMapAddSet(lookups, item, pubsubs.get(name)));
}

function getPubSubs(items) {
const pubsubs = new Set();
items.each((n, item)=>{
weakMapAddSet(lookups, item).forEach(pubsub=>{
if (!name || names.get(pubsub).has(name)) pubsubs.add(pubsub)
});
});
return pubsubs;
}

this.publish = (...params)=>{
getPubSubs(this).forEach(pubsub=>pubsub.publish(...params));
return this;
};

this.broadcast = (...params)=>{
getPubSubs(this).forEach(pubsub=>pubsub.broadcast(...params));
return this;
};

this.subscribe = (...params)=>{
getPubSubs(this).forEach(pubsub=>pubsub.subscribe(...params));
return this;
};

return this;
};
}
//endRemoveIf(node)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "topic-subscribe",
"description": "PubSub module with subscription filtering.",
"main": "index.js",
"version": "0.8.4",
"version": "0.9.0",
"scripts": {
"test": "./gulpfile.js test",
"build": "./gulpfile.js build",
Expand Down
43 changes: 41 additions & 2 deletions test/unit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function getPubSubInstance() {
try {
return new PubSub();
} catch (err) {
return $.pubsub(counter++);
return $("#mocha").pubsub(counter++);
}
}

Expand All @@ -52,9 +52,20 @@ function runner() {
describe(describeItem(jsDoc, 'PubSub#subscribe'), ()=>{
const topics = getPubSubInstance();

//removeIf(browser)
it('The subscribe method should return a function.', ()=>{
assert.isFunction(topics.subscribe('/my-test-channel', ()=>{}));
});
//endRemoveIf(browser)

//removeIf(node)
it('The subscribe method should return a jQuery-style object.', ()=>{
assert.instanceOf(topics.subscribe('/my-test-channel', ()=>{}), $);
assert.isFunction(topics.subscribe('/my-test-channel', ()=>{}).on);
assert.isFunction(topics.subscribe('/my-test-channel', ()=>{}).trigger);
assert.isFunction(topics.subscribe('/my-test-channel', ()=>{}).filter);
});
//endRemoveIf(node)

describe('Subscribe should throw if wrong types supplied', ()=>{
it('The subscribe method should throw if one or more channels not a string.', ()=>{
Expand All @@ -77,6 +88,7 @@ function runner() {
});
});

//removeIf(browser)
it('Subscribe should return a useable unsubscribe function.', ()=>{
const topics = getPubSubInstance();

Expand All @@ -89,6 +101,7 @@ function runner() {
topics.publish('/test', 'TEST MESSAGE');
assert.isFalse(called, 'Subscription not fired.');
});
//endRemoveIf(browser)

it('Subscribe should subscribe to multiple channels when given arrays.', ()=> {
const topics = getPubSubInstance();
Expand Down Expand Up @@ -144,9 +157,20 @@ function runner() {
describe(describeItem(jsDoc, 'PubSub#publish'), ()=>{
const topics = getPubSubInstance();

//removeIf(browser)
it('The publish method should return a boolean.', ()=>{
assert.isBoolean(topics.publish('/my-test-channel', {}));
});
//endRemoveIf(browser)

//removeIf(node)
it('The publish method should return a jQuery style object.', ()=>{
assert.instanceOf(topics.publish('/my-test-channel', {}), $);
assert.isFunction(topics.publish('/my-test-channel', {}).on);
assert.isFunction(topics.publish('/my-test-channel', {}).trigger);
assert.isFunction(topics.publish('/my-test-channel', {}).filter);
});
//removeIf(node)

describe('Publish should throw if wrong types supplied.', ()=>{
it('The publish method should throw if one or more channels not a string.', ()=>{
Expand Down Expand Up @@ -283,6 +307,7 @@ function runner() {
assert.equal(called, 2, 'Filter did not run correctly.');
});

//removeIf(browser)
it('Publish should return whether a callback was fired.', ()=>{
const topics = getPubSubInstance();

Expand All @@ -291,14 +316,26 @@ function runner() {
assert.isTrue(topics.publish('/test', 'TEST MESSAGE'));
assert.isFalse(topics.publish('/extra', 'TEST MESSAGE'));
});
//endRemoveIf(browser)
});

describe(describeItem(jsDoc, 'PubSub#broadcast'), ()=> {
const topics = getPubSubInstance();

//removeIf(browser)
it('The broadcast method should return a boolean.', ()=>{
assert.isBoolean(topics.publish('/test', {}));
assert.isBoolean(topics.broadcast('/test', {}));
});
//endRemoveIf(browser)

//removeIf(node)
it('The vroadcast method should return a jQuery-style object.', ()=>{
assert.instanceOf(topics.broadcast('/my-test-channel', ()=>{}), $);
assert.isFunction(topics.broadcast('/my-test-channel', {}).on);
assert.isFunction(topics.broadcast('/my-test-channel', {}).trigger);
assert.isFunction(topics.broadcast('/my-test-channel', {}).filter);
});
//endRemoveIf(node)

describe('Broadcast should throw if wrong types supplied.', ()=>{
it('The broadcast method should throw if one or more channels not a string.', ()=>{
Expand Down Expand Up @@ -343,6 +380,7 @@ function runner() {
assert.equal(called, 2);
});

//removeIf(browser)
it('Broadcast should return whether a callback was fired.', ()=>{
const topics = getPubSubInstance();

Expand All @@ -353,6 +391,7 @@ function runner() {
assert.isFalse(topics.broadcast('/extra', 'TEST MESSAGE'));
assert.isTrue(topics.broadcast('/', 'TEST MESSAGE'));
});
//endRemoveIf(browser)
});

it('Subscribed callbacks should fire when message broadcast on ancestor channel and filter matches.', ()=>{
Expand Down

0 comments on commit 4a77774

Please sign in to comment.