diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/.DS_Store differ
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d9f7e49
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+Copyright 2011 Andrew M. Trice. All rights reserved, except where otherwise noted.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice, this list of
+ conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ of conditions and the following disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY ANDREW M. TRICE ''AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANDREW M. TRICE OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/README b/README
new file mode 100644
index 0000000..c8edae5
--- /dev/null
+++ b/README
@@ -0,0 +1,20 @@
+app-UI
+--------------------------------------
+app-UI is a collection of user interface components that may be helpful to web and mobile developers for creating interactive applications using HTML and JavaScript, especially those targeting mobile devices.
+
+app-UI has three application containers:
+
+*ViewNavigator*
+
+*SplitViewNavigator*
+
+*SlidingView*
+
+
+Dependencies:
+The required dependencies are contained within this code repository, with links to the original files/sources. Dependencies include:
+
+jQuery - http://jquery.com/
+jQuery Animate Enhanced - https://github.com/benbarnett/jQuery-Animate-Enhanced
+iScroll 4 - http://cubiq.org/iscroll-4
+NoClickDelay - http://cubiq.org/remove-onclick-delay-on-webkit-for-iphone
\ No newline at end of file
diff --git a/samples/.DS_Store b/samples/.DS_Store
new file mode 100644
index 0000000..5db6513
Binary files /dev/null and b/samples/.DS_Store differ
diff --git a/samples/browser history/.DS_Store b/samples/browser history/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/samples/browser history/.DS_Store differ
diff --git a/samples/browser history/assets/.DS_Store b/samples/browser history/assets/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/samples/browser history/assets/.DS_Store differ
diff --git a/samples/browser history/assets/header_bg_wood.png b/samples/browser history/assets/header_bg_wood.png
new file mode 100644
index 0000000..62854e3
Binary files /dev/null and b/samples/browser history/assets/header_bg_wood.png differ
diff --git a/samples/browser history/index.html b/samples/browser history/index.html
new file mode 100644
index 0000000..564218d
--- /dev/null
+++ b/samples/browser history/index.html
@@ -0,0 +1,208 @@
+
+
+
+ TV Listings
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/browser history/libs/.DS_Store b/samples/browser history/libs/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/samples/browser history/libs/.DS_Store differ
diff --git a/samples/browser history/libs/jquery.address-1.4.js b/samples/browser history/libs/jquery.address-1.4.js
new file mode 100644
index 0000000..12a9abe
--- /dev/null
+++ b/samples/browser history/libs/jquery.address-1.4.js
@@ -0,0 +1,655 @@
+/*
+ * jQuery Address Plugin v1.4
+ * http://www.asual.com/jquery/address/
+ *
+ * Copyright (c) 2009-2010 Rostislav Hristov
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Date: 2011-05-04 14:22:12 +0300 (Wed, 04 May 2011)
+ */
+(function ($) {
+
+ $.address = (function () {
+
+ var _trigger = function(name) {
+ $($.address).trigger(
+ $.extend($.Event(name),
+ (function() {
+ var parameters = {},
+ parameterNames = $.address.parameterNames();
+ for (var i = 0, l = parameterNames.length; i < l; i++) {
+ parameters[parameterNames[i]] = $.address.parameter(parameterNames[i]);
+ }
+ return {
+ value: $.address.value(),
+ path: $.address.path(),
+ pathNames: $.address.pathNames(),
+ parameterNames: parameterNames,
+ parameters: parameters,
+ queryString: $.address.queryString()
+ };
+ }).call($.address)
+ )
+ );
+ },
+ _bind = function(value, data, fn) {
+ $().bind.apply($($.address), Array.prototype.slice.call(arguments));
+ return $.address;
+ },
+ _supportsState = function() {
+ return (_h.pushState && _opts.state !== UNDEFINED);
+ },
+ _hrefState = function() {
+ return ('/' + _l.pathname.replace(new RegExp(_opts.state), '') +
+ _l.search + (_hrefHash() ? '#' + _hrefHash() : '')).replace(_re, '/');
+ },
+ _hrefHash = function() {
+ var index = _l.href.indexOf('#');
+ return index != -1 ? _crawl(_l.href.substr(index + 1), FALSE) : '';
+ },
+ _href = function() {
+ return _supportsState() ? _hrefState() : _hrefHash();
+ },
+ _window = function() {
+ try {
+ return top.document !== UNDEFINED ? top : window;
+ } catch (e) {
+ return window;
+ }
+ },
+ _js = function() {
+ return 'javascript';
+ },
+ _strict = function(value) {
+ value = value.toString();
+ return (_opts.strict && value.substr(0, 1) != '/' ? '/' : '') + value;
+ },
+ _crawl = function(value, direction) {
+ if (_opts.crawlable && direction) {
+ return (value !== '' ? '!' : '') + value;
+ }
+ return value.replace(/^\!/, '');
+ },
+ _cssint = function(el, value) {
+ return parseInt(el.css(value), 10);
+ },
+ _search = function(el) {
+ var url, s;
+ for (var i = 0, l = el.childNodes.length; i < l; i++) {
+ try {
+ if ('src' in el.childNodes[i] && el.childNodes[i].src) {
+ url = String(el.childNodes[i].src);
+ }
+ } catch (e) {
+ // IE Invalid pointer problem with base64 encoded images
+ }
+ s = _search(el.childNodes[i]);
+ if (s) {
+ url = s;
+ }
+ }
+ return url;
+ },
+ _listen = function() {
+ if (!_silent) {
+ var hash = _href(),
+ diff = _value != hash;
+ if (diff) {
+ if (_msie && _version < 7) {
+ _l.reload();
+ } else {
+ if (_msie && _version < 8 && _opts.history) {
+ _st(_html, 50);
+ }
+ _value = hash;
+ _update(FALSE);
+ }
+ }
+ }
+ },
+ _update = function(internal) {
+ _trigger(CHANGE);
+ _trigger(internal ? INTERNAL_CHANGE : EXTERNAL_CHANGE);
+ _st(_track, 10);
+ },
+ _track = function() {
+ if (_opts.tracker !== 'null' && _opts.tracker !== null) {
+ var fn = $.isFunction(_opts.tracker) ? _opts.tracker : _t[_opts.tracker],
+ value = (_l.pathname + _l.search +
+ ($.address && !_supportsState() ? $.address.value() : ''))
+ .replace(/\/\//, '/').replace(/^\/$/, '');
+ if ($.isFunction(fn)) {
+ fn(value);
+ } else if ($.isFunction(_t.urchinTracker)) {
+ _t.urchinTracker(value);
+ } else if (_t.pageTracker !== UNDEFINED && $.isFunction(_t.pageTracker._trackPageview)) {
+ _t.pageTracker._trackPageview(value);
+ } else if (_t._gaq !== UNDEFINED && $.isFunction(_t._gaq.push)) {
+ _t._gaq.push(['_trackPageview', decodeURI(value)]);
+ }
+ }
+ },
+ _html = function() {
+ var src = _js() + ':' + FALSE + ';document.open();document.writeln(\'' +
+ _d.title.replace('\'', '\\\'') + '
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/multi-device form factor/www/phonegap-1.4.1.js b/samples/multi-device form factor/www/phonegap-1.4.1.js
new file mode 100644
index 0000000..680e180
--- /dev/null
+++ b/samples/multi-device form factor/www/phonegap-1.4.1.js
@@ -0,0 +1,4123 @@
+/* PhoneGap v1.4.1 */
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+
+/*
+ * Some base contributions
+ * Copyright (c) 2011, Proyectos Equis Ka, S.L.
+ */
+
+if (typeof PhoneGap === "undefined") {
+
+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 = {
+ // This queue holds the currently executing command and all pending
+ // commands executed with PhoneGap.exec().
+ commandQueue: [],
+ // Indicates if we're currently in the middle of flushing the command
+ // queue on the native side.
+ commandQueueFlushing: false,
+ _constructors: [],
+ documentEventHandler: {}, // Collection of custom document event handlers
+ windowEventHandler: {}
+};
+
+/**
+ * List of resource files loaded by PhoneGap.
+ * This is used to ensure JS and other files are loaded only once.
+ */
+PhoneGap.resources = {base: true};
+
+/**
+ * Determine if resource has been loaded by PhoneGap
+ *
+ * @param name
+ * @return
+ */
+PhoneGap.hasResource = function(name) {
+ return PhoneGap.resources[name];
+};
+
+/**
+ * Add a resource to list of loaded resources by PhoneGap
+ *
+ * @param name
+ */
+PhoneGap.addResource = function(name) {
+ PhoneGap.resources[name] = true;
+};
+
+/**
+ * Boolean flag indicating if the PhoneGap API is available and initialized.
+ */ // TODO: Remove this, it is unused here ... -jm
+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) {
+ var state = document.readyState;
+ if ( ( state == 'loaded' || state == 'complete' ) && DeviceInfo.uuid != null )
+ {
+ func();
+ }
+ else
+ {
+ PhoneGap._constructors.push(func);
+ }
+};
+
+(function()
+ {
+ var timer = setInterval(function()
+ {
+
+ var state = document.readyState;
+
+ if ( ( state == 'loaded' || state == 'complete' ) && DeviceInfo.uuid != null )
+ {
+ clearInterval(timer); // stop looking
+ // run our constructors list
+ while (PhoneGap._constructors.length > 0)
+ {
+ var constructor = PhoneGap._constructors.shift();
+ try
+ {
+ constructor();
+ }
+ catch(e)
+ {
+ if (typeof(console['log']) == 'function')
+ {
+ console.log("Failed to run constructor: " + console.processMessage(e));
+ }
+ else
+ {
+ 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);
+ }
+ }, 1);
+})();
+
+// session id for calls
+PhoneGap.sessionKey = 0;
+
+// centralized callbacks
+PhoneGap.callbackId = 0;
+PhoneGap.callbacks = {};
+PhoneGap.callbackStatus = {
+ NO_RESULT: 0,
+ OK: 1,
+ CLASS_NOT_FOUND_EXCEPTION: 2,
+ ILLEGAL_ACCESS_EXCEPTION: 3,
+ INSTANTIATION_EXCEPTION: 4,
+ MALFORMED_URL_EXCEPTION: 5,
+ IO_EXCEPTION: 6,
+ INVALID_ACTION: 7,
+ JSON_EXCEPTION: 8,
+ ERROR: 9
+ };
+
+/**
+ * Creates a gap bridge iframe used to notify the native code about queued
+ * commands.
+ *
+ * @private
+ */
+PhoneGap.createGapBridge = function() {
+ gapBridge = document.createElement("iframe");
+ gapBridge.setAttribute("style", "display:none;");
+ gapBridge.setAttribute("height","0px");
+ gapBridge.setAttribute("width","0px");
+ gapBridge.setAttribute("frameborder","0");
+ document.documentElement.appendChild(gapBridge);
+ return gapBridge;
+}
+
+/**
+ * Execute a PhoneGap command by queuing it and letting the native side know
+ * there are queued commands. The native side will then request all of the
+ * queued commands and execute them.
+ *
+ * Arguments may be in one of two formats:
+ *
+ * FORMAT ONE (preferable)
+ * The native side will call PhoneGap.callbackSuccess or
+ * PhoneGap.callbackError, depending upon the result of the action.
+ *
+ * @param {Function} success The success callback
+ * @param {Function} fail The fail callback
+ * @param {String} service The name of the service to use
+ * @param {String} action The name of the action to use
+ * @param {String[]} [args] Zero or more arguments to pass to the method
+ *
+ * FORMAT TWO
+ * @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
+ * object parameters are passed as an array object
+ * [object1, object2] each object will be passed as
+ * JSON strings
+ */
+PhoneGap.exec = function() {
+ if (!PhoneGap.available) {
+ alert("ERROR: Attempting to call PhoneGap.exec()"
+ +" before 'deviceready'. Ignoring.");
+ return;
+ }
+
+ var successCallback, failCallback, service, action, actionArgs;
+ var callbackId = null;
+ if (typeof arguments[0] !== "string") {
+ // FORMAT ONE
+ successCallback = arguments[0];
+ failCallback = arguments[1];
+ service = arguments[2];
+ action = arguments[3];
+ actionArgs = arguments[4];
+
+ // Since we need to maintain backwards compatibility, we have to pass
+ // an invalid callbackId even if no callback was provided since plugins
+ // will be expecting it. The PhoneGap.exec() implementation allocates
+ // an invalid callbackId and passes it even if no callbacks were given.
+ callbackId = 'INVALID';
+ } else {
+ // FORMAT TWO
+ splitCommand = arguments[0].split(".");
+ action = splitCommand.pop();
+ service = splitCommand.join(".");
+ actionArgs = Array.prototype.splice.call(arguments, 1);
+ }
+
+ // Start building the command object.
+ var command = {
+ className: service,
+ methodName: action,
+ arguments: []
+ };
+
+ // Register the callbacks and add the callbackId to the positional
+ // arguments if given.
+ if (successCallback || failCallback) {
+ callbackId = service + PhoneGap.callbackId++;
+ PhoneGap.callbacks[callbackId] =
+ {success:successCallback, fail:failCallback};
+ }
+ if (callbackId != null) {
+ command.arguments.push(callbackId);
+ }
+
+ for (var i = 0; i < actionArgs.length; ++i) {
+ var arg = actionArgs[i];
+ if (arg == undefined || arg == null) {
+ continue;
+ } else if (typeof(arg) == 'object') {
+ command.options = arg;
+ } else {
+ command.arguments.push(arg);
+ }
+ }
+
+ // Stringify and queue the command. We stringify to command now to
+ // effectively clone the command arguments in case they are mutated before
+ // the command is executed.
+ PhoneGap.commandQueue.push(JSON.stringify(command));
+
+ // If the queue length is 1, then that means it was empty before we queued
+ // the given command, so let the native side know that we have some
+ // commands to execute, unless the queue is currently being flushed, in
+ // which case the command will be picked up without notification.
+ if (PhoneGap.commandQueue.length == 1 && !PhoneGap.commandQueueFlushing) {
+ if (!PhoneGap.gapBridge) {
+ PhoneGap.gapBridge = PhoneGap.createGapBridge();
+ }
+
+ PhoneGap.gapBridge.src = "gap://ready";
+ }
+}
+
+/**
+ * Called by native code to retrieve all queued commands and clear the queue.
+ */
+PhoneGap.getAndClearQueuedCommands = function() {
+ json = JSON.stringify(PhoneGap.commandQueue);
+ PhoneGap.commandQueue = [];
+ return json;
+}
+
+/**
+ * Called by native code when returning successful result from an action.
+ *
+ * @param callbackId
+ * @param args
+ * args.status - PhoneGap.callbackStatus
+ * args.message - return value
+ * args.keepCallback - 0 to remove callback, 1 to keep callback in PhoneGap.callbacks[]
+ */
+PhoneGap.callbackSuccess = function(callbackId, args) {
+ if (PhoneGap.callbacks[callbackId]) {
+
+ // If result is to be sent to callback
+ if (args.status == PhoneGap.callbackStatus.OK) {
+ try {
+ if (PhoneGap.callbacks[callbackId].success) {
+ PhoneGap.callbacks[callbackId].success(args.message);
+ }
+ }
+ catch (e) {
+ console.log("Error in success callback: "+callbackId+" = "+e);
+ }
+ }
+
+ // Clear callback if not expecting any more results
+ if (!args.keepCallback) {
+ delete PhoneGap.callbacks[callbackId];
+ }
+ }
+};
+
+/**
+ * Called by native code when returning error result from an action.
+ *
+ * @param callbackId
+ * @param args
+ */
+PhoneGap.callbackError = function(callbackId, args) {
+ if (PhoneGap.callbacks[callbackId]) {
+ try {
+ if (PhoneGap.callbacks[callbackId].fail) {
+ PhoneGap.callbacks[callbackId].fail(args.message);
+ }
+ }
+ catch (e) {
+ console.log("Error in error callback: "+callbackId+" = "+e);
+ }
+
+ // Clear callback if not expecting any more results
+ if (!args.keepCallback) {
+ delete PhoneGap.callbacks[callbackId];
+ }
+ }
+};
+
+
+/**
+ * Does a deep clone of the object.
+ *
+ * @param obj
+ * @return
+ */
+PhoneGap.clone = function(obj) {
+ if(!obj) {
+ return obj;
+ }
+
+ if(obj instanceof Array){
+ var retVal = new Array();
+ for(var i = 0; i < obj.length; ++i){
+ retVal.push(PhoneGap.clone(obj[i]));
+ }
+ return retVal;
+ }
+
+ if (obj instanceof Function) {
+ return obj;
+ }
+
+ if(!(obj instanceof Object)){
+ return obj;
+ }
+
+ if (obj instanceof Date) {
+ return obj;
+ }
+
+ retVal = new Object();
+ for(i in obj){
+ if(!(i in retVal) || retVal[i] != obj[i]) {
+ retVal[i] = PhoneGap.clone(obj[i]);
+ }
+ }
+ return retVal;
+};
+
+// Intercept calls to document.addEventListener
+PhoneGap.m_document_addEventListener = document.addEventListener;
+
+// Intercept calls to window.addEventListener
+PhoneGap.m_window_addEventListener = window.addEventListener;
+
+/**
+ * Add a custom window event handler.
+ *
+ * @param {String} event The event name that callback handles
+ * @param {Function} callback The event handler
+ */
+PhoneGap.addWindowEventHandler = function(event, callback) {
+ PhoneGap.windowEventHandler[event] = callback;
+}
+
+/**
+ * Add a custom document event handler.
+ *
+ * @param {String} event The event name that callback handles
+ * @param {Function} callback The event handler
+ */
+PhoneGap.addDocumentEventHandler = function(event, callback) {
+ PhoneGap.documentEventHandler[event] = callback;
+}
+
+/**
+ * Intercept adding document event listeners and handle our own
+ *
+ * @param {Object} evt
+ * @param {Function} handler
+ * @param capture
+ */
+document.addEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+
+ // If subscribing to an event that is handled by a plugin
+ if (typeof PhoneGap.documentEventHandler[e] !== "undefined") {
+ if (PhoneGap.documentEventHandler[e](e, handler, true)) {
+ return; // Stop default behavior
+ }
+ }
+
+ PhoneGap.m_document_addEventListener.call(document, evt, handler, capture);
+};
+
+/**
+ * Intercept adding window event listeners and handle our own
+ *
+ * @param {Object} evt
+ * @param {Function} handler
+ * @param capture
+ */
+window.addEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+
+ // If subscribing to an event that is handled by a plugin
+ if (typeof PhoneGap.windowEventHandler[e] !== "undefined") {
+ if (PhoneGap.windowEventHandler[e](e, handler, true)) {
+ return; // Stop default behavior
+ }
+ }
+
+ PhoneGap.m_window_addEventListener.call(window, evt, handler, capture);
+};
+
+// Intercept calls to document.removeEventListener and watch for events that
+// are generated by PhoneGap native code
+PhoneGap.m_document_removeEventListener = document.removeEventListener;
+
+// Intercept calls to window.removeEventListener
+PhoneGap.m_window_removeEventListener = window.removeEventListener;
+
+/**
+ * Intercept removing document event listeners and handle our own
+ *
+ * @param {Object} evt
+ * @param {Function} handler
+ * @param capture
+ */
+document.removeEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+
+ // If unsubcribing from an event that is handled by a plugin
+ if (typeof PhoneGap.documentEventHandler[e] !== "undefined") {
+ if (PhoneGap.documentEventHandler[e](e, handler, false)) {
+ return; // Stop default behavior
+ }
+ }
+
+ PhoneGap.m_document_removeEventListener.call(document, evt, handler, capture);
+};
+
+/**
+ * Intercept removing window event listeners and handle our own
+ *
+ * @param {Object} evt
+ * @param {Function} handler
+ * @param capture
+ */
+window.removeEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+
+ // If unsubcribing from an event that is handled by a plugin
+ if (typeof PhoneGap.windowEventHandler[e] !== "undefined") {
+ if (PhoneGap.windowEventHandler[e](e, handler, false)) {
+ return; // Stop default behavior
+ }
+ }
+
+ PhoneGap.m_window_removeEventListener.call(window, evt, handler, capture);
+};
+
+/**
+ * Method to fire document event
+ *
+ * @param {String} type The event type to fire
+ * @param {Object} data Data to send with event
+ */
+PhoneGap.fireDocumentEvent = function(type, data) {
+ var e = document.createEvent('Events');
+ e.initEvent(type);
+ if (data) {
+ for (var i in data) {
+ e[i] = data[i];
+ }
+ }
+ document.dispatchEvent(e);
+};
+
+/**
+ * Method to fire window event
+ *
+ * @param {String} type The event type to fire
+ * @param {Object} data Data to send with event
+ */
+PhoneGap.fireWindowEvent = function(type, data) {
+ var e = document.createEvent('Events');
+ e.initEvent(type);
+ if (data) {
+ for (var i in data) {
+ e[i] = data[i];
+ }
+ }
+ window.dispatchEvent(e);
+};
+
+/**
+ * Method to fire event from native code
+ * Leaving this generic version to handle problems with iOS 3.x. Is currently used by orientation and battery events
+ * Remove when iOS 3.x no longer supported and call fireWindowEvent or fireDocumentEvent directly
+ */
+PhoneGap.fireEvent = function(type, target, data) {
+ var e = document.createEvent('Events');
+ e.initEvent(type);
+ if (data) {
+ for (var i in data) {
+ e[i] = data[i];
+ }
+ }
+ target = target || document;
+ if (target.dispatchEvent === undefined) { // ie window.dispatchEvent is undefined in iOS 3.x
+ target = document;
+ }
+
+ target.dispatchEvent(e);
+};
+/**
+ * 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 -1) {
+ me._batteryListener.splice(pos, 1);
+ }
+ } else if (eventType === "batterylow") {
+ var pos = me._lowListener.indexOf(handler);
+ if (pos > -1) {
+ me._lowListener.splice(pos, 1);
+ }
+ } else if (eventType === "batterycritical") {
+ var pos = me._criticalListener.indexOf(handler);
+ if (pos > -1) {
+ me._criticalListener.splice(pos, 1);
+ }
+ }
+
+ // If there are no more registered event listeners stop the battery listener on native side.
+ if (me._batteryListener.length === 0 && me._lowListener.length === 0 && me._criticalListener.length === 0) {
+ PhoneGap.exec(null, null, "com.phonegap.battery", "stop", []);
+ }
+ }
+};
+
+/**
+ * Callback for battery status
+ *
+ * @param {Object} info keys: level, isPlugged
+ */
+Battery.prototype._status = function(info) {
+ if (info) {
+ var me = this;
+ if (me._level != info.level || me._isPlugged != info.isPlugged) {
+ // Fire batterystatus event
+ //PhoneGap.fireWindowEvent("batterystatus", info);
+ // use this workaround since iOS 3.x does have window.dispatchEvent
+ PhoneGap.fireEvent("batterystatus", window, info);
+
+ // Fire low battery event
+ if (info.level == 20 || info.level == 5) {
+ if (info.level == 20) {
+ //PhoneGap.fireWindowEvent("batterylow", info);
+ // use this workaround since iOS 3.x does not have window.dispatchEvent
+ PhoneGap.fireEvent("batterylow", window, info);
+ }
+ else {
+ //PhoneGap.fireWindowEvent("batterycritical", info);
+ // use this workaround since iOS 3.x does not have window.dispatchEvent
+ PhoneGap.fireEvent("batterycritical", window, info);
+ }
+ }
+ }
+ me._level = info.level;
+ me._isPlugged = info.isPlugged;
+ }
+};
+
+/**
+ * Error callback for battery start
+ */
+Battery.prototype._error = function(e) {
+ console.log("Error initializing Battery: " + e);
+};
+
+PhoneGap.addConstructor(function() {
+ if (typeof navigator.battery === "undefined") {
+ navigator.battery = new Battery();
+ PhoneGap.addWindowEventHandler("batterystatus", navigator.battery.eventHandler);
+ PhoneGap.addWindowEventHandler("batterylow", navigator.battery.eventHandler);
+ PhoneGap.addWindowEventHandler("batterycritical", navigator.battery.eventHandler);
+ }
+});
+}if (!PhoneGap.hasResource("camera")) {
+ PhoneGap.addResource("camera");
+
+
+/**
+ * This class provides access to the device camera.
+ * @constructor
+ */
+Camera = function() {
+
+}
+/**
+ * Available Camera Options
+ * {boolean} allowEdit - true to allow editing image, default = false
+ * {number} quality 0-100 (low to high) default = 100
+ * {Camera.DestinationType} destinationType default = DATA_URL
+ * {Camera.PictureSourceType} sourceType default = CAMERA
+ * {number} targetWidth - width in pixels to scale image default = 0 (no scaling)
+ * {number} targetHeight - height in pixels to scale image default = 0 (no scaling)
+ * {Camera.EncodingType} - encodingType default = JPEG
+ * {boolean} correctOrientation - Rotate the image to correct for the orientation of the device during capture (iOS only)
+ * {boolean} saveToPhotoAlbum - Save the image to the photo album on the device after capture (iOS only)
+ */
+/**
+ * Format of image that is returned from getPicture.
+ *
+ * Example: navigator.camera.getPicture(success, fail,
+ * { quality: 80,
+ * destinationType: Camera.DestinationType.DATA_URL,
+ * sourceType: Camera.PictureSourceType.PHOTOLIBRARY})
+ */
+Camera.DestinationType = {
+ DATA_URL: 0, // Return base64 encoded string
+ FILE_URI: 1 // Return file uri
+};
+Camera.prototype.DestinationType = Camera.DestinationType;
+
+/**
+ * Source to getPicture from.
+ *
+ * Example: navigator.camera.getPicture(success, fail,
+ * { quality: 80,
+ * destinationType: Camera.DestinationType.DATA_URL,
+ * sourceType: Camera.PictureSourceType.PHOTOLIBRARY})
+ */
+Camera.PictureSourceType = {
+ PHOTOLIBRARY : 0, // Choose image from picture library
+ CAMERA : 1, // Take picture from camera
+ SAVEDPHOTOALBUM : 2 // Choose image from picture library
+};
+Camera.prototype.PictureSourceType = Camera.PictureSourceType;
+
+/**
+ * Encoding of image returned from getPicture.
+ *
+ * Example: navigator.camera.getPicture(success, fail,
+ * { quality: 80,
+ * destinationType: Camera.DestinationType.DATA_URL,
+ * sourceType: Camera.PictureSourceType.CAMERA,
+ * encodingType: Camera.EncodingType.PNG})
+ */
+Camera.EncodingType = {
+ JPEG: 0, // Return JPEG encoded image
+ PNG: 1 // Return PNG encoded image
+};
+Camera.prototype.EncodingType = Camera.EncodingType;
+
+/**
+ * Type of pictures to select from. Only applicable when
+ * PictureSourceType is PHOTOLIBRARY or SAVEDPHOTOALBUM
+ *
+ * Example: navigator.camera.getPicture(success, fail,
+ * { quality: 80,
+ * destinationType: Camera.DestinationType.DATA_URL,
+ * sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
+ * mediaType: Camera.MediaType.PICTURE})
+ */
+Camera.MediaType = {
+ PICTURE: 0, // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
+ VIDEO: 1, // allow selection of video only, ONLY RETURNS URL
+ ALLMEDIA : 2 // allow selection from all media types
+};
+Camera.prototype.MediaType = Camera.MediaType;
+
+/**
+ * Gets a picture from source defined by "options.sourceType", and returns the
+ * image as defined by the "options.destinationType" option.
+
+ * The defaults are sourceType=CAMERA and destinationType=DATA_URL.
+ *
+ * @param {Function} successCallback
+ * @param {Function} errorCallback
+ * @param {Object} options
+ */
+Camera.prototype.getPicture = function(successCallback, errorCallback, options) {
+ // successCallback required
+ if (typeof successCallback != "function") {
+ console.log("Camera Error: successCallback is not a function");
+ return;
+ }
+
+ // errorCallback optional
+ if (errorCallback && (typeof errorCallback != "function")) {
+ console.log("Camera Error: errorCallback is not a function");
+ return;
+ }
+
+ PhoneGap.exec(successCallback, errorCallback, "com.phonegap.camera","getPicture",[options]);
+};
+
+
+
+PhoneGap.addConstructor(function() {
+ if (typeof navigator.camera == "undefined") navigator.camera = new Camera();
+});
+};
+
+if (!PhoneGap.hasResource("device")) {
+ PhoneGap.addResource("device");
+
+/**
+ * this represents the mobile device, and provides properties for inspecting the model, version, UUID of the
+ * phone, etc.
+ * @constructor
+ */
+Device = function()
+{
+ this.platform = null;
+ this.version = null;
+ this.name = null;
+ this.phonegap = null;
+ this.uuid = null;
+ try
+ {
+ this.platform = DeviceInfo.platform;
+ this.version = DeviceInfo.version;
+ this.name = DeviceInfo.name;
+ this.phonegap = DeviceInfo.gap;
+ this.uuid = DeviceInfo.uuid;
+
+ }
+ catch(e)
+ {
+ // TODO:
+ }
+ this.available = PhoneGap.available = this.uuid != null;
+}
+
+PhoneGap.addConstructor(function() {
+ if (typeof navigator.device === "undefined") {
+ navigator.device = window.device = new Device();
+ }
+});
+};
+if (!PhoneGap.hasResource("capture")) {
+ PhoneGap.addResource("capture");
+/**
+ * The CaptureError interface encapsulates all errors in the Capture API.
+ */
+function CaptureError() {
+ this.code = null;
+};
+
+// Capture error codes
+CaptureError.CAPTURE_INTERNAL_ERR = 0;
+CaptureError.CAPTURE_APPLICATION_BUSY = 1;
+CaptureError.CAPTURE_INVALID_ARGUMENT = 2;
+CaptureError.CAPTURE_NO_MEDIA_FILES = 3;
+CaptureError.CAPTURE_NOT_SUPPORTED = 20;
+
+/**
+ * The Capture interface exposes an interface to the camera and microphone of the hosting device.
+ */
+function Capture() {
+ this.supportedAudioModes = [];
+ this.supportedImageModes = [];
+ this.supportedVideoModes = [];
+};
+
+/**
+ * Launch audio recorder application for recording audio clip(s).
+ *
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ * @param {CaptureAudioOptions} options
+ *
+ * No audio recorder to launch for iOS - return CAPTURE_NOT_SUPPORTED
+ */
+Capture.prototype.captureAudio = function(successCallback, errorCallback, options) {
+ /*if (errorCallback && typeof errorCallback === "function") {
+ errorCallback({
+ "code": CaptureError.CAPTURE_NOT_SUPPORTED
+ });
+ }*/
+ PhoneGap.exec(successCallback, errorCallback, "com.phonegap.mediacapture", "captureAudio", [options]);
+};
+
+/**
+ * Launch camera application for taking image(s).
+ *
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ * @param {CaptureImageOptions} options
+ */
+Capture.prototype.captureImage = function(successCallback, errorCallback, options) {
+ PhoneGap.exec(successCallback, errorCallback, "com.phonegap.mediacapture", "captureImage", [options]);
+};
+
+/**
+ * Casts a PluginResult message property (array of objects) to an array of MediaFile objects
+ * (used in Objective-C)
+ *
+ * @param {PluginResult} pluginResult
+ */
+Capture.prototype._castMediaFile = function(pluginResult) {
+ var mediaFiles = [];
+ var i;
+ for (i=0; i} categories
+* @param {ContactField[]} urls contact's web sites
+*/
+var Contact = function(id, displayName, name, nickname, phoneNumbers, emails, addresses,
+ ims, organizations, birthday, note, photos, categories, urls) {
+ this.id = id || null;
+ this.displayName = displayName || null;
+ this.name = name || null; // ContactName
+ this.nickname = nickname || null;
+ this.phoneNumbers = phoneNumbers || null; // ContactField[]
+ this.emails = emails || null; // ContactField[]
+ this.addresses = addresses || null; // ContactAddress[]
+ this.ims = ims || null; // ContactField[]
+ this.organizations = organizations || null; // ContactOrganization[]
+ this.birthday = birthday || null; // JS Date
+ this.note = note || null;
+ this.photos = photos || null; // ContactField[]
+ this.categories = categories || null;
+ this.urls = urls || null; // ContactField[]
+};
+
+/**
+* Converts Dates to milliseconds before sending to iOS
+*/
+Contact.prototype.convertDatesOut = function()
+{
+ var dates = new Array("birthday");
+ for (var i=0; i][;base64],
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsDataURL = function(file) {
+ this.fileName = "";
+
+ if (typeof file.fullPath === "undefined") {
+ this.fileName = file;
+ } else {
+ this.fileName = file.fullPath;
+ }
+
+ // LOADING state
+ this.readyState = FileReader.LOADING;
+
+ // If loadstart callback
+ if (typeof this.onloadstart === "function") {
+ var evt = File._createEvent("loadstart", this);
+ this.onloadstart(evt);
+ }
+
+ var me = this;
+
+ // Read file
+ navigator.fileMgr.readAsDataURL(this.fileName,
+
+ // Success callback
+ function(r) {
+ var evt;
+
+ // If DONE (cancelled), then don't do anything
+ if (me.readyState === FileReader.DONE) {
+ return;
+ }
+
+ // Save result
+ me.result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ evt = File._createEvent("load", me);
+ me.onload(evt);
+ }
+
+ // DONE state
+ me.readyState = FileReader.DONE;
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ evt = File._createEvent("loadend", me);
+ me.onloadend(evt);
+ }
+ },
+
+ // Error callback
+ function(e) {
+ var evt;
+ // If DONE (cancelled), then don't do anything
+ if (me.readyState === FileReader.DONE) {
+ return;
+ }
+
+ // Save error
+ me.error = e;
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ evt = File._createEvent("error", me);
+ me.onerror(evt);
+ }
+
+ // DONE state
+ me.readyState = FileReader.DONE;
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ evt = File._createEvent("loadend", me);
+ me.onloadend(evt);
+ }
+ }
+ );
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file The name of the file
+ */
+FileReader.prototype.readAsBinaryString = function(file) {
+ // TODO - Can't return binary data to browser.
+ this.fileName = file;
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file The name of the file
+ */
+FileReader.prototype.readAsArrayBuffer = function(file) {
+ // TODO - Can't return binary data to browser.
+ this.fileName = file;
+};
+
+//-----------------------------------------------------------------------------
+// File Writer
+//-----------------------------------------------------------------------------
+
+/**
+ * This class writes to the mobile device file system.
+ *
+ @param file {File} a File object representing a file on the file system
+*/
+FileWriter = function(file) {
+ this.fileName = "";
+ this.length = 0;
+ if (file) {
+ this.fileName = file.fullPath || file;
+ this.length = file.size || 0;
+ }
+
+ // default is to write at the beginning of the file
+ this.position = 0;
+
+ this.readyState = 0; // EMPTY
+
+ this.result = null;
+
+ // Error
+ this.error = null;
+
+ // Event handlers
+ this.onwritestart = null; // When writing starts
+ this.onprogress = null; // While writing the file, and reporting partial file data
+ this.onwrite = null; // When the write has successfully completed.
+ this.onwriteend = null; // When the request has completed (either in success or failure).
+ this.onabort = null; // When the write has been aborted. For instance, by invoking the abort() method.
+ this.onerror = null; // When the write has failed (see errors).
+}
+
+// States
+FileWriter.INIT = 0;
+FileWriter.WRITING = 1;
+FileWriter.DONE = 2;
+
+/**
+ * Abort writing file.
+ */
+FileWriter.prototype.abort = function() {
+ // check for invalid state
+ if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) {
+ throw FileError.INVALID_STATE_ERR;
+ }
+
+ // set error
+ var error = new FileError(), evt;
+ error.code = error.ABORT_ERR;
+ this.error = error;
+
+ // If error callback
+ if (typeof this.onerror === "function") {
+ evt = File._createEvent("error", this);
+ this.onerror(evt);
+ }
+ // If abort callback
+ if (typeof this.onabort === "function") {
+ evt = File._createEvent("abort", this);
+ this.onabort(evt);
+ }
+
+ this.readyState = FileWriter.DONE;
+
+ // If write end callback
+ if (typeof this.onwriteend == "function") {
+ evt = File._createEvent("writeend", this);
+ this.onwriteend(evt);
+ }
+};
+
+/**
+ * @Deprecated: use write instead
+ *
+ * @param file to write the data to
+ * @param text to be written
+ * @param bAppend if true write to end of file, otherwise overwrite the file
+ */
+FileWriter.prototype.writeAsText = function(file, text, bAppend) {
+ // Throw an exception if we are already writing a file
+ if (this.readyState === FileWriter.WRITING) {
+ throw FileError.INVALID_STATE_ERR;
+ }
+
+ if (bAppend !== true) {
+ bAppend = false; // for null values
+ }
+
+ this.fileName = file;
+
+ // WRITING state
+ this.readyState = FileWriter.WRITING;
+
+ var me = this;
+
+ // If onwritestart callback
+ if (typeof me.onwritestart === "function") {
+ var evt = File._createEvent("writestart", me);
+ me.onwritestart(evt);
+ }
+
+
+ // Write file
+ navigator.fileMgr.writeAsText(file, text, bAppend,
+ // Success callback
+ function(r) {
+ var evt;
+
+ // If DONE (cancelled), then don't do anything
+ if (me.readyState === FileWriter.DONE) {
+ return;
+ }
+
+ // Save result
+ me.result = r;
+
+ // If onwrite callback
+ if (typeof me.onwrite === "function") {
+ evt = File._createEvent("write", me);
+ me.onwrite(evt);
+ }
+
+ // DONE state
+ me.readyState = FileWriter.DONE;
+
+ // If onwriteend callback
+ if (typeof me.onwriteend === "function") {
+ evt = File._createEvent("writeend", me);
+ me.onwriteend(evt);
+ }
+ },
+
+ // Error callback
+ function(e) {
+ var evt;
+
+ // If DONE (cancelled), then don't do anything
+ if (me.readyState === FileWriter.DONE) {
+ return;
+ }
+
+ // Save error
+ me.error = e;
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ evt = File._createEvent("error", me);
+ me.onerror(evt);
+ }
+
+ // DONE state
+ me.readyState = FileWriter.DONE;
+
+ // If onwriteend callback
+ if (typeof me.onwriteend === "function") {
+ evt = File._createEvent("writeend", me);
+ me.onwriteend(evt);
+ }
+ }
+ );
+};
+
+/**
+ * Writes data to the file
+ *
+ * @param text to be written
+ */
+FileWriter.prototype.write = function(text) {
+ // Throw an exception if we are already writing a file
+ if (this.readyState === FileWriter.WRITING) {
+ throw FileError.INVALID_STATE_ERR;
+ }
+
+ // WRITING state
+ this.readyState = FileWriter.WRITING;
+
+ var me = this;
+
+ // If onwritestart callback
+ if (typeof me.onwritestart === "function") {
+ var evt = File._createEvent("writestart", me);
+ me.onwritestart(evt);
+ }
+
+ // Write file
+ navigator.fileMgr.write(this.fileName, text, this.position,
+
+ // Success callback
+ function(r) {
+ var evt;
+ // If DONE (cancelled), then don't do anything
+ if (me.readyState === FileWriter.DONE) {
+ return;
+ }
+
+
+ // position always increases by bytes written because file would be extended
+ me.position += r;
+ // The length of the file is now where we are done writing.
+ me.length = me.position;
+
+ // If onwrite callback
+ if (typeof me.onwrite === "function") {
+ evt = File._createEvent("write", me);
+ me.onwrite(evt);
+ }
+
+ // DONE state
+ me.readyState = FileWriter.DONE;
+
+ // If onwriteend callback
+ if (typeof me.onwriteend === "function") {
+ evt = File._createEvent("writeend", me);
+ me.onwriteend(evt);
+ }
+ },
+
+ // Error callback
+ function(e) {
+ var evt;
+
+ // If DONE (cancelled), then don't do anything
+ if (me.readyState === FileWriter.DONE) {
+ return;
+ }
+
+ // Save error
+ me.error = e;
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ evt = File._createEvent("error", me);
+ me.onerror(evt);
+ }
+
+ // DONE state
+ me.readyState = FileWriter.DONE;
+
+ // If onwriteend callback
+ if (typeof me.onwriteend === "function") {
+ evt = File._createEvent("writeend", me);
+ me.onwriteend(evt);
+ }
+ }
+ );
+
+};
+
+/**
+ * Moves the file pointer to the location specified.
+ *
+ * If the offset is a negative number the position of the file
+ * pointer is rewound. If the offset is greater than the file
+ * size the position is set to the end of the file.
+ *
+ * @param offset is the location to move the file pointer to.
+ */
+FileWriter.prototype.seek = function(offset) {
+ // Throw an exception if we are already writing a file
+ if (this.readyState === FileWriter.WRITING) {
+ throw FileError.INVALID_STATE_ERR;
+ }
+
+ if (!offset) {
+ return;
+ }
+
+ // See back from end of file.
+ if (offset < 0) {
+ this.position = Math.max(offset + this.length, 0);
+ }
+ // Offset is bigger then file size so set position
+ // to the end of the file.
+ else if (offset > this.length) {
+ this.position = this.length;
+ }
+ // Offset is between 0 and file size so set the position
+ // to start writing.
+ else {
+ this.position = offset;
+ }
+};
+
+/**
+ * Truncates the file to the size specified.
+ *
+ * @param size to chop the file at.
+ */
+FileWriter.prototype.truncate = function(size) {
+ // Throw an exception if we are already writing a file
+ if (this.readyState === FileWriter.WRITING) {
+ throw FileError.INVALID_STATE_ERR;
+ }
+ // what if no size specified?
+
+ // WRITING state
+ this.readyState = FileWriter.WRITING;
+
+ var me = this;
+
+ // If onwritestart callback
+ if (typeof me.onwritestart === "function") {
+ var evt = File._createEvent("writestart", me);
+ me.onwritestart(evt);
+ }
+
+ // Write file
+ navigator.fileMgr.truncate(this.fileName, size,
+
+ // Success callback
+ function(r) {
+ var evt;
+ // If DONE (cancelled), then don't do anything
+ if (me.readyState === FileWriter.DONE) {
+ return;
+ }
+
+ // Update the length of the file
+ me.length = r;
+ me.position = Math.min(me.position, r);
+
+ // If onwrite callback
+ if (typeof me.onwrite === "function") {
+ evt = File._createEvent("write", me);
+ me.onwrite(evt);
+ }
+
+ // DONE state
+ me.readyState = FileWriter.DONE;
+
+ // If onwriteend callback
+ if (typeof me.onwriteend === "function") {
+ evt = File._createEvent("writeend", me);
+ me.onwriteend(evt);
+ }
+ },
+
+ // Error callback
+ function(e) {
+ var evt;
+ // If DONE (cancelled), then don't do anything
+ if (me.readyState === FileWriter.DONE) {
+ return;
+ }
+
+ // Save error
+ me.error = e;
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ evt = File._createEvent("error", me);
+ me.onerror(evt);
+ }
+
+ // DONE state
+ me.readyState = FileWriter.DONE;
+
+ // If onwriteend callback
+ if (typeof me.onwriteend === "function") {
+ evt = File._createEvent("writeend", me);
+ me.onwriteend(evt);
+ }
+ }
+ );
+};
+
+LocalFileSystem = function() {
+};
+
+// File error codes
+LocalFileSystem.TEMPORARY = 0;
+LocalFileSystem.PERSISTENT = 1;
+LocalFileSystem.RESOURCE = 2;
+LocalFileSystem.APPLICATION = 3;
+
+/**
+ * Requests a filesystem in which to store application data.
+ *
+ * @param {int} type of file system being requested
+ * @param {Function} successCallback is called with the new FileSystem
+ * @param {Function} errorCallback is called with a FileError
+ */
+LocalFileSystem.prototype.requestFileSystem = function(type, size, successCallback, errorCallback) {
+ if (type < 0 || type > 3) {
+ if (typeof errorCallback == "function") {
+ errorCallback({
+ "code": FileError.SYNTAX_ERR
+ });
+ }
+ }
+ else {
+ PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "requestFileSystem", [type, size]);
+ }
+};
+
+/**
+ *
+ * @param {DOMString} uri referring to a local file in a filesystem
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+LocalFileSystem.prototype.resolveLocalFileSystemURI = function(uri, successCallback, errorCallback) {
+ PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "resolveLocalFileSystemURI", [uri]);
+};
+
+/**
+* This function is required as we need to convert raw
+* JSON objects into concrete File and Directory objects.
+*
+* @param a JSON Objects that need to be converted to DirectoryEntry or FileEntry objects.
+* @returns an entry
+*/
+LocalFileSystem.prototype._castFS = function(pluginResult) {
+ var entry = null;
+ entry = new DirectoryEntry();
+ entry.isDirectory = pluginResult.message.root.isDirectory;
+ entry.isFile = pluginResult.message.root.isFile;
+ entry.name = pluginResult.message.root.name;
+ entry.fullPath = pluginResult.message.root.fullPath;
+ pluginResult.message.root = entry;
+ return pluginResult;
+}
+
+LocalFileSystem.prototype._castEntry = function(pluginResult) {
+ var entry = null;
+ if (pluginResult.message.isDirectory) {
+ entry = new DirectoryEntry();
+ }
+ else if (pluginResult.message.isFile) {
+ entry = new FileEntry();
+ }
+ entry.isDirectory = pluginResult.message.isDirectory;
+ entry.isFile = pluginResult.message.isFile;
+ entry.name = pluginResult.message.name;
+ entry.fullPath = pluginResult.message.fullPath;
+ pluginResult.message = entry;
+ return pluginResult;
+}
+
+LocalFileSystem.prototype._castEntries = function(pluginResult) {
+ var entries = pluginResult.message;
+ var retVal = [];
+ for (i=0; i