2009-11-18 02:38:49 +08:00
|
|
|
if (typeof(DeviceInfo) != 'object')
|
|
|
|
DeviceInfo = {};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This represents the PhoneGap API itself, and provides a global namespace for accessing
|
|
|
|
* information about the state of PhoneGap.
|
|
|
|
* @class
|
|
|
|
*/
|
|
|
|
PhoneGap = {
|
|
|
|
queue: {
|
|
|
|
ready: true,
|
|
|
|
commands: [],
|
|
|
|
timer: null
|
2010-07-23 04:05:41 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
2009-11-18 02:38:49 +08:00
|
|
|
};
|
|
|
|
|
2010-07-23 04:05:41 +08:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-11-18 02:38:49 +08:00
|
|
|
/**
|
|
|
|
* Boolean flag indicating if the PhoneGap API is available and initialized.
|
2009-12-04 09:07:07 +08:00
|
|
|
*/ // TODO: Remove this, it is unused here ... -jm
|
2009-11-18 02:38:49 +08:00
|
|
|
PhoneGap.available = DeviceInfo.uuid != undefined;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add an initialization function to a queue that ensures it will run and initialize
|
|
|
|
* application constructors only once PhoneGap has been initialized.
|
|
|
|
* @param {Function} func The function callback you want run once PhoneGap is initialized
|
|
|
|
*/
|
|
|
|
PhoneGap.addConstructor = function(func) {
|
2010-07-23 04:05:41 +08:00
|
|
|
PhoneGap.onDeviceReady.sob(function() {
|
2010-07-21 02:25:55 +08:00
|
|
|
try {
|
2010-07-23 04:05:41 +08:00
|
|
|
func();
|
2010-07-21 02:25:55 +08:00
|
|
|
} catch(e) {
|
|
|
|
if (typeof(debug['log']) == 'function') {
|
|
|
|
debug.log("Failed to run constructor: " + debug.processMessage(e));
|
|
|
|
} else {
|
|
|
|
alert("Failed to run constructor: " + e.message);
|
2009-11-18 02:38:49 +08:00
|
|
|
}
|
2010-07-21 02:25:55 +08:00
|
|
|
}
|
2010-07-23 04:05:41 +08:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
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();
|
2010-07-21 02:25:55 +08:00
|
|
|
});
|
2009-11-18 02:38:49 +08:00
|
|
|
|
2010-07-23 04:05:41 +08:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-11-18 02:38:49 +08:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
* recieve them.
|
|
|
|
* @param {String} command Command to be run in PhoneGap, e.g. "ClassName.method"
|
|
|
|
* @param {String[]} [args] Zero or more arguments to pass to the method
|
|
|
|
*/
|
|
|
|
PhoneGap.exec = function() {
|
|
|
|
PhoneGap.queue.commands.push(arguments);
|
|
|
|
if (PhoneGap.queue.timer == null)
|
|
|
|
PhoneGap.queue.timer = setInterval(PhoneGap.run_command, 10);
|
|
|
|
};
|
2009-12-04 09:07:07 +08:00
|
|
|
|
2009-11-18 02:38:49 +08:00
|
|
|
/**
|
2009-12-04 09:07:07 +08:00
|
|
|
* Internal function used to dispatch the request to PhoneGap. It processes the
|
|
|
|
* command queue and executes the next command on the list. If one of the
|
|
|
|
* arguments is a JavaScript object, it will be passed on the QueryString of the
|
|
|
|
* url, which will be turned into a dictionary on the other end.
|
2009-11-18 02:38:49 +08:00
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
PhoneGap.run_command = function() {
|
2009-12-04 09:07:07 +08:00
|
|
|
if (!PhoneGap.available || !PhoneGap.queue.ready)
|
|
|
|
return;
|
|
|
|
|
|
|
|
PhoneGap.queue.ready = false;
|
|
|
|
|
|
|
|
var args = PhoneGap.queue.commands.shift();
|
|
|
|
if (PhoneGap.queue.commands.length == 0) {
|
|
|
|
clearInterval(PhoneGap.queue.timer);
|
|
|
|
PhoneGap.queue.timer = null;
|
|
|
|
}
|
2009-11-18 02:38:49 +08:00
|
|
|
|
2009-12-04 09:07:07 +08:00
|
|
|
var uri = [];
|
|
|
|
var dict = null;
|
|
|
|
for (var i = 1; i < args.length; i++) {
|
|
|
|
var arg = args[i];
|
|
|
|
if (arg == undefined || arg == null)
|
|
|
|
arg = '';
|
|
|
|
if (typeof(arg) == 'object')
|
|
|
|
dict = arg;
|
|
|
|
else
|
|
|
|
uri.push(encodeURIComponent(arg));
|
|
|
|
}
|
|
|
|
var url = "gap://" + args[0] + "/" + uri.join("/");
|
|
|
|
if (dict != null) {
|
|
|
|
var query_args = [];
|
|
|
|
for (var name in dict) {
|
|
|
|
if (typeof(name) != 'string')
|
|
|
|
continue;
|
|
|
|
query_args.push(encodeURIComponent(name) + "=" + encodeURIComponent(dict[name]));
|
|
|
|
}
|
|
|
|
if (query_args.length > 0)
|
|
|
|
url += "?" + query_args.join("&");
|
|
|
|
}
|
|
|
|
document.location = url;
|
|
|
|
|
|
|
|
};
|
2010-08-19 02:12:53 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal function that uses XHR to call into PhoneGap Java code and retrieve
|
|
|
|
* any JavaScript code that needs to be run. This is used for callbacks from
|
|
|
|
* Java to JavaScript.
|
|
|
|
*/
|
|
|
|
PhoneGap.JSCallback = function() {
|
|
|
|
var xmlhttp = new XMLHttpRequest();
|
|
|
|
|
|
|
|
// Callback function when XMLHttpRequest is ready
|
|
|
|
xmlhttp.onreadystatechange=function(){
|
|
|
|
if(xmlhttp.readyState == 4){
|
|
|
|
|
|
|
|
// If callback has JavaScript statement to execute
|
|
|
|
if (xmlhttp.status == 200) {
|
|
|
|
|
|
|
|
var msg = xmlhttp.responseText;
|
|
|
|
setTimeout(function() {
|
|
|
|
try {
|
|
|
|
var t = eval(msg);
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
console.log("JSCallback Error: "+e);
|
|
|
|
}
|
|
|
|
}, 1);
|
|
|
|
setTimeout(PhoneGap.JSCallback, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If callback ping (used to keep XHR request from timing out)
|
|
|
|
else if (xmlhttp.status == 404) {
|
|
|
|
setTimeout(PhoneGap.JSCallback, 10);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If error, restart callback server
|
|
|
|
else {
|
|
|
|
console.log("JSCallback Error: Request failed.");
|
|
|
|
CallbackServer.restartServer();
|
|
|
|
setTimeout(PhoneGap.JSCallback, 100);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
xmlhttp.open("GET", "http://127.0.0.1:"+CallbackServer.getPort()+"/" , true);
|
|
|
|
xmlhttp.send();
|
2010-08-20 23:59:45 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a UUID
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
PhoneGap.createUUID = function() {
|
|
|
|
return PhoneGap.UUIDcreatePart(4) + '-' +
|
|
|
|
PhoneGap.UUIDcreatePart(2) + '-' +
|
|
|
|
PhoneGap.UUIDcreatePart(2) + '-' +
|
|
|
|
PhoneGap.UUIDcreatePart(2) + '-' +
|
|
|
|
PhoneGap.UUIDcreatePart(6);
|
|
|
|
};
|
|
|
|
|
|
|
|
PhoneGap.UUIDcreatePart = function(length) {
|
|
|
|
var uuidpart = "";
|
|
|
|
for (var i=0; i<length; i++) {
|
|
|
|
var uuidchar = parseInt((Math.random() * 256)).toString(16);
|
|
|
|
if (uuidchar.length == 1) {
|
|
|
|
uuidchar = "0" + uuidchar;
|
|
|
|
}
|
|
|
|
uuidpart += uuidchar;
|
|
|
|
}
|
|
|
|
return uuidpart;
|
|
|
|
};
|
|
|
|
|
2010-07-23 04:05:41 +08:00
|
|
|
PhoneGap.close = function(context, func, params) {
|
|
|
|
if (null == params) {
|
|
|
|
return function() {
|
|
|
|
return func.apply(context, arguments);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return function() {
|
|
|
|
return func.apply(context, params);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|