tweaks to PhoneGap.Channel

This commit is contained in:
Dave Johnson 2010-07-26 12:35:06 -07:00
parent 8e5de2cb7b
commit e0d1414c4a
3 changed files with 72 additions and 128 deletions

View File

@ -142,19 +142,9 @@ PhoneGap.Channel.merge(function() {
// Listen for DOMContentLoaded // Listen for DOMContentLoaded
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
PhoneGap.onDOMContentLoaded.fire(); PhoneGap.onDOMContentLoaded.fire();
}); }, false);
// Intercept calls to document.addEventListener and watch for deviceready
PhoneGap._document_addEventListener = document.addEventListener;
document.addEventListener = function(evt, handler, capture) {
if (evt.toLowerCase() == 'deviceready') {
PhoneGap.onDeviceReady.sob(handler);
} else {
PhoneGap._document_addEventListener.call(document, evt, handler);
}
};
@ -638,7 +628,17 @@ Device.prototype.exitApp = function()
PhoneGap.addConstructor(function() { PhoneGap.addConstructor(function() {
navigator.device = window.device = new Device(); navigator.device = window.device = new Device();
}); });// Intercept calls to document.addEventListener and watch for deviceready
PhoneGap._document_addEventListener = document.addEventListener;
document.addEventListener = function(evt, handler, capture) {
if (evt.toLowerCase() == 'deviceready') {
PhoneGap.onDeviceReady.sob(handler);
} else {
PhoneGap._document_addEventListener.call(document, evt, handler);
}
};
PhoneGap.addConstructor(function() { if (typeof navigator.fileMgr == "undefined") navigator.fileMgr = new FileMgr();}); PhoneGap.addConstructor(function() { if (typeof navigator.fileMgr == "undefined") navigator.fileMgr = new FileMgr();});

View File

@ -1,81 +0,0 @@
PhoneGap.Channel = function(type)
{
this.type = type;
this.handlers = {};
this.guid = 0;
this.fired = false;
this.enabled = true;
};
PhoneGap.Channel.prototype.sub = function(f, c, g)
{
// need a function to call
if (f == null)
return;
var func = f;
if (typeof c == "object" && f instanceof Function)
func = PhoneGap.close(c, f);
g = g || func.observer_guid || f.observer_guid || this.guid++;
func.observer_guid = g;
f.observer_guid = g;
this.handlers[g] = func;
return g;
};
PhoneGap.Channel.prototype.sob = function(f, c)
{
var g = null;
var _this = this;
var m = function() {
f.apply(c || null, arguments);
_this.dub(g);
}
if (this.fired) {
if (typeof c == "object" && f instanceof Function)
f = PhoneGap.close(c, f);
f.apply(this, this.fireArgs);
} else {
g = this.sub(m);
}
return g;
};
PhoneGap.Channel.prototype.dub = function(g)
{
if (g instanceof Function)
g = g.observer_guid;
this.handlers[g] = null;
delete this.handlers[g];
};
PhoneGap.Channel.prototype.fire = function(e)
{
if (this.enabled)
{
var fail = false;
for (var item in this.handlers) {
var handler = this.handlers[item];
if (handler instanceof Function) {
var rv = (handler.apply(this, arguments)==false);
fail = fail || rv;
}
}
this.fired = true;
this.fireArgs = arguments;
return !fail;
}
return true;
};
PhoneGap.Channel.merge = function(h, e) {
var i = e.length;
var f = function() {
if (!(--i)) h();
}
for (var j=0; j<i; j++) {
(!e[j].fired?e[j].sob(f):i--);
}
if (!i) h();
}

View File

