diff --git a/samples/01 - viewnavigator/01 - basic/index.html b/samples/01 - viewnavigator/01 - basic/index.html index 03bfc0b..9e96628 100644 --- a/samples/01 - viewnavigator/01 - basic/index.html +++ b/samples/01 - viewnavigator/01 - basic/index.html @@ -1,67 +1,67 @@ - View Navigator Sample - + View Navigator Sample + - - - - - - - + + + + + + + - \ No newline at end of file + diff --git a/samples/01 - viewnavigator/02 - movie reviews/index.html b/samples/01 - viewnavigator/02 - movie reviews/index.html index 8cc06d2..ead2a3e 100644 --- a/samples/01 - viewnavigator/02 - movie reviews/index.html +++ b/samples/01 - viewnavigator/02 - movie reviews/index.html @@ -1,42 +1,42 @@ - View Navigator Sample - + View Navigator Sample + - - - - - - - - - + + + + + + + + + + + + + + - - \ No newline at end of file + diff --git a/samples/01 - viewnavigator/02 - movie reviews/phonegap-1.4.1.js b/samples/01 - viewnavigator/02 - movie reviews/phonegap-1.4.1.js new file mode 100644 index 0000000..680e180 --- /dev/null +++ b/samples/01 - viewnavigator/02 - movie reviews/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 - View Navigator Multiple Instances - + View Navigator Multiple Instances + - - - - - - - + + + + + + + + - - \ No newline at end of file + diff --git a/samples/03 - slidingView/01 - basic/index.html b/samples/03 - slidingView/01 - basic/index.html index b4bb846..c51fff9 100644 --- a/samples/03 - slidingView/01 - basic/index.html +++ b/samples/03 - slidingView/01 - basic/index.html @@ -1,27 +1,27 @@ - Sliding View Sample - + Sliding View Sample + - - - - - + + + + + - + + + body { + padding:0; + margin:0; + background:#fff; + -webkit-user-select:none; + -webkit-text-size-adjust:none; + color:#333; + font-family:helvetica; + font-size:12px; + text-align:center; + } + + h1 { + font-size:2em; + padding:20px 0; + margin:0; + } + + #swipeview { + width:100%; + min-width:320px; + height:150px; + background:#ddd; + border-top:1px solid #aaa; + border-bottom:1px solid #aaa; + } + + #nav { + position:absolute; + z-index:100; + top:8px; + width:200px; + height:20px; + left:50%; + background:rgba(0,0,0,0.75); + padding:0; + margin:0 0 0 -100px; + -webkit-border-radius:10px; + } + + #nav li { + display:block; + float:left; + width:14px; + height:14px; line-height:14px; + -webkit-border-radius:7px; + background:rgba(255,255,255,0.1); + overflow:hidden; + padding:0; + margin:3px 11px 0 0; + text-align:center; + } + + #nav li#prev { + margin-left:5px; + background:transparent; + } + + #nav li#next { + margin-right:0; + background:transparent; + } + + #nav li.selected { + background:rgba(255,255,255,0.4); + } + + #swipeview-slider > div { + position:relative; + display:-webkit-box; + -webkit-box-orient:vertical; + -webkit-box-pack:center; + -webkit-box-align:center; + overflow:hidden; + } + + #swipeview-slider span { + -webkit-box-sizing:border-box; + display:block; + text-align:center; + font-size:1.4em; + padding:0 20px; + } + + p { + padding:20px; + margin:0; + font-size:1.4em; + } + + + - + - +
-
-

Swipe horizontally to reveal the sidebar

-

Created with http://oridomi.com/, works on iOS devices.

+ +
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis, lorem nec vestibulum placerat, turpis nunc porttitor urna, non consectetur mauris eros vitae urna. Vestibulum at augue nisi. Suspendisse lobortis, libero vel adipiscing egestas, quam mi rhoncus justo, id imperdiet ligula nibh porta massa. - +
+
+

Swipe horizontally to reveal the sidebar

+

Created with http://oridomi.com/, works on iOS devices.

+ +
- + - \ No newline at end of file + diff --git a/samples/03 - slidingView/05 - oridomi w viewnav/index.html b/samples/03 - slidingView/05 - oridomi w viewnav/index.html index 8d387a1..b294a33 100644 --- a/samples/03 - slidingView/05 - oridomi w viewnav/index.html +++ b/samples/03 - slidingView/05 - oridomi w viewnav/index.html @@ -1,163 +1,163 @@ - Sliding View Sample - + Sliding View Sample + - - - - - - - - - - - - + + + + - + + - + - +
- + - \ No newline at end of file + diff --git a/samples/04 - browser history/index.html b/samples/04 - browser history/index.html index 564218d..e62e17b 100644 --- a/samples/04 - browser history/index.html +++ b/samples/04 - browser history/index.html @@ -1,73 +1,73 @@ - TV Listings - + TV Listings + - - - - - + + + + + - - - - - + + + - + - \ No newline at end of file + diff --git a/samples/05 - multi-device form factor/www/index.html b/samples/05 - multi-device form factor/www/index.html index 8e61007..7d1daaf 100644 --- a/samples/05 - multi-device form factor/www/index.html +++ b/samples/05 - multi-device form factor/www/index.html @@ -1,233 +1,235 @@ - View Navigator Sample - + View Navigator Sample + - - - - - - - - - + - - - - + + + + - - - - + + + + + + + + + + - - - - \ No newline at end of file + } + + $( "#"+movie.id ).addClass( "listSelected" ); + + var html = "
"; + html += "

