You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2012/09/18 17:17:43 UTC
js commit: Revert "Separate Channel into sticky and non-sticky
versions."
Updated Branches:
refs/heads/master 34239a8c1 -> d30179b30
Revert "Separate Channel into sticky and non-sticky versions."
Something is broken with this... Going to revert for now and try again
later.
This reverts commit aa15ac60d6cbabae83f619880a3a6e8be14817ce.
Project: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/commit/d30179b3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/tree/d30179b3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/diff/d30179b3
Branch: refs/heads/master
Commit: d30179b30152b9383a80637e609cf2d785e1aa3e
Parents: 34239a8
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Sep 18 11:16:25 2012 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Sep 18 11:16:25 2012 -0400
----------------------------------------------------------------------
lib/bada/plugin/bada/device.js | 2 +-
lib/common/channel.js | 166 +++++++++--------
lib/common/plugin/device.js | 2 +-
lib/common/plugin/network.js | 2 +-
lib/cordova.js | 13 +-
lib/scripts/bootstrap.js | 2 +-
lib/tizen/plugin/tizen/Device.js | 2 +-
test/test.channel.js | 327 ++++++++++++++-------------------
8 files changed, 238 insertions(+), 278 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/d30179b3/lib/bada/plugin/bada/device.js
----------------------------------------------------------------------
diff --git a/lib/bada/plugin/bada/device.js b/lib/bada/plugin/bada/device.js
index b1da422..3d34166 100644
--- a/lib/bada/plugin/bada/device.js
+++ b/lib/bada/plugin/bada/device.js
@@ -34,7 +34,7 @@ function Device() {
var me = this;
- channel.onCordovaReady.subscribe(function() {
+ channel.onCordovaReady.subscribeOnce(function() {
me.getDeviceInfo(function (device) {
me.platform = device.platform;
me.version = device.version;
http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/d30179b3/lib/common/channel.js
----------------------------------------------------------------------
diff --git a/lib/common/channel.js b/lib/common/channel.js
index 1ad7227..21f0e6e 100644
--- a/lib/common/channel.js
+++ b/lib/common/channel.js
@@ -25,22 +25,19 @@ var utils = require('cordova/utils'),
/**
* Custom pub-sub "channel" that can have functions subscribed to it
* This object is used to define and control firing of events for
- * cordova initialization, as well as for custom events thereafter.
+ * cordova initialization.
*
* The order of events during page load and Cordova startup is as follows:
*
- * onDOMContentLoaded* Internal event that is received when the web page is loaded and parsed.
- * onNativeReady* Internal event that indicates the Cordova native side is ready.
- * onCordovaReady* Internal event fired when all Cordova JavaScript objects have been created.
- * onCordovaInfoReady* Internal event fired when device properties are available.
- * onCordovaConnectionReady* Internal event fired when the connection property has been set.
- * onDeviceReady* User event fired to indicate that Cordova is ready
- * onResume User event fired to indicate a start/resume lifecycle event
- * onPause User event fired to indicate a pause lifecycle event
- * onDestroy* Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
- *
- * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
- * All listeners that subscribe after the event is fired will be executed right away.
+ * onDOMContentLoaded Internal event that is received when the web page is loaded and parsed.
+ * onNativeReady Internal event that indicates the Cordova native side is ready.
+ * onCordovaReady Internal event fired when all Cordova JavaScript objects have been created.
+ * onCordovaInfoReady Internal event fired when device properties are available.
+ * onCordovaConnectionReady Internal event fired when the connection property has been set.
+ * onDeviceReady User event fired to indicate that Cordova is ready
+ * onResume User event fired to indicate a start/resume lifecycle event
+ * onPause User event fired to indicate a pause lifecycle event
+ * onDestroy Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
*
* The only Cordova events that user code should register for are:
* deviceready Cordova native code is initialized and Cordova APIs can be called from JavaScript
@@ -63,16 +60,12 @@ var utils = require('cordova/utils'),
* @constructor
* @param type String the channel name
*/
-var Channel = function(type, sticky) {
+var Channel = function(type) {
this.type = type;
- // Map of guid -> function.
this.handlers = {};
- // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
- this.state = sticky ? 1 : 0;
- // Used in sticky mode to remember args passed to fire().
- this.fireArgs = null;
- // Used by onHasSubscribersChange to know if there are any listeners.
this.numHandlers = 0;
+ this.fired = false;
+ this.enabled = true;
// Function that is called when the first listener is subscribed, or when
// the last listener is unsubscribed.
this.onHasSubscribersChange = null;
@@ -80,27 +73,22 @@ var Channel = function(type, sticky) {
channel = {
/**
* Calls the provided function only after all of the channels specified
- * have been fired. All channels must be sticky channels.
+ * have been fired.
*/
- join: function(h, c) {
- var len = c.length,
- i = len,
- f = function() {
- if (!(--i)) h();
- };
+ join: function (h, c) {
+ var i = c.length;
+ var len = i;
+ var f = function() {
+ if (!(--i)) h();
+ };
for (var j=0; j<len; j++) {
- if (c[j].state == 0) {
- throw Error('Can only use join with sticky channels.')
- }
- c[j].subscribe(f);
+ !c[j].fired?c[j].subscribeOnce(f):i--;
}
- if (!len) h();
- },
- create: function(type) {
- return channel[type] = new Channel(type, false);
+ if (!i) h();
},
- createSticky: function(type) {
- return channel[type] = new Channel(type, true);
+ create: function (type, opts) {
+ channel[type] = new Channel(type, opts);
+ return channel[type];
},
/**
@@ -118,7 +106,13 @@ var Channel = function(type, sticky) {
*/
waitForInitialization: function(feature) {
if (feature) {
- var c = channel[feature] || this.createSticky(feature);
+ var c = null;
+ if (this[feature]) {
+ c = this[feature];
+ }
+ else {
+ c = this.create(feature);
+ }
this.deviceReadyChannelsMap[feature] = c;
this.deviceReadyChannelsArray.push(c);
}
@@ -138,7 +132,7 @@ var Channel = function(type, sticky) {
};
function forceFunction(f) {
- if (typeof f != 'function') throw "Function required as first argument!";
+ if (f === null || f === undefined || typeof f != 'function') throw "Function required as first argument!";
}
/**
@@ -148,46 +142,67 @@ function forceFunction(f) {
* and a guid that can be used to stop subscribing to the channel.
* Returns the guid.
*/
-Channel.prototype.subscribe = function(f, c) {
+Channel.prototype.subscribe = function(f, c, g) {
// need a function to call
forceFunction(f);
- if (this.state == 2) {
- f.apply(c || this, this.fireArgs);
- return;
- }
- var func = f,
- guid = f.observer_guid;
+ var func = f;
if (typeof c == "object") { func = utils.close(c, f); }
- if (!guid) {
+ g = g || func.observer_guid || f.observer_guid;
+ if (!g) {
// first time any channel has seen this subscriber
- guid = '' + nextGuid++;
+ g = nextGuid++;
}
- func.observer_guid = guid;
- f.observer_guid = guid;
+ func.observer_guid = g;
+ f.observer_guid = g;
// Don't add the same handler more than once.
- if (!this.handlers[guid]) {
- this.handlers[guid] = func;
+ if (!this.handlers[g]) {
+ this.handlers[g] = func;
this.numHandlers++;
if (this.numHandlers == 1) {
this.onHasSubscribersChange && this.onHasSubscribersChange();
}
+ if (this.fired) func.apply(this, this.fireArgs);
}
+ return g;
+};
+
+/**
+ * Like subscribe but the function is only called once and then it
+ * auto-unsubscribes itself.
+ */
+Channel.prototype.subscribeOnce = function(f, c) {
+ // need a function to call
+ forceFunction(f);
+
+ var g = null;
+ var _this = this;
+ if (this.fired) {
+ f.apply(c || null, this.fireArgs);
+ } else {
+ g = this.subscribe(function() {
+ _this.unsubscribe(g);
+ f.apply(c || null, arguments);
+ });
+ f.observer_guid = g;
+ }
+ return g;
};
/**
* Unsubscribes the function with the given guid from the channel.
*/
-Channel.prototype.unsubscribe = function(f) {
+Channel.prototype.unsubscribe = function(g) {
// need a function to unsubscribe
- forceFunction(f);
+ if (g === null || g === undefined) { throw "You must pass _something_ into Channel.unsubscribe"; }
- var guid = f.observer_guid,
- handler = this.handlers[guid];
+ if (typeof g == 'function') { g = g.observer_guid; }
+ var handler = this.handlers[g];
if (handler) {
- delete this.handlers[guid];
+ if (handler.observer_guid) handler.observer_guid=null;
+ delete this.handlers[g];
this.numHandlers--;
if (this.numHandlers == 0) {
this.onHasSubscribersChange && this.onHasSubscribersChange();
@@ -199,14 +214,10 @@ Channel.prototype.unsubscribe = function(f) {
* Calls all functions subscribed to this channel.
*/
Channel.prototype.fire = function(e) {
- var fail = false,
- fireArgs = Array.prototype.slice.call(arguments);
- // Apply stickiness.
- if (this.state == 1) {
- this.state = 2;
- this.fireArgs = fireArgs;
- }
- if (this.numHandlers) {
+ if (this.enabled) {
+ var fail = false;
+ this.fired = true;
+ this.fireArgs = arguments;
// Copy the values first so that it is safe to modify it from within
// callbacks.
var toCall = [];
@@ -214,36 +225,33 @@ Channel.prototype.fire = function(e) {
toCall.push(this.handlers[item]);
}
for (var i = 0; i < toCall.length; ++i) {
- toCall[i].apply(this, fireArgs);
- }
- if (this.state == 2 && this.numHandlers) {
- this.numHandlers = 0;
- this.handlers = {};
- this.onHasSubscribersChange && this.onHasSubscribersChange();
+ var rv = (toCall[i].apply(this, arguments)===false);
+ fail = fail || rv;
}
+ return !fail;
}
+ return true;
};
-
// defining them here so they are ready super fast!
// DOM event that is received when the web page is loaded and parsed.
-channel.createSticky('onDOMContentLoaded');
+channel.create('onDOMContentLoaded');
// Event to indicate the Cordova native side is ready.
-channel.createSticky('onNativeReady');
+channel.create('onNativeReady');
// Event to indicate that all Cordova JavaScript objects have been created
// and it's time to run plugin constructors.
-channel.createSticky('onCordovaReady');
+channel.create('onCordovaReady');
// Event to indicate that device properties are available
-channel.createSticky('onCordovaInfoReady');
+channel.create('onCordovaInfoReady');
// Event to indicate that the connection property has been set.
-channel.createSticky('onCordovaConnectionReady');
+channel.create('onCordovaConnectionReady');
// Event to indicate that Cordova is ready
-channel.createSticky('onDeviceReady');
+channel.create('onDeviceReady');
// Event to indicate a resume lifecycle event
channel.create('onResume');
@@ -252,7 +260,7 @@ channel.create('onResume');
channel.create('onPause');
// Event to indicate a destroy lifecycle event
-channel.createSticky('onDestroy');
+channel.create('onDestroy');
// Channels that must fire before "deviceready" is fired.
channel.waitForInitialization('onCordovaReady');
http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/d30179b3/lib/common/plugin/device.js
----------------------------------------------------------------------
diff --git a/lib/common/plugin/device.js b/lib/common/plugin/device.js
index 905bfe1..3477ff8 100644
--- a/lib/common/plugin/device.js
+++ b/lib/common/plugin/device.js
@@ -41,7 +41,7 @@ function Device() {
var me = this;
- channel.onCordovaReady.subscribe(function() {
+ channel.onCordovaReady.subscribeOnce(function() {
me.getInfo(function(info) {
me.available = true;
me.platform = info.platform;
http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/d30179b3/lib/common/plugin/network.js
----------------------------------------------------------------------
diff --git a/lib/common/plugin/network.js b/lib/common/plugin/network.js
index adaba5a..637ea89 100644
--- a/lib/common/plugin/network.js
+++ b/lib/common/plugin/network.js
@@ -41,7 +41,7 @@ var NetworkConnection = function () {
var me = this;
- channel.onCordovaReady.subscribe(function() {
+ channel.onCordovaReady.subscribeOnce(function() {
me.getInfo(function (info) {
me.type = info;
if (info === "none") {
http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/d30179b3/lib/cordova.js
----------------------------------------------------------------------
diff --git a/lib/cordova.js b/lib/cordova.js
index fc4a744..e1650fa 100644
--- a/lib/cordova.js
+++ b/lib/cordova.js
@@ -50,7 +50,11 @@ var documentEventHandlers = {},
document.addEventListener = function(evt, handler, capture) {
var e = evt.toLowerCase();
if (typeof documentEventHandlers[e] != 'undefined') {
- documentEventHandlers[e].subscribe(handler);
+ if (evt === 'deviceready') {
+ documentEventHandlers[e].subscribeOnce(handler);
+ } else {
+ documentEventHandlers[e].subscribe(handler);
+ }
} else {
m_document_addEventListener.call(document, evt, handler, capture);
}
@@ -113,9 +117,6 @@ var cordova = {
addWindowEventHandler:function(event) {
return (windowEventHandlers[event] = channel.create(event));
},
- addStickyDocumentEventHandler:function(event) {
- return (documentEventHandlers[event] = channel.createSticky(event));
- },
addDocumentEventHandler:function(event) {
return (documentEventHandlers[event] = channel.create(event));
},
@@ -233,7 +234,7 @@ var cordova = {
}
},
addConstructor: function(func) {
- channel.onCordovaReady.subscribe(function() {
+ channel.onCordovaReady.subscribeOnce(function() {
try {
func();
} catch(e) {
@@ -246,6 +247,6 @@ var cordova = {
// Register pause, resume and deviceready channels as events on document.
channel.onPause = cordova.addDocumentEventHandler('pause');
channel.onResume = cordova.addDocumentEventHandler('resume');
-channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
+channel.onDeviceReady = cordova.addDocumentEventHandler('deviceready');
module.exports = cordova;
http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/d30179b3/lib/scripts/bootstrap.js
----------------------------------------------------------------------
diff --git a/lib/scripts/bootstrap.js b/lib/scripts/bootstrap.js
index 6aa08af..2bf8075 100644
--- a/lib/scripts/bootstrap.js
+++ b/lib/scripts/bootstrap.js
@@ -69,7 +69,7 @@
};
// boot up once native side is ready
- channel.onNativeReady.subscribe(_self.boot);
+ channel.onNativeReady.subscribeOnce(_self.boot);
// _nativeReady is global variable that the native side can set
// to signify that the native code is ready. It is a global since
http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/d30179b3/lib/tizen/plugin/tizen/Device.js
----------------------------------------------------------------------
diff --git a/lib/tizen/plugin/tizen/Device.js b/lib/tizen/plugin/tizen/Device.js
index c5532fb..908f05d 100644
--- a/lib/tizen/plugin/tizen/Device.js
+++ b/lib/tizen/plugin/tizen/Device.js
@@ -45,7 +45,7 @@ function Device() {
console.log("error initializing cordova: " + error);
}
- channel.onCordovaReady.subscribe(function() {
+ channel.onCordovaReady.subscribeOnce(function() {
me.getDeviceInfo(onSuccessCallback, onErrorCallback);
});
}
http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/d30179b3/test/test.channel.js
----------------------------------------------------------------------
diff --git a/test/test.channel.js b/test/test.channel.js
index cd14d38..e71f993 100644
--- a/test/test.channel.js
+++ b/test/test.channel.js
@@ -21,315 +21,266 @@
describe("channel", function () {
var channel = require('cordova/channel'),
- multiChannel,
- stickyChannel;
-
- function callCount(spy) {
- return spy.argsForCall.length;
- }
- function expectCallCount(spy, count) {
- expect(callCount(spy)).toEqual(count);
- }
+ c;
+
beforeEach(function() {
- multiChannel = channel.create('multiChannel');
- stickyChannel = channel.createSticky('stickyChannel');
+ c = channel.create('masterexploder');
});
describe("subscribe method", function() {
it("should throw an exception if no function is provided", function() {
expect(function() {
- multiChannel.subscribe();
+ c.subscribe();
}).toThrow();
expect(function() {
- multiChannel.subscribe(null);
+ c.subscribe(null);
}).toThrow();
expect(function() {
- multiChannel.subscribe(undefined);
+ c.subscribe(undefined);
}).toThrow();
expect(function() {
- multiChannel.subscribe({apply:function(){},call:function(){}});
+ c.subscribe({apply:function(){},call:function(){}});
}).toThrow();
});
it("should not change number of handlers if no function is provided", function() {
- var initialLength = multiChannel.numHandlers;
+ var initialLength = c.numHandlers;
try {
- multiChannel.subscribe();
+ c.subscribe();
} catch(e) {}
- expect(multiChannel.numHandlers).toEqual(initialLength);
+ expect(c.numHandlers).toEqual(initialLength);
try {
- multiChannel.subscribe(null);
+ c.subscribe(null);
} catch(e) {}
- expect(multiChannel.numHandlers).toEqual(initialLength);
+ expect(c.numHandlers).toEqual(initialLength);
});
it("should not change number of handlers when subscribing same function multiple times", function() {
+ var initialLength = c.numHandlers;
+ var handler = function(){};
+
+ c.subscribe(handler);
+ c.subscribe(handler);
+ c.subscribe(handler);
+
+ expect(c.numHandlers).toEqual(initialLength+1);
+ });
+ it("should be able to use the same function with multiple channels.", function() {
+ var c2 = channel.create('jables');
var handler = function(){};
- multiChannel.subscribe(handler);
- multiChannel.subscribe(handler);
- stickyChannel.subscribe(handler);
- stickyChannel.subscribe(handler);
+ c.subscribe(handler);
+ c2.subscribe(handler);
- expect(multiChannel.numHandlers).toEqual(1);
- expect(stickyChannel.numHandlers).toEqual(1);
+ expect(c.numHandlers).toEqual(1);
+ expect(c2.numHandlers).toEqual(1);
});
});
describe("unsubscribe method", function() {
it("should throw an exception if passed in null or undefined", function() {
expect(function() {
- multiChannel.unsubscribe();
+ c.unsubscribe();
}).toThrow();
expect(function() {
- multiChannel.unsubscribe(null);
+ c.unsubscribe(null);
}).toThrow();
});
it("should not decrement numHandlers if unsubscribing something that does not exist", function() {
- multiChannel.subscribe(function() {});
- multiChannel.unsubscribe(function() {});
- expect(multiChannel.numHandlers).toEqual(1);
+ var initialLength = c.numHandlers;
+ c.unsubscribe('blah');
+ expect(c.numHandlers).toEqual(initialLength);
+ c.unsubscribe(2);
+ expect(c.numHandlers).toEqual(initialLength);
+ c.unsubscribe({balls:false});
+ expect(c.numHandlers).toEqual(initialLength);
});
it("should change the handlers length appropriately", function() {
var firstHandler = function() {};
var secondHandler = function() {};
var thirdHandler = function() {};
- multiChannel.subscribe(firstHandler);
- multiChannel.subscribe(secondHandler);
- multiChannel.subscribe(thirdHandler);
- expect(multiChannel.numHandlers).toEqual(3);
+ c.subscribe(firstHandler);
+ c.subscribe(secondHandler);
+ c.subscribe(thirdHandler);
+
+ var initialLength = c.numHandlers;
- multiChannel.unsubscribe(thirdHandler);
- expect(multiChannel.numHandlers).toEqual(2);
+ c.unsubscribe(thirdHandler);
- multiChannel.unsubscribe(firstHandler);
- multiChannel.unsubscribe(secondHandler);
+ expect(c.numHandlers).toEqual(initialLength - 1);
- expect(multiChannel.numHandlers).toEqual(0);
+ c.unsubscribe(firstHandler);
+ c.unsubscribe(secondHandler);
+
+ expect(c.numHandlers).toEqual(0);
});
it("should not decrement handlers length more than once if unsubing a single handler", function() {
var firstHandler = function(){};
- multiChannel.subscribe(firstHandler);
+ c.subscribe(firstHandler);
- expect(multiChannel.numHandlers).toEqual(1);
+ expect(c.numHandlers).toEqual(1);
- multiChannel.unsubscribe(firstHandler);
- multiChannel.unsubscribe(firstHandler);
- multiChannel.unsubscribe(firstHandler);
- multiChannel.unsubscribe(firstHandler);
+ c.unsubscribe(firstHandler);
+ c.unsubscribe(firstHandler);
+ c.unsubscribe(firstHandler);
+ c.unsubscribe(firstHandler);
- expect(multiChannel.numHandlers).toEqual(0);
+ expect(c.numHandlers).toEqual(0);
});
it("should not unregister a function registered with a different handler", function() {
var cHandler = function(){};
var c2Handler = function(){};
var c2 = channel.create('jables');
- multiChannel.subscribe(cHandler);
+ c.subscribe(cHandler);
c2.subscribe(c2Handler);
- expect(multiChannel.numHandlers).toEqual(1);
+ expect(c.numHandlers).toEqual(1);
expect(c2.numHandlers).toEqual(1);
- multiChannel.unsubscribe(c2Handler);
+ c.unsubscribe(c2Handler);
c2.unsubscribe(cHandler);
- expect(multiChannel.numHandlers).toEqual(1);
+ expect(c.numHandlers).toEqual(1);
expect(c2.numHandlers).toEqual(1);
});
+ it("should be able to unsubscribe a subscribeOnce.", function() {
+ var handler = function(){};
+ c.subscribeOnce(handler);
+
+ expect(c.numHandlers).toEqual(1);
+
+ c.unsubscribe(handler);
+
+ expect(c.numHandlers).toEqual(0);
+ });
});
- function commonFireTests(multi) {
+ describe("fire method", function() {
it("should fire all subscribed handlers", function() {
- var testChannel = multi ? multiChannel : stickyChannel;
var handler = jasmine.createSpy();
var anotherOne = jasmine.createSpy();
- testChannel.subscribe(handler);
- testChannel.subscribe(anotherOne);
-
- testChannel.fire();
+ c.subscribe(handler);
+ c.subscribe(anotherOne);
- expectCallCount(handler, 1);
- expectCallCount(anotherOne, 1);
- });
- it("should pass params to handlers", function() {
- var testChannel = multi ? multiChannel : stickyChannel;
- var handler = jasmine.createSpy();
-
- testChannel.subscribe(handler);
+ c.fire();
- testChannel.fire(1, 2, 3);
- expect(handler.argsForCall[0]).toEqual({0:1, 1:2, 2:3});
+ expect(handler).toHaveBeenCalled();
+ expect(anotherOne).toHaveBeenCalled();
});
it("should not fire a handler that was unsubscribed", function() {
- var testChannel = multi ? multiChannel : stickyChannel;
var handler = jasmine.createSpy();
var anotherOne = jasmine.createSpy();
- testChannel.subscribe(handler);
- testChannel.subscribe(anotherOne);
- testChannel.unsubscribe(handler);
+ c.subscribe(handler);
+ c.subscribe(anotherOne);
+ c.unsubscribe(handler);
- testChannel.fire();
+ c.fire();
- expectCallCount(handler, 0);
- expectCallCount(anotherOne, 1);
+ expect(handler).not.toHaveBeenCalled();
+ expect(anotherOne).toHaveBeenCalled();
});
it("should not fire a handler more than once if it was subscribed more than once", function() {
- var testChannel = multi ? multiChannel : stickyChannel;
- var handler = jasmine.createSpy();
+ var count = 0;
+ var handler = jasmine.createSpy().andCallFake(function() { count++; });
- testChannel.subscribe(handler);
- testChannel.subscribe(handler);
- testChannel.subscribe(handler);
+ c.subscribe(handler);
+ c.subscribe(handler);
+ c.subscribe(handler);
- testChannel.fire();
+ c.fire();
- expectCallCount(handler, 1);
+ expect(handler).toHaveBeenCalled();
+ expect(count).toEqual(1);
});
it("handler should be called when subscribed, removed, and subscribed again", function() {
- var testChannel = multi ? multiChannel : stickyChannel;
- var handler = jasmine.createSpy();
+ var count = 0;
+ var handler = jasmine.createSpy().andCallFake(function() { count++; });
- testChannel.subscribe(handler);
- testChannel.unsubscribe(handler);
- testChannel.subscribe(handler);
+ c.subscribe(handler);
+ c.unsubscribe(handler);
+ c.subscribe(handler);
- testChannel.fire();
+ c.fire();
+
+ expect(handler).toHaveBeenCalled();
+ expect(count).toEqual(1);
- expectCallCount(handler, 1);
- });
- it("should not prevent a callback from firing when it is removed during firing.", function() {
- var testChannel = multi ? multiChannel : stickyChannel;
- var handler = jasmine.createSpy().andCallFake(function() { testChannel.unsubscribe(handler2); });
- var handler2 = jasmine.createSpy();
- testChannel.subscribe(handler);
- testChannel.subscribe(handler2);
- testChannel.fire();
- expectCallCount(handler, 1);
- expectCallCount(handler2, 1);
});
- }
- describe("fire method for sticky channels", function() {
- commonFireTests(false);
it("should instantly trigger the callback if the event has already been fired", function () {
- var before = jasmine.createSpy('before'),
+ var chan = channel.create("foo"),
+ before = jasmine.createSpy('before'),
after = jasmine.createSpy('after');
- stickyChannel.subscribe(before);
- stickyChannel.fire(1, 2, 3);
- stickyChannel.subscribe(after);
+ chan.subscribe(before);
+ chan.fire();
+ chan.subscribe(after);
- expectCallCount(before, 1);
- expectCallCount(after, 1);
- expect(after.argsForCall[0]).toEqual({0:1, 1:2, 2:3});
+ expect(before).toHaveBeenCalled();
+ expect(after).toHaveBeenCalled();
});
it("should instantly trigger the callback if the event is currently being fired.", function () {
- var handler1 = jasmine.createSpy().andCallFake(function() { stickyChannel.subscribe(handler2); }),
+ var handler1 = jasmine.createSpy().andCallFake(function() { c.subscribe(handler2); }),
handler2 = jasmine.createSpy().andCallFake(function(arg1) { expect(arg1).toEqual('foo');});
- stickyChannel.subscribe(handler1);
- stickyChannel.fire('foo');
+ c.subscribe(handler1);
+ c.fire('foo');
- expectCallCount(handler2, 1);
- });
- it("should unregister all handlers after being fired.", function() {
- var handler = jasmine.createSpy();
- stickyChannel.subscribe(handler);
- stickyChannel.fire();
- stickyChannel.fire();
- expectCallCount(handler, 1);
+ expect(handler2).toHaveBeenCalled();
});
});
- describe("fire method for multi channels", function() {
- commonFireTests(true);
- it("should not trigger the callback if the event has already been fired", function () {
- var before = jasmine.createSpy('before'),
- after = jasmine.createSpy('after');
-
- multiChannel.subscribe(before);
- multiChannel.fire();
- multiChannel.subscribe(after);
-
- expectCallCount(before, 1);
- expectCallCount(after, 0);
+ describe("subscribeOnce method", function() {
+ it("should be unregistered after being fired.", function() {
+ var count = 0;
+ var handler = jasmine.createSpy().andCallFake(function() { count++; });
+ c.subscribeOnce(handler);
+ c.fire();
+ c.fire();
+ expect(count).toEqual(1);
});
- it("should not trigger the callback if the event is currently being fired.", function () {
- var handler1 = jasmine.createSpy().andCallFake(function() { multiChannel.subscribe(handler2); }),
- handler2 = jasmine.createSpy();
-
- multiChannel.subscribe(handler1);
- multiChannel.fire();
- multiChannel.fire();
-
- expectCallCount(handler1, 2);
- expectCallCount(handler2, 1);
+ it("should be safe to add listeners from within callback.", function() {
+ var count = 0;
+ var handler = jasmine.createSpy().andCallFake(function() { count++; c.subscribeOnce(handler2); });
+ var handler2 = jasmine.createSpy().andCallFake(function() { count++; });
+ c.subscribeOnce(handler);
+ c.fire();
+ expect(count).toEqual(2);
});
- it("should not unregister handlers after being fired.", function() {
- var handler = jasmine.createSpy();
- multiChannel.subscribe(handler);
- multiChannel.fire();
- multiChannel.fire();
- expectCallCount(handler, 2);
- });
- });
- describe("channel.join()", function() {
- it("should be called when all functions start unfired", function() {
- var handler = jasmine.createSpy(),
- stickyChannel2 = channel.createSticky('stickyChannel');
- channel.join(handler, [stickyChannel, stickyChannel2]);
- expectCallCount(handler, 0);
- stickyChannel.fire();
- expectCallCount(handler, 0);
- stickyChannel2.fire();
- expectCallCount(handler, 1);
- });
- it("should be called when one functions start fired", function() {
- var handler = jasmine.createSpy(),
- stickyChannel2 = channel.createSticky('stickyChannel');
- stickyChannel.fire();
- channel.join(handler, [stickyChannel, stickyChannel2]);
- expectCallCount(handler, 0);
- stickyChannel2.fire();
- expectCallCount(handler, 1);
- });
- it("should be called when all functions start fired", function() {
- var handler = jasmine.createSpy(),
- stickyChannel2 = channel.createSticky('stickyChannel');
- stickyChannel.fire();
- stickyChannel2.fire();
- channel.join(handler, [stickyChannel, stickyChannel2]);
- expectCallCount(handler, 1);
- });
- it("should throw if a channel is not sticky", function() {
- expect(function() {
- channel.join(function(){}, [stickyChannel, multiChannel]);
- }).toThrow();
+ it("should not prevent a callback from firing when it is removed during firing.", function() {
+ var count = 0;
+ var handler = jasmine.createSpy().andCallFake(function() { count++; c.unsubscribe(handler2); });
+ var handler2 = jasmine.createSpy().andCallFake(function() { count++; });
+ c.subscribeOnce(handler);
+ c.subscribeOnce(handler2);
+ c.fire();
+ expect(count).toEqual(2);
});
});
describe("onHasSubscribersChange", function() {
it("should be called only when the first subscriber is added and last subscriber is removed.", function() {
var handler = jasmine.createSpy().andCallFake(function() {
- if (callCount(handler) == 1) {
+ var callCount = handler.argsForCall.length;
+ if (callCount == 1) {
expect(this.numHandlers).toEqual(1);
} else {
expect(this.numHandlers).toEqual(0);
}
});
- multiChannel.onHasSubscribersChange = handler;
+ c.onHasSubscribersChange = handler;
function foo1() {}
function foo2() {}
- multiChannel.subscribe(foo1);
- multiChannel.subscribe(foo2);
- multiChannel.unsubscribe(foo1);
- multiChannel.unsubscribe(foo2);
- expectCallCount(handler, 2);
+ c.subscribe(foo1);
+ c.subscribe(foo2);
+ c.unsubscribe(foo1);
+ c.unsubscribe(foo2);
+ expect(handler.argsForCall.length).toEqual(2);
});
});
});