@ -15,9 +15,9 @@ PhoneGap = {
}; };
/**
* Custom pub-sub channel that can have functions subscribed to it
*/
PhoneGap.Channel = function(type) PhoneGap.Channel = function(type)
{ {
this.type = type; this.type = type;
@ -27,15 +27,19 @@ PhoneGap.Channel = function(type)
this.enabled = true; this.enabled = true;
}; };
PhoneGap.Channel.prototype.sub = function(f, c, g) /**
{ * Subscribes the given function to the channel. Any time that
* Channel.fire is called so too will the function.
* Optionally specify an execution context for the function
* and a guid that can be used to stop subscribing to the channel.
* Returns the guid.
*/
PhoneGap.Channel.prototype.subscribe = function(f, c, g) {
// need a function to call // need a function to call
if (f == null) if (f == null) { return; }
return;
var func = f; var func = f;
if (typeof c == "object" && f instanceof Function) if (typeof c == "object" && f instanceof Function) { func = PhoneGap.close(c, f); }
func = PhoneGap.close(c, f);
g = g || func.observer_guid || f.observer_guid || this.guid++; g = g || func.observer_guid || f.observer_guid || this.guid++;
func.observer_guid = g; func.observer_guid = g;
@ -44,36 +48,40 @@ PhoneGap.Channel.prototype.sub = function(f, c, g)
return g; return g;
}; };
PhoneGap.Channel.prototype.sob = function(f, c) /**
{ * Like subscribe but the function is only called once and then it
* auto-unsubscribes itself.
*/
PhoneGap.Channel.prototype.subscribeOnce = function(f, c) {
var g = null; var g = null;
var _this = this; var _this = this;
var m = function() { var m = function() {
f.apply(c || null, arguments); f.apply(c || null, arguments);
_this.dub(g); _this.unsubscribe(g);
} }
if (this.fired) { if (this.fired) {
if (typeof c == "object" && f instanceof Function) if (typeof c == "object" && f instanceof Function) { f = PhoneGap.close(c, f); }
f = PhoneGap.close(c, f);
f.apply(this, this.fireArgs); f.apply(this, this.fireArgs);
} else { } else {
g = this.sub(m); g = this.subscribe(m);
} }
return g; return g;
}; };
PhoneGap.Channel.prototype.dub = function(g) /**
{ * Unsubscribes the function with the given guid from the channel.
if (g instanceof Function) */
g = g.observer_guid; PhoneGap.Channel.prototype.unsubscribe = function(g) {
if (g instanceof Function) { g = g.observer_guid; }
this.handlers[g] = null; this.handlers[g] = null;
delete this.handlers[g]; delete this.handlers[g];
}; };
PhoneGap.Channel.prototype.fire = function(e) /**
{ * Calls all functions subscribed to this channel.
if (this.enabled) */
{ PhoneGap.Channel.prototype.fire = function(e) {
if (this.enabled) {
var fail = false; var fail = false;
for (var item in this.handlers) { for (var item in this.handlers) {
var handler = this.handlers[item]; var handler = this.handlers[item];
@ -89,20 +97,22 @@ PhoneGap.Channel.prototype.fire = function(e)
return true; return true;
}; };
PhoneGap.Channel.merge = function(h, e) { /**
var i = e.length; * Calls the provided function only after all of the channels specified
* have been fired.
*/
PhoneGap.Channel.join = function(h, c) {
var i = c.length;
var f = function() { var f = function() {
if (!(--i)) h(); if (!(--i)) h();
} }
for (var j=0; j<i; j++) { for (var j=0; j<i; j++) {
(!e[j].fired?e[j].sob(f):i--); (!c[j].fired?c[j].subscribeOnce(f):i--);
} }
if (!i) h(); if (!i) h();
} }
/** /**
* Boolean flag indicating if the PhoneGap API is available and initialized. * Boolean flag indicating if the PhoneGap API is available and initialized.
*/ // TODO: Remove this, it is unused here ... -jm */ // TODO: Remove this, it is unused here ... -jm
@ -114,7 +124,7 @@ PhoneGap.available = DeviceInfo.uuid != undefined;
* @param {Function} func The function callback you want run once PhoneGap is initialized * @param {Function} func The function callback you want run once PhoneGap is initialized
*/ */
PhoneGap.addConstructor = function(func) { PhoneGap.addConstructor = function(func) {
PhoneGap.onDeviceReady.sob(function() { PhoneGap.onDeviceReady.subscribeOnce(function() {
try { try {
func(); func();
} catch(e) { } catch(e) {
@ -127,22 +137,38 @@ PhoneGap.addConstructor = function(func) {
}); });
}; };
/**
* onDOMContentLoaded channel is fired when the DOM content
* of the page has been parsed.
*/
PhoneGap.onDOMContentLoaded = new PhoneGap.Channel(); PhoneGap.onDOMContentLoaded = new PhoneGap.Channel();
/**
* onNativeReady channel is fired when the PhoneGap native code
* has been initialized.
*/
PhoneGap.onNativeReady = new PhoneGap.Channel(); PhoneGap.onNativeReady = new PhoneGap.Channel();
if (_nativeReady) PhoneGap.onNativeReady.fire(); // _nativeReady is global variable that the native side can set
// to signify that the native code is ready. It is a global since
// it may be called before any PhoneGap JS is ready.
if (_nativeReady) { PhoneGap.onNativeReady.fire(); }
/**
* onDeviceReady is fired only after both onDOMContentLoaded and
* onNativeReady have fired.
*/
PhoneGap.onDeviceReady = new PhoneGap.Channel(); PhoneGap.onDeviceReady = new PhoneGap.Channel();
PhoneGap.Channel.merge(function() { PhoneGap.Channel.join(function() {
PhoneGap.onDeviceReady.fire(); PhoneGap.onDeviceReady.fire();
}, [ PhoneGap.onDOMContentLoaded, PhoneGap.onNativeReady ]); }, [ PhoneGap.onDOMContentLoaded, PhoneGap.onNativeReady ]);
// Listen for DOMContentLoaded // Listen for DOMContentLoaded and notify our channel subscribers
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
PhoneGap.onDOMContentLoaded.fire(); PhoneGap.onDOMContentLoaded.fire();
}); }, false);
// Intercept calls to document.addEventListener and watch for deviceready // Intercept calls to document.addEventListener and watch for deviceready
@ -150,7 +176,7 @@ PhoneGap._document_addEventListener = document.addEventListener;
document.addEventListener = function(evt, handler, capture) { document.addEventListener = function(evt, handler, capture) {
if (evt.toLowerCase() == 'deviceready') { if (evt.toLowerCase() == 'deviceready') {
PhoneGap.onDeviceReady.sob(handler); PhoneGap.onDeviceReady.subscribeOnce(handler);
} else { } else {
PhoneGap._document_addEventListener.call(document, evt, handler); PhoneGap._document_addEventListener.call(document, evt, handler);
} }
@ -158,7 +184,6 @@ document.addEventListener = function(evt, handler, capture) {
/** /**
* Execute a PhoneGap command in a queued fashion, to ensure commands do not * Execute a PhoneGap command in a queued fashion, to ensure commands do not
* execute with any race conditions, and only run when PhoneGap is ready to * execute with any race conditions, and only run when PhoneGap is ready to