" + movie.title + "

"; + html += "

" + movie.mpaa_rating + ", " + movie.runtime + "min. - (" + movie.year + ")

"; + html += ""; + html += "

" + movie.synopsis + "

"; + html += "

Ratings:

"; + html += "Audience: " + movie.ratings.audience_score + " - " + movie.ratings.audience_rating + "
" + html += "Critics: " + movie.ratings.critics_score + " - " + movie.ratings.critics_rating + "
" + html += "

" + html += "

What the critics say:

" + movie.critics_consensus + "

"; + html += "

Cast:

    "; + + for ( var i = 0; i < movie.abridged_cast.length; i ++ ) + { + var actor = movie.abridged_cast[i]; + html += "
  • " + actor.name + ": "; + + if ( actor.characters ) { + for ( var j = 0; j < actor.characters.length; j ++ ) + { + if ( j > 0 ) { html += ", " }; + html += actor.characters[j]; + } + } + + html += "
  • "; + } + + html += "

"; + + html += "
"; + + var viewDescriptor = { title: movie.title, + view: $(html) + }; + + if ( controller.tabletView ) { + window.splitViewNavigator.replaceBodyView( viewDescriptor ); + } + else { + viewDescriptor.backLabel = "Back"; + window.viewNavigator.pushView( viewDescriptor ); + } + } + + + $(document).ready( function() { + + controller.init(); + var _w = Math.max( $(window).width(), $(window).height() ); + var _h = Math.min( $(window).width(), $(window).height() ); + controller.tabletView = (_w >= 1000 && _h >= 600); + + var defaultView = { title: "Rotten Tomatoes", + view: $("
") + }; + + if ( controller.tabletView ) { + //Setup the ViewNavigator + new SplitViewNavigator( 'body', { + toggleButtonLabel: 'Movies' + }); + window.splitViewNavigator.pushSidebarView( controller.rootView ); + window.splitViewNavigator.pushBodyView( defaultView ); + } + else { + //phone view + window.viewNavigator = new ViewNavigator( 'body' ); + window.viewNavigator.pushView( controller.rootView ); + } + } ); + + + + + + diff --git a/src/splitviewnavigator/splitviewnavigator.js b/src/splitviewnavigator/splitviewnavigator.js index 5e43bee..20992df 100644 --- a/src/splitviewnavigator/splitviewnavigator.js +++ b/src/splitviewnavigator/splitviewnavigator.js @@ -11,7 +11,16 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var SplitViewNavigator = function( target, toggleButtonLabel, backLinkCSS, bindToWindow ) { +var SplitViewNavigator = function( target, options ) { + + var defaults = { + CSSNamespace: 'splitViewNavigator_', + toggleButtonLabel: 'Menu', + backLinkCSS: 'viewNavigator_backButton', + bindToWindow: true + }; + + this.options = options = $.extend( {}, defaults, options ); this.animating = false; this.animationDuration = 350; @@ -23,18 +32,16 @@ var SplitViewNavigator = function( target, toggleButtonLabel, backLinkCSS, bindT var regexp = new RegExp('Windows Phone OS 7'); this.winPhone = (navigator.userAgent.search(regexp) >= 0); - this.rootElement = $('
'); - this.sidebarContainer = $('
'); + this.rootElement = $('
'); + this.sidebarContainer = $('
'); this.contentOverlay = $('
'); - this.bodyContainer = $('
'); + this.bodyContainer = $('
'); - this.sidebarViewNavigator = new ViewNavigator( this.sidebarContainer.get()[0], backLinkCSS, false ); + this.sidebarViewNavigator = new ViewNavigator( this.sidebarContainer.get()[0], options.backLinkCSS, false ); - this.bodyViewNavigator = new ViewNavigator( this.bodyContainer.get()[0], backLinkCSS, false ); + this.bodyViewNavigator = new ViewNavigator( this.bodyContainer.get()[0], options.backLinkCSS, false ); - this.backLinkCSS = backLinkCSS ? backLinkCSS : 'viewNavigator_backButton'; - - this.toggleSidebarButton = $('
  • '+toggleButtonLabel+'
  • '); + this.toggleSidebarButton = $('
  • ' + options.toggleButtonLabel + '
  • '); this.rootElement.append( this.bodyContainer ); this.rootElement.append( this.contentOverlay ); @@ -52,7 +59,7 @@ var SplitViewNavigator = function( target, toggleButtonLabel, backLinkCSS, bindT this.parent.resize( function(event){ self.resizeContent() } ); //} - if ( bindToWindow != false ) { + if ( options.bindToWindow != false ) { $(window).resize( function(event){ self.resizeContent() } ); } else { diff --git a/src/viewnavigator/viewnavigator.js b/src/viewnavigator/viewnavigator.js index 99f46a5..8155b53 100644 --- a/src/viewnavigator/viewnavigator.js +++ b/src/viewnavigator/viewnavigator.js @@ -11,7 +11,15 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var ViewNavigator = function( target, backLinkCSS, bindToWindow ) { +var ViewNavigator = function( target, options ) { + + var defaults = { + CSSNamespace: 'viewNavigator_', + backLinkCSS: 'viewNavigator_backButton', + bindToWindow: true + }; + + this.options = options = $.extend( {}, defaults, options ); this.supportsBackKey = true; //phonegap on android only this.animating = false; @@ -26,22 +34,20 @@ var ViewNavigator = function( target, backLinkCSS, bindToWindow ) { var regexp = new RegExp('Windows Phone OS 7'); this.winPhone = (navigator.userAgent.search(regexp) >= 0); - this.rootElement = $('
    '); - this.header = $('
    '); - this.content = $('
    '); + this.rootElement = $('
    '); + this.header = $('
    '); + this.content = $('
    '); this.rootElement.append( this.header ); this.rootElement.append( this.content ); this.parent = $( target ); - this.backLinkCSS = backLinkCSS ? backLinkCSS : 'viewNavigator_backButton'; - var self = this; //$(window).resize( function(event){ self.resizeContent() } ); //alert( this.parent.toString() ); //this.parent.resize( function(event){ self.resizeContent() } ); - if ( bindToWindow != false ) { + if ( options.bindToWindow != false ) { $(window).resize( function(event){ self.resizeContent() } ); } else { @@ -106,19 +112,17 @@ ViewNavigator.prototype.updateView = function( viewDescriptor ) { this.animating = true; - - this.contentPendingRemove = this.contentViewHolder; this.headerContentPendingRemove = this.headerContent; - this.headerContent = $('
    '); + this.headerContent = $('
    '); - this.headerTitle = $('
    ' + viewDescriptor.title + '
    '); + this.headerTitle = $('
    ' + viewDescriptor.title + '
    '); this.headerContent.append( this.headerTitle ); var linkGuid = this.guid(); if ( viewDescriptor.backLabel ) { - this.headerBacklink = $(''); + this.headerBacklink = $(''); this.headerContent.append( this.headerBacklink ); //this is for proper handling in splitviewnavigator @@ -126,7 +130,7 @@ ViewNavigator.prototype.updateView = function( viewDescriptor ) { } var id = this.guid(); - this.contentViewHolder = $('
    '); + this.contentViewHolder = $('
    '); this.contentViewHolder.append( viewDescriptor.view ); this.resizeContent();