diff --git a/example/phonegap.js b/example/phonegap.js index 0d946c88..504eac87 100644 --- a/example/phonegap.js +++ b/example/phonegap.js @@ -11,10 +11,98 @@ PhoneGap = { ready: true, commands: [], timer: null - }, - _constructors: [] + } }; + + + + +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 0) { - var constructor = PhoneGap._constructors.shift(); + PhoneGap.onDeviceReady.sob(function() { try { - constructor(); + func(); } catch(e) { if (typeof(debug['log']) == 'function') { debug.log("Failed to run constructor: " + debug.processMessage(e)); @@ -50,13 +124,41 @@ document.addEventListener('DOMContentLoaded', function() { alert("Failed to run constructor: " + e.message); } } - } - // all constructors run, now fire the deviceready event - var e = document.createEvent('Events'); - e.initEvent('deviceready'); - document.dispatchEvent(e); + }); +}; + +PhoneGap.onDOMContentLoaded = new PhoneGap.Channel(); +PhoneGap.onNativeReady = new PhoneGap.Channel(); + +if (_nativeReady) PhoneGap.onNativeReady.fire(); + +PhoneGap.onDeviceReady = new PhoneGap.Channel(); + +PhoneGap.Channel.merge(function() { + PhoneGap.onDeviceReady.fire(); +}, [ PhoneGap.onDOMContentLoaded, PhoneGap.onNativeReady ]); + + +// Listen for DOMContentLoaded +document.addEventListener('DOMContentLoaded', function() { + PhoneGap.onDOMContentLoaded.fire(); }); + +// 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); + } +}; + + + + /** * 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 @@ -114,6 +216,18 @@ PhoneGap.run_command = function() { document.location = url; }; + +PhoneGap.close = function(context, func, params) { + if (null == params) { + return function() { + return func.apply(context, arguments); + } + } else { + return function() { + return func.apply(context, params); + } + } +} function Acceleration(x, y, z) { this.x = x; @@ -192,7 +306,7 @@ Accelerometer.prototype.gotCurrentAcceleration = function(key, x, y, z) Accelerometer.prototype.watchAcceleration = function(successCallback, errorCallback, options) { // TODO: add the interval id to a list so we can clear all watches var frequency = (options != undefined)? options.frequency : 10000; - var accel = Acceleration(0,0,0); + var accel = new Acceleration(0,0,0); accel.win = successCallback; accel.fail = errorCallback; accel.opts = options; @@ -256,87 +370,7 @@ Camera.prototype.fail = function(err) PhoneGap.addConstructor(function() { if (typeof navigator.camera == "undefined") navigator.camera = new Camera(); }); -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 0) { - var constructor = PhoneGap._constructors.shift(); + PhoneGap.onDeviceReady.sob(function() { try { - constructor(); + func(); } catch(e) { if (typeof(debug['log']) == 'function') { debug.log("Failed to run constructor: " + debug.processMessage(e)); @@ -50,9 +124,41 @@ document.addEventListener('DOMContentLoaded', function() { alert("Failed to run constructor: " + e.message); } } - } + }); +}; + +PhoneGap.onDOMContentLoaded = new PhoneGap.Channel(); +PhoneGap.onNativeReady = new PhoneGap.Channel(); + +if (_nativeReady) PhoneGap.onNativeReady.fire(); + +PhoneGap.onDeviceReady = new PhoneGap.Channel(); + +PhoneGap.Channel.merge(function() { + PhoneGap.onDeviceReady.fire(); +}, [ PhoneGap.onDOMContentLoaded, PhoneGap.onNativeReady ]); + + +// Listen for DOMContentLoaded +document.addEventListener('DOMContentLoaded', function() { + PhoneGap.onDOMContentLoaded.fire(); }); + +// 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); + } +}; + + + + /** * 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 @@ -181,3 +287,14 @@ PhoneGap.UUIDcreatePart = function(length) { return uuidpart; }; +PhoneGap.close = function(context, func, params) { + if (null == params) { + return function() { + return func.apply(context, arguments); + } + } else { + return function() { + return func.apply(context, params); + } + } +} \ No newline at end of file diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java index 4238cf4d..9ec794b4 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -132,6 +132,11 @@ public class DroidGap extends Activity { root.addView(appView); + // Try firing the onNativeReady event in JS. If it fails because the JS is + // not loaded yet then just set a flag so that the onNativeReady can be fired + // from the JS side when the JS gets to that code. + appView.loadUrl("javascript:try{PhoneGap.onNativeReady.fire();}catch(e){_nativeReady = true;}"); + setContentView(root); }