/* * PhoneGap v1.1.0 is available under *either* the terms of the modified BSD license *or* the * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text. * * Copyright (c) 2005-2010, Nitobi Software Inc. * Copyright (c) 2010-2011, IBM Corporation * Copyright (c) 2011, Codevise Solutions Ltd. * 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 */ /** * 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]); }; /** * Launch camera application for taking image(s). * * @param {Function} successCB * @param {Function} errorCB * @param {CaptureImageOptions} options */ 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