commit 2113f815bd0daee8a52917014e54508503eea4cf Author: moparisthebest Date: Mon Mar 18 09:35:36 2013 -0500 First revision diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0f29a65 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +# editor backup files +*~ + +android/bin +blackberry/build +images/markets + +# idea project files +.idea/ + + diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml new file mode 100644 index 0000000..c9ef5ff --- /dev/null +++ b/android/AndroidManifest.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/android/ant.properties b/android/ant.properties new file mode 100644 index 0000000..9a76e50 --- /dev/null +++ b/android/ant.properties @@ -0,0 +1,19 @@ +# This file is used to override default values used by the Ant build system. +# +# This file must be checked into Version Control Systems, as it is +# integral to the build system of your project. + +# This file is only used by the Ant script. + +# You can use this to override default values such as +# 'source.dir' for the location of your java source folder and +# 'out.dir' for the location of your output folder. + +# You can also use it define how the release builds are signed by declaring +# the following properties: +# 'key.store' for the location of your keystore and +# 'key.alias' for the name of the key to use. +# The password will be asked during the build when you use the 'release' target. + +key.store=/home/mopar/.config/android.keystore +key.alias=android_market diff --git a/android/assets/www b/android/assets/www new file mode 120000 index 0000000..933a599 --- /dev/null +++ b/android/assets/www @@ -0,0 +1 @@ +../../www \ No newline at end of file diff --git a/android/build.xml b/android/build.xml new file mode 100644 index 0000000..0c79a02 --- /dev/null +++ b/android/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/cordova/appinfo.jar b/android/cordova/appinfo.jar new file mode 100644 index 0000000..af1bde6 Binary files /dev/null and b/android/cordova/appinfo.jar differ diff --git a/android/cordova/build b/android/cordova/build new file mode 100755 index 0000000..e586e4d --- /dev/null +++ b/android/cordova/build @@ -0,0 +1,24 @@ +# 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. + +#!/bin/bash + +set -e + +CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd ) + +bash "$CORDOVA_PATH"/cordova build diff --git a/android/cordova/clean b/android/cordova/clean new file mode 100755 index 0000000..53b7f9a --- /dev/null +++ b/android/cordova/clean @@ -0,0 +1,24 @@ +# 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. + +#!/bin/bash + +set -e + +CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd ) + +bash "$CORDOVA_PATH"/cordova clean diff --git a/android/cordova/cordova b/android/cordova/cordova new file mode 100755 index 0000000..14611cf --- /dev/null +++ b/android/cordova/cordova @@ -0,0 +1,167 @@ +# 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. + +#!/bin/bash + + +PROJECT_PATH=$( cd "$( dirname "$0" )/.." && pwd ) + +function check_devices { +# FIXME + local devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep device` + if [ -z "$devices" ] ; then + echo "1" + else + echo "0" + fi +} + +function emulate { + declare -a avd_list=($(android list avd | grep "Name:" | cut -f 2 -d ":" | xargs)) + # we need to start adb-server + adb start-server 1>/dev/null + + # Do not launch an emulator if there is already one running or if a device is attached + if [ $(check_devices) == 0 ] ; then + return + fi + + local avd_id="1000" #FIXME: hopefully user does not have 1000 AVDs + # User has no AVDs + if [ ${#avd_list[@]} == 0 ] + then + echo "You don't have any Android Virtual Devices. Please create at least one AVD." + echo "android" + fi + # User has only one AVD + if [ ${#avd_list[@]} == 1 ] + then + emulator -cpu-delay 0 -no-boot-anim -cache /tmp/cache -avd ${avd_list[0]} 1> /dev/null 2>&1 & + # User has more than 1 AVD + elif [ ${#avd_list[@]} -gt 1 ] + then + while [ -z ${avd_list[$avd_id]} ] + do + echo "Choose from one of the following Android Virtual Devices [0 to $((${#avd_list[@]}-1))]:" + for(( i = 0 ; i < ${#avd_list[@]} ; i++ )) + do + echo "$i) ${avd_list[$i]}" + done + read -t 5 -p "> " avd_id + # default value if input timeout + if [ $avd_id -eq 1000 ] ; then avd_id=0 ; fi + done + emulator -cpu-delay 0 -no-boot-anim -cache /tmp/cache -avd ${avd_list[$avd_id]} 1> /dev/null 2>&1 & + fi + +} + +function clean { + ant clean +} +# has to be used independently and not in conjunction with other commands +function log { + adb logcat +} + +function run { + clean && emulate && wait_for_device && install && launch +} + +function install { + + declare -a devices=($(adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep device | cut -f 1)) + local device_id="1000" #FIXME: hopefully user does not have 1000 AVDs + + if [ ${#devices[@]} == 0 ] + then + # should not reach here. Emulator should launch or device should be attached + echo "Emulator not running or device not attached. Could not install debug package" + exit 70 + fi + + if [ ${#devices[@]} == 1 ] + then + export ANDROID_SERIAL=${devices[0]} + # User has more than 1 AVD + elif [ ${#devices[@]} -gt 1 ] + then + while [ -z ${devices[$device_id]} ] + do + echo "Choose from one of the following devices/emulators [0 to $((${#devices[@]}-1))]:" + for(( i = 0 ; i < ${#devices[@]} ; i++ )) + do + echo "$i) ${devices[$i]}" + done + read -t 5 -p "> " device_id + # default value if input timeout + if [ $device_id -eq 1000 ] ; then device_id=0 ; fi + done + export ANDROID_SERIAL=${devices[$device_id]} + fi + + ant debug install +} + +function clean_after_build(){ + rm -f assets/www/cordova.js +} + +function build { + trap clean_after_build EXIT + cp libs/cordova-2.5.0.js assets/www/cordova.js + ant debug +} + +function release { + trap clean_after_build EXIT + cp libs/cordova-2.5.0.js assets/www/cordova.js + ant release +} + +function wait_for_device { + local i="0" + echo -n "Waiting for device..." + + while [ $i -lt 300 ] + do + if [ $(check_devices) -eq 0 ] + then + break + else + sleep 1 + i=$[i+1] + echo -n "." + fi + done + # Device timeout: emulator has not started in time or device not attached + if [ $i -eq 300 ] + then + echo "device timeout!" + exit 69 + else + echo "connected!" + fi +} + +function launch { + local launch_str=$(java -jar "$PROJECT_PATH"/cordova/appinfo.jar "$PROJECT_PATH"/AndroidManifest.xml) + adb shell am start -n $launch_str +} + +# TODO parse arguments +(cd "$PROJECT_PATH" && $1) diff --git a/android/cordova/log b/android/cordova/log new file mode 100755 index 0000000..087a200 --- /dev/null +++ b/android/cordova/log @@ -0,0 +1,24 @@ +# 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. + +#!/bin/bash + +set -e + +CORDOVA_PATH=$( cd "$( dirname "$0" )/.." && pwd ) + +bash "$CORDOVA_PATH"/cordova/cordova log diff --git a/android/cordova/release b/android/cordova/release new file mode 100755 index 0000000..73d873e --- /dev/null +++ b/android/cordova/release @@ -0,0 +1,24 @@ +# 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. + +#!/bin/bash + +set -e + +CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd ) + +bash "$CORDOVA_PATH"/cordova release diff --git a/android/cordova/run b/android/cordova/run new file mode 100755 index 0000000..840a8d5 --- /dev/null +++ b/android/cordova/run @@ -0,0 +1,24 @@ +# 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. + +#!/bin/bash + +set -e + +CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd ) + +bash "$CORDOVA_PATH"/cordova run diff --git a/android/gen/R.java.d b/android/gen/R.java.d new file mode 100644 index 0000000..71aab67 --- /dev/null +++ b/android/gen/R.java.d @@ -0,0 +1,15 @@ +/home/mopar/devel/priv/pointsplus/PointsWatcher/android/gen/com/moparisthebest/pointswatcher/R.java \ + : /home/mopar/devel/priv/pointsplus/PointsWatcher/android/res/drawable-mdpi/icon.png \ +/home/mopar/devel/priv/pointsplus/PointsWatcher/android/res/drawable-xhdpi/icon.png \ +/home/mopar/devel/priv/pointsplus/PointsWatcher/android/res/layout/main.xml \ +/home/mopar/devel/priv/pointsplus/PointsWatcher/android/res/drawable-hdpi/icon.png \ +/home/mopar/devel/priv/pointsplus/PointsWatcher/android/res/drawable/icon.png \ +/home/mopar/devel/priv/pointsplus/PointsWatcher/android/res/xml/config.xml \ +/home/mopar/devel/priv/pointsplus/PointsWatcher/android/res/values/strings.xml \ +/home/mopar/devel/priv/pointsplus/PointsWatcher/android/res/drawable-ldpi/icon.png \ +/home/mopar/devel/priv/pointsplus/PointsWatcher/android/bin/res/drawable-mdpi/icon.png \ +/home/mopar/devel/priv/pointsplus/PointsWatcher/android/bin/res/drawable-xhdpi/icon.png \ +/home/mopar/devel/priv/pointsplus/PointsWatcher/android/bin/res/drawable-hdpi/icon.png \ +/home/mopar/devel/priv/pointsplus/PointsWatcher/android/bin/res/drawable/icon.png \ +/home/mopar/devel/priv/pointsplus/PointsWatcher/android/bin/res/drawable-ldpi/icon.png \ +/home/mopar/devel/priv/pointsplus/PointsWatcher/android/bin/AndroidManifest.xml \ diff --git a/android/gen/com/moparisthebest/pointswatcher/BuildConfig.java b/android/gen/com/moparisthebest/pointswatcher/BuildConfig.java new file mode 100644 index 0000000..9cc7317 --- /dev/null +++ b/android/gen/com/moparisthebest/pointswatcher/BuildConfig.java @@ -0,0 +1,6 @@ +/** Automatically generated file. DO NOT MODIFY */ +package com.moparisthebest.pointswatcher; + +public final class BuildConfig { + public final static boolean DEBUG = true; +} \ No newline at end of file diff --git a/android/gen/com/moparisthebest/pointswatcher/R.java b/android/gen/com/moparisthebest/pointswatcher/R.java new file mode 100644 index 0000000..8010672 --- /dev/null +++ b/android/gen/com/moparisthebest/pointswatcher/R.java @@ -0,0 +1,25 @@ +/* AUTO-GENERATED FILE. DO NOT MODIFY. + * + * This class was automatically generated by the + * aapt tool from the resource data it found. It + * should not be modified by hand. + */ + +package com.moparisthebest.pointswatcher; + +public final class R { + public static final class attr { + } + public static final class drawable { + public static final int icon=0x7f020000; + } + public static final class layout { + public static final int main=0x7f030000; + } + public static final class string { + public static final int app_name=0x7f050000; + } + public static final class xml { + public static final int config=0x7f040000; + } +} diff --git a/android/libs/cordova-2.5.0.jar b/android/libs/cordova-2.5.0.jar new file mode 100644 index 0000000..1c3b9f0 Binary files /dev/null and b/android/libs/cordova-2.5.0.jar differ diff --git a/android/libs/cordova-2.5.0.js b/android/libs/cordova-2.5.0.js new file mode 100644 index 0000000..e4b9ea2 --- /dev/null +++ b/android/libs/cordova-2.5.0.js @@ -0,0 +1,6461 @@ +// Platform: android + +// commit f50d20a87431c79a54572263729461883f611a53 + +// File generated at :: Tue Feb 26 2013 13:37:51 GMT-0800 (PST) + +/* + 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. +*/ + +;(function() { + +// file: lib/scripts/require.js + +var require, + define; + +(function () { + var modules = {}; + // Stack of moduleIds currently being built. + var requireStack = []; + // Map of module ID -> index into requireStack of modules currently being built. + var inProgressModules = {}; + + function build(module) { + var factory = module.factory; + module.exports = {}; + delete module.factory; + factory(require, module.exports, module); + return module.exports; + } + + require = function (id) { + if (!modules[id]) { + throw "module " + id + " not found"; + } else if (id in inProgressModules) { + var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id; + throw "Cycle in require graph: " + cycle; + } + if (modules[id].factory) { + try { + inProgressModules[id] = requireStack.length; + requireStack.push(id); + return build(modules[id]); + } finally { + delete inProgressModules[id]; + requireStack.pop(); + } + } + return modules[id].exports; + }; + + define = function (id, factory) { + if (modules[id]) { + throw "module " + id + " already defined"; + } + + modules[id] = { + id: id, + factory: factory + }; + }; + + define.remove = function (id) { + delete modules[id]; + }; + + define.moduleMap = modules; +})(); + +//Export for use in node +if (typeof module === "object" && typeof require === "function") { + module.exports.require = require; + module.exports.define = define; +} + +// file: lib/cordova.js +define("cordova", function(require, exports, module) { + + +var channel = require('cordova/channel'); + +/** + * Listen for DOMContentLoaded and notify our channel subscribers. + */ +document.addEventListener('DOMContentLoaded', function() { + channel.onDOMContentLoaded.fire(); +}, false); +if (document.readyState == 'complete' || document.readyState == 'interactive') { + channel.onDOMContentLoaded.fire(); +} + +/** + * Intercept calls to addEventListener + removeEventListener and handle deviceready, + * resume, and pause events. + */ +var m_document_addEventListener = document.addEventListener; +var m_document_removeEventListener = document.removeEventListener; +var m_window_addEventListener = window.addEventListener; +var m_window_removeEventListener = window.removeEventListener; + +/** + * Houses custom event handlers to intercept on document + window event listeners. + */ +var documentEventHandlers = {}, + windowEventHandlers = {}; + +document.addEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + if (typeof documentEventHandlers[e] != 'undefined') { + documentEventHandlers[e].subscribe(handler); + } else { + m_document_addEventListener.call(document, evt, handler, capture); + } +}; + +window.addEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + if (typeof windowEventHandlers[e] != 'undefined') { + windowEventHandlers[e].subscribe(handler); + } else { + m_window_addEventListener.call(window, evt, handler, capture); + } +}; + +document.removeEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + // If unsubscribing from an event that is handled by a plugin + if (typeof documentEventHandlers[e] != "undefined") { + documentEventHandlers[e].unsubscribe(handler); + } else { + m_document_removeEventListener.call(document, evt, handler, capture); + } +}; + +window.removeEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + // If unsubscribing from an event that is handled by a plugin + if (typeof windowEventHandlers[e] != "undefined") { + windowEventHandlers[e].unsubscribe(handler); + } else { + m_window_removeEventListener.call(window, evt, handler, capture); + } +}; + +function createEvent(type, data) { + var event = document.createEvent('Events'); + event.initEvent(type, false, false); + if (data) { + for (var i in data) { + if (data.hasOwnProperty(i)) { + event[i] = data[i]; + } + } + } + return event; +} + +if(typeof window.console === "undefined") { + window.console = { + log:function(){} + }; +} + +var cordova = { + define:define, + require:require, + /** + * Methods to add/remove your own addEventListener hijacking on document + window. + */ + addWindowEventHandler:function(event) { + return (windowEventHandlers[event] = channel.create(event)); + }, + addStickyDocumentEventHandler:function(event) { + return (documentEventHandlers[event] = channel.createSticky(event)); + }, + addDocumentEventHandler:function(event) { + return (documentEventHandlers[event] = channel.create(event)); + }, + removeWindowEventHandler:function(event) { + delete windowEventHandlers[event]; + }, + removeDocumentEventHandler:function(event) { + delete documentEventHandlers[event]; + }, + /** + * Retrieve original event handlers that were replaced by Cordova + * + * @return object + */ + getOriginalHandlers: function() { + return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener}, + 'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}}; + }, + /** + * Method to fire event from native code + * bNoDetach is required for events which cause an exception which needs to be caught in native code + */ + fireDocumentEvent: function(type, data, bNoDetach) { + var evt = createEvent(type, data); + if (typeof documentEventHandlers[type] != 'undefined') { + if( bNoDetach ) { + documentEventHandlers[type].fire(evt); + } + else { + setTimeout(function() { + documentEventHandlers[type].fire(evt); + }, 0); + } + } else { + document.dispatchEvent(evt); + } + }, + fireWindowEvent: function(type, data) { + var evt = createEvent(type,data); + if (typeof windowEventHandlers[type] != 'undefined') { + setTimeout(function() { + windowEventHandlers[type].fire(evt); + }, 0); + } else { + window.dispatchEvent(evt); + } + }, + + /** + * Plugin callback mechanism. + */ + // Randomize the starting callbackId to avoid collisions after refreshing or navigating. + // This way, it's very unlikely that any new callback would get the same callbackId as an old callback. + callbackId: Math.floor(Math.random() * 2000000000), + callbacks: {}, + 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 + }, + + /** + * Called by native code when returning successful result from an action. + */ + callbackSuccess: function(callbackId, args) { + try { + cordova.callbackFromNative(callbackId, true, args.status, args.message, args.keepCallback); + } catch (e) { + console.log("Error in error callback: " + callbackId + " = "+e); + } + }, + + /** + * Called by native code when returning error result from an action. + */ + callbackError: function(callbackId, args) { + // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative. + // Derive success from status. + try { + cordova.callbackFromNative(callbackId, false, args.status, args.message, args.keepCallback); + } catch (e) { + console.log("Error in error callback: " + callbackId + " = "+e); + } + }, + + /** + * Called by native code when returning the result from an action. + */ + callbackFromNative: function(callbackId, success, status, message, keepCallback) { + var callback = cordova.callbacks[callbackId]; + if (callback) { + if (success && status == cordova.callbackStatus.OK) { + callback.success && callback.success(message); + } else if (!success) { + callback.fail && callback.fail(message); + } + + // Clear callback if not expecting any more results + if (!keepCallback) { + delete cordova.callbacks[callbackId]; + } + } + }, + addConstructor: function(func) { + channel.onCordovaReady.subscribe(function() { + try { + func(); + } catch(e) { + console.log("Failed to run constructor: " + e); + } + }); + } +}; + +// Register pause, resume and deviceready channels as events on document. +channel.onPause = cordova.addDocumentEventHandler('pause'); +channel.onResume = cordova.addDocumentEventHandler('resume'); +channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready'); + +module.exports = cordova; + +}); + +// file: lib/common/argscheck.js +define("cordova/argscheck", function(require, exports, module) { + +var exec = require('cordova/exec'); +var utils = require('cordova/utils'); + +var moduleExports = module.exports; + +var typeMap = { + 'A': 'Array', + 'D': 'Date', + 'N': 'Number', + 'S': 'String', + 'F': 'Function', + 'O': 'Object' +}; + +function extractParamName(callee, argIndex) { + return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex]; +} + +function checkArgs(spec, functionName, args, opt_callee) { + if (!moduleExports.enableChecks) { + return; + } + var errMsg = null; + var typeName; + for (var i = 0; i < spec.length; ++i) { + var c = spec.charAt(i), + cUpper = c.toUpperCase(), + arg = args[i]; + // Asterix means allow anything. + if (c == '*') { + continue; + } + typeName = utils.typeName(arg); + if ((arg === null || arg === undefined) && c == cUpper) { + continue; + } + if (typeName != typeMap[cUpper]) { + errMsg = 'Expected ' + typeMap[cUpper]; + break; + } + } + if (errMsg) { + errMsg += ', but got ' + typeName + '.'; + errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg; + // Don't log when running jake test. + if (typeof jasmine == 'undefined') { + console.error(errMsg); + } + throw TypeError(errMsg); + } +} + +function getValue(value, defaultValue) { + return value === undefined ? defaultValue : value; +} + +moduleExports.checkArgs = checkArgs; +moduleExports.getValue = getValue; +moduleExports.enableChecks = true; + + +}); + +// file: lib/common/builder.js +define("cordova/builder", function(require, exports, module) { + +var utils = require('cordova/utils'); + +function each(objects, func, context) { + for (var prop in objects) { + if (objects.hasOwnProperty(prop)) { + func.apply(context, [objects[prop], prop]); + } + } +} + +function clobber(obj, key, value) { + exports.replaceHookForTesting(obj, key); + obj[key] = value; + // Getters can only be overridden by getters. + if (obj[key] !== value) { + utils.defineGetter(obj, key, function() { + return value; + }); + } +} + +function assignOrWrapInDeprecateGetter(obj, key, value, message) { + if (message) { + utils.defineGetter(obj, key, function() { + console.log(message); + delete obj[key]; + clobber(obj, key, value); + return value; + }); + } else { + clobber(obj, key, value); + } +} + +function include(parent, objects, clobber, merge) { + each(objects, function (obj, key) { + try { + var result = obj.path ? require(obj.path) : {}; + + if (clobber) { + // Clobber if it doesn't exist. + if (typeof parent[key] === 'undefined') { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } else if (typeof obj.path !== 'undefined') { + // If merging, merge properties onto parent, otherwise, clobber. + if (merge) { + recursiveMerge(parent[key], result); + } else { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } + } + result = parent[key]; + } else { + // Overwrite if not currently defined. + if (typeof parent[key] == 'undefined') { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } else { + // Set result to what already exists, so we can build children into it if they exist. + result = parent[key]; + } + } + + if (obj.children) { + include(result, obj.children, clobber, merge); + } + } catch(e) { + utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"'); + } + }); +} + +/** + * Merge properties from one object onto another recursively. Properties from + * the src object will overwrite existing target property. + * + * @param target Object to merge properties into. + * @param src Object to merge properties from. + */ +function recursiveMerge(target, src) { + for (var prop in src) { + if (src.hasOwnProperty(prop)) { + if (target.prototype && target.prototype.constructor === target) { + // If the target object is a constructor override off prototype. + clobber(target.prototype, prop, src[prop]); + } else { + if (typeof src[prop] === 'object' && typeof target[prop] === 'object') { + recursiveMerge(target[prop], src[prop]); + } else { + clobber(target, prop, src[prop]); + } + } + } + } +} + +exports.buildIntoButDoNotClobber = function(objects, target) { + include(target, objects, false, false); +}; +exports.buildIntoAndClobber = function(objects, target) { + include(target, objects, true, false); +}; +exports.buildIntoAndMerge = function(objects, target) { + include(target, objects, true, true); +}; +exports.recursiveMerge = recursiveMerge; +exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter; +exports.replaceHookForTesting = function() {}; + +}); + +// file: lib/common/channel.js +define("cordova/channel", function(require, exports, module) { + +var utils = require('cordova/utils'), + nextGuid = 1; + +/** + * Custom pub-sub "channel" that can have functions subscribed to it + * This object is used to define and control firing of events for + * cordova initialization, as well as for custom events thereafter. + * + * The order of events during page load and Cordova startup is as follows: + * + * onDOMContentLoaded* Internal event that is received when the web page is loaded and parsed. + * onNativeReady* Internal event that indicates the Cordova native side is ready. + * onCordovaReady* Internal event fired when all Cordova JavaScript objects have been created. + * onCordovaInfoReady* Internal event fired when device properties are available. + * onCordovaConnectionReady* Internal event fired when the connection property has been set. + * onDeviceReady* User event fired to indicate that Cordova is ready + * onResume User event fired to indicate a start/resume lifecycle event + * onPause User event fired to indicate a pause lifecycle event + * onDestroy* Internal event fired when app is being destroyed (User should use window.onunload event, not this one). + * + * The events marked with an * are sticky. Once they have fired, they will stay in the fired state. + * All listeners that subscribe after the event is fired will be executed right away. + * + * The only Cordova events that user code should register for are: + * deviceready Cordova native code is initialized and Cordova APIs can be called from JavaScript + * pause App has moved to background + * resume App has returned to foreground + * + * Listeners can be registered as: + * document.addEventListener("deviceready", myDeviceReadyListener, false); + * document.addEventListener("resume", myResumeListener, false); + * document.addEventListener("pause", myPauseListener, false); + * + * The DOM lifecycle events should be used for saving and restoring state + * window.onload + * window.onunload + * + */ + +/** + * Channel + * @constructor + * @param type String the channel name + */ +var Channel = function(type, sticky) { + this.type = type; + // Map of guid -> function. + this.handlers = {}; + // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired. + this.state = sticky ? 1 : 0; + // Used in sticky mode to remember args passed to fire(). + this.fireArgs = null; + // Used by onHasSubscribersChange to know if there are any listeners. + this.numHandlers = 0; + // Function that is called when the first listener is subscribed, or when + // the last listener is unsubscribed. + this.onHasSubscribersChange = null; +}, + channel = { + /** + * Calls the provided function only after all of the channels specified + * have been fired. All channels must be sticky channels. + */ + join: function(h, c) { + var len = c.length, + i = len, + f = function() { + if (!(--i)) h(); + }; + for (var j=0; jNative bridge. + POLLING: 0, + // For LOAD_URL to be viable, it would need to have a work-around for + // the bug where the soft-keyboard gets dismissed when a message is sent. + LOAD_URL: 1, + // For the ONLINE_EVENT to be viable, it would need to intercept all event + // listeners (both through addEventListener and window.ononline) as well + // as set the navigator property itself. + ONLINE_EVENT: 2, + // Uses reflection to access private APIs of the WebView that can send JS + // to be executed. + // Requires Android 3.2.4 or above. + PRIVATE_API: 3 + }, + jsToNativeBridgeMode, // Set lazily. + nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT, + pollEnabled = false, + messagesFromNative = []; + +function androidExec(success, fail, service, action, args) { + // Set default bridge modes if they have not already been set. + // By default, we use the failsafe, since addJavascriptInterface breaks too often + if (jsToNativeBridgeMode === undefined) { + androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT); + } + + // Process any ArrayBuffers in the args into a string. + for (var i = 0; i < args.length; i++) { + if (utils.typeName(args[i]) == 'ArrayBuffer') { + args[i] = window.btoa(String.fromCharCode.apply(null, new Uint8Array(args[i]))); + } + } + + var callbackId = service + cordova.callbackId++, + argsJson = JSON.stringify(args), + returnValue; + + // TODO: Returning the payload of a synchronous call was deprecated in 2.2.0. + // Remove it after 6 months. + function captureReturnValue(value) { + returnValue = value; + success && success(value); + } + + cordova.callbacks[callbackId] = {success:captureReturnValue, fail:fail}; + + if (jsToNativeBridgeMode == jsToNativeModes.LOCATION_CHANGE) { + window.location = 'http://cdv_exec/' + service + '#' + action + '#' + callbackId + '#' + argsJson; + } else { + var messages = nativeApiProvider.get().exec(service, action, callbackId, argsJson); + androidExec.processMessages(messages); + } + if (cordova.callbacks[callbackId]) { + if (success || fail) { + cordova.callbacks[callbackId].success = success; + } else { + delete cordova.callbacks[callbackId]; + } + } + return returnValue; +} + +function pollOnce() { + var msg = nativeApiProvider.get().retrieveJsMessages(); + androidExec.processMessages(msg); +} + +function pollingTimerFunc() { + if (pollEnabled) { + pollOnce(); + setTimeout(pollingTimerFunc, 50); + } +} + +function hookOnlineApis() { + function proxyEvent(e) { + cordova.fireWindowEvent(e.type); + } + // The network module takes care of firing online and offline events. + // It currently fires them only on document though, so we bridge them + // to window here (while first listening for exec()-releated online/offline + // events). + window.addEventListener('online', pollOnce, false); + window.addEventListener('offline', pollOnce, false); + cordova.addWindowEventHandler('online'); + cordova.addWindowEventHandler('offline'); + document.addEventListener('online', proxyEvent, false); + document.addEventListener('offline', proxyEvent, false); +} + +hookOnlineApis(); + +androidExec.jsToNativeModes = jsToNativeModes; +androidExec.nativeToJsModes = nativeToJsModes; + +androidExec.setJsToNativeBridgeMode = function(mode) { + if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) { + console.log('Falling back on PROMPT mode since _cordovaNative is missing.'); + mode = jsToNativeModes.PROMPT; + } + nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT); + jsToNativeBridgeMode = mode; +}; + +androidExec.setNativeToJsBridgeMode = function(mode) { + if (mode == nativeToJsBridgeMode) { + return; + } + if (nativeToJsBridgeMode == nativeToJsModes.POLLING) { + pollEnabled = false; + } + + nativeToJsBridgeMode = mode; + // Tell the native side to switch modes. + nativeApiProvider.get().setNativeToJsBridgeMode(mode); + + if (mode == nativeToJsModes.POLLING) { + pollEnabled = true; + setTimeout(pollingTimerFunc, 1); + } +}; + +// Processes a single message, as encoded by NativeToJsMessageQueue.java. +function processMessage(message) { + try { + var firstChar = message.charAt(0); + if (firstChar == 'J') { + eval(message.slice(1)); + } else if (firstChar == 'S' || firstChar == 'F') { + var success = firstChar == 'S'; + var keepCallback = message.charAt(1) == '1'; + var spaceIdx = message.indexOf(' ', 2); + var status = +message.slice(2, spaceIdx); + var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1); + var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx); + var payloadKind = message.charAt(nextSpaceIdx + 1); + var payload; + if (payloadKind == 's') { + payload = message.slice(nextSpaceIdx + 2); + } else if (payloadKind == 't') { + payload = true; + } else if (payloadKind == 'f') { + payload = false; + } else if (payloadKind == 'N') { + payload = null; + } else if (payloadKind == 'n') { + payload = +message.slice(nextSpaceIdx + 2); + } else if (payloadKind == 'A') { + var data = message.slice(nextSpaceIdx + 2); + var bytes = window.atob(data); + var arraybuffer = new Uint8Array(bytes.length); + for (var i = 0; i < bytes.length; i++) { + arraybuffer[i] = bytes.charCodeAt(i); + } + payload = arraybuffer.buffer; + } else { + payload = JSON.parse(message.slice(nextSpaceIdx + 1)); + } + cordova.callbackFromNative(callbackId, success, status, payload, keepCallback); + } else { + console.log("processMessage failed: invalid message:" + message); + } + } catch (e) { + console.log("processMessage failed: Message: " + message); + console.log("processMessage failed: Error: " + e); + console.log("processMessage failed: Stack: " + e.stack); + } +} + +// This is called from the NativeToJsMessageQueue.java. +androidExec.processMessages = function(messages) { + if (messages) { + messagesFromNative.push(messages); + while (messagesFromNative.length) { + messages = messagesFromNative.shift(); + // The Java side can send a * message to indicate that it + // still has messages waiting to be retrieved. + // TODO(agrieve): This is currently disabled on the Java side + // since it breaks returning the result in exec of synchronous + // plugins. Once we remove this ability, we can remove this comment. + if (messages == '*') { + window.setTimeout(pollOnce, 0); + continue; + } + + var spaceIdx = messages.indexOf(' '); + var msgLen = +messages.slice(0, spaceIdx); + var message = messages.substr(spaceIdx + 1, msgLen); + messages = messages.slice(spaceIdx + msgLen + 1); + // Put the remaining messages back into queue in case an exec() + // is made by the callback. + if (messages) { + messagesFromNative.unshift(messages); + } + + if (message) { + processMessage(message); + } + } + } +}; + +module.exports = androidExec; + +}); + +// file: lib/common/modulemapper.js +define("cordova/modulemapper", function(require, exports, module) { + +var builder = require('cordova/builder'), + moduleMap = define.moduleMap, + symbolList, + deprecationMap; + +exports.reset = function() { + symbolList = []; + deprecationMap = {}; +}; + +function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) { + if (!(moduleName in moduleMap)) { + throw new Error('Module ' + moduleName + ' does not exist.'); + } + symbolList.push(strategy, moduleName, symbolPath); + if (opt_deprecationMessage) { + deprecationMap[symbolPath] = opt_deprecationMessage; + } +} + +// Note: Android 2.3 does have Function.bind(). +exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('c', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('m', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('d', moduleName, symbolPath, opt_deprecationMessage); +}; + +function prepareNamespace(symbolPath, context) { + if (!symbolPath) { + return context; + } + var parts = symbolPath.split('.'); + var cur = context; + for (var i = 0, part; part = parts[i]; ++i) { + cur = cur[part] = cur[part] || {}; + } + return cur; +} + +exports.mapModules = function(context) { + var origSymbols = {}; + context.CDV_origSymbols = origSymbols; + for (var i = 0, len = symbolList.length; i < len; i += 3) { + var strategy = symbolList[i]; + var moduleName = symbolList[i + 1]; + var symbolPath = symbolList[i + 2]; + var lastDot = symbolPath.lastIndexOf('.'); + var namespace = symbolPath.substr(0, lastDot); + var lastName = symbolPath.substr(lastDot + 1); + + var module = require(moduleName); + var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null; + var parentObj = prepareNamespace(namespace, context); + var target = parentObj[lastName]; + + if (strategy == 'm' && target) { + builder.recursiveMerge(target, module); + } else if ((strategy == 'd' && !target) || (strategy != 'd')) { + if (!(symbolPath in origSymbols)) { + origSymbols[symbolPath] = target; + } + builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg); + } + } +}; + +exports.getOriginalSymbol = function(context, symbolPath) { + var origSymbols = context.CDV_origSymbols; + if (origSymbols && (symbolPath in origSymbols)) { + return origSymbols[symbolPath]; + } + var parts = symbolPath.split('.'); + var obj = context; + for (var i = 0; i < parts.length; ++i) { + obj = obj && obj[parts[i]]; + } + return obj; +}; + +exports.loadMatchingModules = function(matchingRegExp) { + for (var k in moduleMap) { + if (matchingRegExp.exec(k)) { + require(k); + } + } +}; + +exports.reset(); + + +}); + +// file: lib/android/platform.js +define("cordova/platform", function(require, exports, module) { + +module.exports = { + id: "android", + initialize:function() { + var channel = require("cordova/channel"), + cordova = require('cordova'), + exec = require('cordova/exec'), + modulemapper = require('cordova/modulemapper'); + + modulemapper.loadMatchingModules(/cordova.*\/symbols$/); + modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app'); + + modulemapper.mapModules(window); + + // Inject a listener for the backbutton on the document. + var backButtonChannel = cordova.addDocumentEventHandler('backbutton'); + backButtonChannel.onHasSubscribersChange = function() { + // If we just attached the first handler or detached the last handler, + // let native know we need to override the back button. + exec(null, null, "App", "overrideBackbutton", [this.numHandlers == 1]); + }; + + // Add hardware MENU and SEARCH button handlers + cordova.addDocumentEventHandler('menubutton'); + cordova.addDocumentEventHandler('searchbutton'); + + // Let native code know we are all done on the JS side. + // Native code will then un-hide the WebView. + channel.join(function() { + exec(null, null, "App", "show", []); + }, [channel.onCordovaReady]); + } +}; + +}); + +// file: lib/common/plugin/Acceleration.js +define("cordova/plugin/Acceleration", function(require, exports, module) { + +var Acceleration = function(x, y, z, timestamp) { + this.x = x; + this.y = y; + this.z = z; + this.timestamp = timestamp || (new Date()).getTime(); +}; + +module.exports = Acceleration; + +}); + +// file: lib/common/plugin/Camera.js +define("cordova/plugin/Camera", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + Camera = require('cordova/plugin/CameraConstants'), + CameraPopoverHandle = require('cordova/plugin/CameraPopoverHandle'); + +var cameraExport = {}; + +// Tack on the Camera Constants to the base camera plugin. +for (var key in Camera) { + cameraExport[key] = Camera[key]; +} + +/** + * 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=FILE_URI. + * + * @param {Function} successCallback + * @param {Function} errorCallback + * @param {Object} options + */ +cameraExport.getPicture = function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'Camera.getPicture', arguments); + options = options || {}; + var getValue = argscheck.getValue; + + var quality = getValue(options.quality, 50); + var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI); + var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA); + var targetWidth = getValue(options.targetWidth, -1); + var targetHeight = getValue(options.targetHeight, -1); + var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG); + var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE); + var allowEdit = !!options.allowEdit; + var correctOrientation = !!options.correctOrientation; + var saveToPhotoAlbum = !!options.saveToPhotoAlbum; + var popoverOptions = getValue(options.popoverOptions, null); + + var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType, + mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions]; + + exec(successCallback, errorCallback, "Camera", "takePicture", args); + return new CameraPopoverHandle(); +}; + +cameraExport.cleanup = function(successCallback, errorCallback) { + exec(successCallback, errorCallback, "Camera", "cleanup", []); +}; + +module.exports = cameraExport; + +}); + +// file: lib/common/plugin/CameraConstants.js +define("cordova/plugin/CameraConstants", function(require, exports, module) { + +module.exports = { + DestinationType:{ + DATA_URL: 0, // Return base64 encoded string + FILE_URI: 1, // Return file uri (content://media/external/images/media/2 for Android) + NATIVE_URI: 2 // Return native uri (eg. asset-library://... for iOS) + }, + EncodingType:{ + JPEG: 0, // Return JPEG encoded image + PNG: 1 // Return PNG encoded image + }, + 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 + }, + PictureSourceType:{ + PHOTOLIBRARY : 0, // Choose image from picture library (same as SAVEDPHOTOALBUM for Android) + CAMERA : 1, // Take picture from camera + SAVEDPHOTOALBUM : 2 // Choose image from picture library (same as PHOTOLIBRARY for Android) + }, + PopoverArrowDirection:{ + ARROW_UP : 1, // matches iOS UIPopoverArrowDirection constants to specify arrow location on popover + ARROW_DOWN : 2, + ARROW_LEFT : 4, + ARROW_RIGHT : 8, + ARROW_ANY : 15 + } +}; + +}); + +// file: lib/common/plugin/CameraPopoverHandle.js +define("cordova/plugin/CameraPopoverHandle", function(require, exports, module) { + +var exec = require('cordova/exec'); + +/** + * A handle to an image picker popover. + */ +var CameraPopoverHandle = function() { + this.setPosition = function(popoverOptions) { + console.log('CameraPopoverHandle.setPosition is only supported on iOS.'); + }; +}; + +module.exports = CameraPopoverHandle; + +}); + +// file: lib/common/plugin/CameraPopoverOptions.js +define("cordova/plugin/CameraPopoverOptions", function(require, exports, module) { + +var Camera = require('cordova/plugin/CameraConstants'); + +/** + * Encapsulates options for iOS Popover image picker + */ +var CameraPopoverOptions = function(x,y,width,height,arrowDir){ + // information of rectangle that popover should be anchored to + this.x = x || 0; + this.y = y || 32; + this.width = width || 320; + this.height = height || 480; + // The direction of the popover arrow + this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY; +}; + +module.exports = CameraPopoverOptions; + +}); + +// file: lib/common/plugin/CaptureAudioOptions.js +define("cordova/plugin/CaptureAudioOptions", function(require, exports, module) { + +/** + * Encapsulates all audio capture operation configuration options. + */ +var CaptureAudioOptions = function(){ + // Upper limit of sound clips user can record. Value must be equal or greater than 1. + this.limit = 1; + // Maximum duration of a single sound clip in seconds. + this.duration = 0; + // The selected audio mode. Must match with one of the elements in supportedAudioModes array. + this.mode = null; +}; + +module.exports = CaptureAudioOptions; + +}); + +// file: lib/common/plugin/CaptureError.js +define("cordova/plugin/CaptureError", function(require, exports, module) { + +/** + * The CaptureError interface encapsulates all errors in the Capture API. + */ +var CaptureError = function(c) { + this.code = c || null; +}; + +// Camera or microphone failed to capture image or sound. +CaptureError.CAPTURE_INTERNAL_ERR = 0; +// Camera application or audio capture application is currently serving other capture request. +CaptureError.CAPTURE_APPLICATION_BUSY = 1; +// Invalid use of the API (e.g. limit parameter has value less than one). +CaptureError.CAPTURE_INVALID_ARGUMENT = 2; +// User exited camera application or audio capture application before capturing anything. +CaptureError.CAPTURE_NO_MEDIA_FILES = 3; +// The requested capture operation is not supported. +CaptureError.CAPTURE_NOT_SUPPORTED = 20; + +module.exports = CaptureError; + +}); + +// file: lib/common/plugin/CaptureImageOptions.js +define("cordova/plugin/CaptureImageOptions", function(require, exports, module) { + +/** + * Encapsulates all image capture operation configuration options. + */ +var CaptureImageOptions = function(){ + // Upper limit of images user can take. Value must be equal or greater than 1. + this.limit = 1; + // The selected image mode. Must match with one of the elements in supportedImageModes array. + this.mode = null; +}; + +module.exports = CaptureImageOptions; + +}); + +// file: lib/common/plugin/CaptureVideoOptions.js +define("cordova/plugin/CaptureVideoOptions", function(require, exports, module) { + +/** + * Encapsulates all video capture operation configuration options. + */ +var CaptureVideoOptions = function(){ + // Upper limit of videos user can record. Value must be equal or greater than 1. + this.limit = 1; + // Maximum duration of a single video clip in seconds. + this.duration = 0; + // The selected video mode. Must match with one of the elements in supportedVideoModes array. + this.mode = null; +}; + +module.exports = CaptureVideoOptions; + +}); + +// file: lib/common/plugin/CompassError.js +define("cordova/plugin/CompassError", function(require, exports, module) { + +/** + * CompassError. + * An error code assigned by an implementation when an error has occurred + * @constructor + */ +var CompassError = function(err) { + this.code = (err !== undefined ? err : null); +}; + +CompassError.COMPASS_INTERNAL_ERR = 0; +CompassError.COMPASS_NOT_SUPPORTED = 20; + +module.exports = CompassError; + +}); + +// file: lib/common/plugin/CompassHeading.js +define("cordova/plugin/CompassHeading", function(require, exports, module) { + +var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) { + this.magneticHeading = magneticHeading; + this.trueHeading = trueHeading; + this.headingAccuracy = headingAccuracy; + this.timestamp = timestamp || new Date().getTime(); +}; + +module.exports = CompassHeading; + +}); + +// file: lib/common/plugin/ConfigurationData.js +define("cordova/plugin/ConfigurationData", function(require, exports, module) { + +/** + * Encapsulates a set of parameters that the capture device supports. + */ +function ConfigurationData() { + // The ASCII-encoded string in lower case representing the media type. + this.type = null; + // The height attribute represents height of the image or video in pixels. + // In the case of a sound clip this attribute has value 0. + this.height = 0; + // The width attribute represents width of the image or video in pixels. + // In the case of a sound clip this attribute has value 0 + this.width = 0; +} + +module.exports = ConfigurationData; + +}); + +// file: lib/common/plugin/Connection.js +define("cordova/plugin/Connection", function(require, exports, module) { + +/** + * Network status + */ +module.exports = { + UNKNOWN: "unknown", + ETHERNET: "ethernet", + WIFI: "wifi", + CELL_2G: "2g", + CELL_3G: "3g", + CELL_4G: "4g", + CELL:"cellular", + NONE: "none" +}; + +}); + +// file: lib/common/plugin/Contact.js +define("cordova/plugin/Contact", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + ContactError = require('cordova/plugin/ContactError'), + utils = require('cordova/utils'); + +/** +* Converts primitives into Complex Object +* Currently only used for Date fields +*/ +function convertIn(contact) { + var value = contact.birthday; + try { + contact.birthday = new Date(parseFloat(value)); + } catch (exception){ + console.log("Cordova Contact convertIn error: exception creating date."); + } + return contact; +} + +/** +* Converts Complex objects into primitives +* Only conversion at present is for Dates. +**/ + +function convertOut(contact) { + var value = contact.birthday; + if (value !== null) { + // try to make it a Date object if it is not already + if (!utils.isDate(value)){ + try { + value = new Date(value); + } catch(exception){ + value = null; + } + } + if (utils.isDate(value)){ + value = value.valueOf(); // convert to milliseconds + } + contact.birthday = value; + } + return contact; +} + +/** +* Contains information about a single contact. +* @constructor +* @param {DOMString} id unique identifier +* @param {DOMString} displayName +* @param {ContactName} name +* @param {DOMString} nickname +* @param {Array.} phoneNumbers array of phone numbers +* @param {Array.} emails array of email addresses +* @param {Array.} addresses array of addresses +* @param {Array.} ims instant messaging user ids +* @param {Array.} organizations +* @param {DOMString} birthday contact's birthday +* @param {DOMString} note user notes about contact +* @param {Array.} photos +* @param {Array.} categories +* @param {Array.} 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.rawId = 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; + this.note = note || null; + this.photos = photos || null; // ContactField[] + this.categories = categories || null; // ContactField[] + this.urls = urls || null; // ContactField[] +}; + +/** +* Removes contact from device storage. +* @param successCB success callback +* @param errorCB error callback +*/ +Contact.prototype.remove = function(successCB, errorCB) { + argscheck.checkArgs('FF', 'Contact.remove', arguments); + var fail = errorCB && function(code) { + errorCB(new ContactError(code)); + }; + if (this.id === null) { + fail(ContactError.UNKNOWN_ERROR); + } + else { + exec(successCB, fail, "Contacts", "remove", [this.id]); + } +}; + +/** +* Creates a deep copy of this Contact. +* With the contact ID set to null. +* @return copy of this Contact +*/ +Contact.prototype.clone = function() { + var clonedContact = utils.clone(this); + clonedContact.id = null; + clonedContact.rawId = null; + + function nullIds(arr) { + if (arr) { + for (var i = 0; i < arr.length; ++i) { + arr[i].id = null; + } + } + } + + // Loop through and clear out any id's in phones, emails, etc. + nullIds(clonedContact.phoneNumbers); + nullIds(clonedContact.emails); + nullIds(clonedContact.addresses); + nullIds(clonedContact.ims); + nullIds(clonedContact.organizations); + nullIds(clonedContact.categories); + nullIds(clonedContact.photos); + nullIds(clonedContact.urls); + return clonedContact; +}; + +/** +* Persists contact to device storage. +* @param successCB success callback +* @param errorCB error callback +*/ +Contact.prototype.save = function(successCB, errorCB) { + argscheck.checkArgs('FFO', 'Contact.save', arguments); + var fail = errorCB && function(code) { + errorCB(new ContactError(code)); + }; + var success = function(result) { + if (result) { + if (successCB) { + var fullContact = require('cordova/plugin/contacts').create(result); + successCB(convertIn(fullContact)); + } + } + else { + // no Entry object returned + fail(ContactError.UNKNOWN_ERROR); + } + }; + var dupContact = convertOut(utils.clone(this)); + exec(success, fail, "Contacts", "save", [dupContact]); +}; + + +module.exports = Contact; + +}); + +// file: lib/common/plugin/ContactAddress.js +define("cordova/plugin/ContactAddress", function(require, exports, module) { + +/** +* Contact address. +* @constructor +* @param {DOMString} id unique identifier, should only be set by native code +* @param formatted // NOTE: not a W3C standard +* @param streetAddress +* @param locality +* @param region +* @param postalCode +* @param country +*/ + +var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) { + this.id = null; + this.pref = (typeof pref != 'undefined' ? pref : false); + this.type = type || null; + this.formatted = formatted || null; + this.streetAddress = streetAddress || null; + this.locality = locality || null; + this.region = region || null; + this.postalCode = postalCode || null; + this.country = country || null; +}; + +module.exports = ContactAddress; + +}); + +// file: lib/common/plugin/ContactError.js +define("cordova/plugin/ContactError", function(require, exports, module) { + +/** + * ContactError. + * An error code assigned by an implementation when an error has occurred + * @constructor + */ +var ContactError = function(err) { + this.code = (typeof err != 'undefined' ? err : null); +}; + +/** + * Error codes + */ +ContactError.UNKNOWN_ERROR = 0; +ContactError.INVALID_ARGUMENT_ERROR = 1; +ContactError.TIMEOUT_ERROR = 2; +ContactError.PENDING_OPERATION_ERROR = 3; +ContactError.IO_ERROR = 4; +ContactError.NOT_SUPPORTED_ERROR = 5; +ContactError.PERMISSION_DENIED_ERROR = 20; + +module.exports = ContactError; + +}); + +// file: lib/common/plugin/ContactField.js +define("cordova/plugin/ContactField", function(require, exports, module) { + +/** +* Generic contact field. +* @constructor +* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard +* @param type +* @param value +* @param pref +*/ +var ContactField = function(type, value, pref) { + this.id = null; + this.type = (type && type.toString()) || null; + this.value = (value && value.toString()) || null; + this.pref = (typeof pref != 'undefined' ? pref : false); +}; + +module.exports = ContactField; + +}); + +// file: lib/common/plugin/ContactFindOptions.js +define("cordova/plugin/ContactFindOptions", function(require, exports, module) { + +/** + * ContactFindOptions. + * @constructor + * @param filter used to match contacts against + * @param multiple boolean used to determine if more than one contact should be returned + */ + +var ContactFindOptions = function(filter, multiple) { + this.filter = filter || ''; + this.multiple = (typeof multiple != 'undefined' ? multiple : false); +}; + +module.exports = ContactFindOptions; + +}); + +// file: lib/common/plugin/ContactName.js +define("cordova/plugin/ContactName", function(require, exports, module) { + +/** +* Contact name. +* @constructor +* @param formatted // NOTE: not part of W3C standard +* @param familyName +* @param givenName +* @param middle +* @param prefix +* @param suffix +*/ +var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) { + this.formatted = formatted || null; + this.familyName = familyName || null; + this.givenName = givenName || null; + this.middleName = middle || null; + this.honorificPrefix = prefix || null; + this.honorificSuffix = suffix || null; +}; + +module.exports = ContactName; + +}); + +// file: lib/common/plugin/ContactOrganization.js +define("cordova/plugin/ContactOrganization", function(require, exports, module) { + +/** +* Contact organization. +* @constructor +* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard +* @param name +* @param dept +* @param title +* @param startDate +* @param endDate +* @param location +* @param desc +*/ + +var ContactOrganization = function(pref, type, name, dept, title) { + this.id = null; + this.pref = (typeof pref != 'undefined' ? pref : false); + this.type = type || null; + this.name = name || null; + this.department = dept || null; + this.title = title || null; +}; + +module.exports = ContactOrganization; + +}); + +// file: lib/common/plugin/Coordinates.js +define("cordova/plugin/Coordinates", function(require, exports, module) { + +/** + * This class contains position information. + * @param {Object} lat + * @param {Object} lng + * @param {Object} alt + * @param {Object} acc + * @param {Object} head + * @param {Object} vel + * @param {Object} altacc + * @constructor + */ +var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) { + /** + * The latitude of the position. + */ + this.latitude = lat; + /** + * The longitude of the position, + */ + this.longitude = lng; + /** + * The accuracy of the position. + */ + this.accuracy = acc; + /** + * The altitude of the position. + */ + this.altitude = (alt !== undefined ? alt : null); + /** + * The direction the device is moving at the position. + */ + this.heading = (head !== undefined ? head : null); + /** + * The velocity with which the device is moving at the position. + */ + this.speed = (vel !== undefined ? vel : null); + + if (this.speed === 0 || this.speed === null) { + this.heading = NaN; + } + + /** + * The altitude accuracy of the position. + */ + this.altitudeAccuracy = (altacc !== undefined) ? altacc : null; +}; + +module.exports = Coordinates; + +}); + +// file: lib/common/plugin/DirectoryEntry.js +define("cordova/plugin/DirectoryEntry", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + utils = require('cordova/utils'), + exec = require('cordova/exec'), + Entry = require('cordova/plugin/Entry'), + FileError = require('cordova/plugin/FileError'), + DirectoryReader = require('cordova/plugin/DirectoryReader'); + +/** + * An interface representing a directory on the file system. + * + * {boolean} isFile always false (readonly) + * {boolean} isDirectory always true (readonly) + * {DOMString} name of the directory, excluding the path leading to it (readonly) + * {DOMString} fullPath the absolute full path to the directory (readonly) + * TODO: implement this!!! {FileSystem} filesystem on which the directory resides (readonly) + */ +var DirectoryEntry = function(name, fullPath) { + DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath); +}; + +utils.extend(DirectoryEntry, Entry); + +/** + * Creates a new DirectoryReader to read entries from this directory + */ +DirectoryEntry.prototype.createReader = function() { + return new DirectoryReader(this.fullPath); +}; + +/** + * Creates or looks up a directory + * + * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory + * @param {Flags} options to create or exclusively create the directory + * @param {Function} successCallback is called with the new entry + * @param {Function} errorCallback is called with a FileError + */ +DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) { + argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments); + var win = successCallback && function(result) { + var entry = new DirectoryEntry(result.name, result.fullPath); + successCallback(entry); + }; + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; + exec(win, fail, "File", "getDirectory", [this.fullPath, path, options]); +}; + +/** + * Deletes a directory and all of it's contents + * + * @param {Function} successCallback is called with no parameters + * @param {Function} errorCallback is called with a FileError + */ +DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) { + argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments); + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; + exec(successCallback, fail, "File", "removeRecursively", [this.fullPath]); +}; + +/** + * Creates or looks up a file + * + * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file + * @param {Flags} options to create or exclusively create the file + * @param {Function} successCallback is called with the new entry + * @param {Function} errorCallback is called with a FileError + */ +DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) { + argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments); + var win = successCallback && function(result) { + var FileEntry = require('cordova/plugin/FileEntry'); + var entry = new FileEntry(result.name, result.fullPath); + successCallback(entry); + }; + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; + exec(win, fail, "File", "getFile", [this.fullPath, path, options]); +}; + +module.exports = DirectoryEntry; + +}); + +// file: lib/common/plugin/DirectoryReader.js +define("cordova/plugin/DirectoryReader", function(require, exports, module) { + +var exec = require('cordova/exec'), + FileError = require('cordova/plugin/FileError') ; + +/** + * An interface that lists the files and directories in a directory. + */ +function DirectoryReader(path) { + this.path = path || null; +} + +/** + * Returns a list of entries from a directory. + * + * @param {Function} successCallback is called with a list of entries + * @param {Function} errorCallback is called with a FileError + */ +DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) { + var win = typeof successCallback !== 'function' ? null : function(result) { + var retVal = []; + for (var i=0; i= 2) { + if (end < 0) { + newEnd = Math.max(size + end, 0); + } else { + newEnd = Math.min(end, size); + } + } + + var newFile = new File(this.name, this.fullPath, this.type, this.lastModifiedData, this.size); + newFile.start = this.start + newStart; + newFile.end = this.start + newEnd; + return newFile; +}; + + +module.exports = File; + +}); + +// file: lib/common/plugin/FileEntry.js +define("cordova/plugin/FileEntry", function(require, exports, module) { + +var utils = require('cordova/utils'), + exec = require('cordova/exec'), + Entry = require('cordova/plugin/Entry'), + FileWriter = require('cordova/plugin/FileWriter'), + File = require('cordova/plugin/File'), + FileError = require('cordova/plugin/FileError'); + +/** + * An interface representing a file on the file system. + * + * {boolean} isFile always true (readonly) + * {boolean} isDirectory always false (readonly) + * {DOMString} name of the file, excluding the path leading to it (readonly) + * {DOMString} fullPath the absolute full path to the file (readonly) + * {FileSystem} filesystem on which the file resides (readonly) + */ +var FileEntry = function(name, fullPath) { + FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath]); +}; + +utils.extend(FileEntry, Entry); + +/** + * Creates a new FileWriter associated with the file that this FileEntry represents. + * + * @param {Function} successCallback is called with the new FileWriter + * @param {Function} errorCallback is called with a FileError + */ +FileEntry.prototype.createWriter = function(successCallback, errorCallback) { + this.file(function(filePointer) { + var writer = new FileWriter(filePointer); + + if (writer.fileName === null || writer.fileName === "") { + errorCallback && errorCallback(new FileError(FileError.INVALID_STATE_ERR)); + } else { + successCallback && successCallback(writer); + } + }, errorCallback); +}; + +/** + * Returns a File that represents the current state of the file that this FileEntry represents. + * + * @param {Function} successCallback is called with the new File object + * @param {Function} errorCallback is called with a FileError + */ +FileEntry.prototype.file = function(successCallback, errorCallback) { + var win = successCallback && function(f) { + var file = new File(f.name, f.fullPath, f.type, f.lastModifiedDate, f.size); + successCallback(file); + }; + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; + exec(win, fail, "File", "getFileMetadata", [this.fullPath]); +}; + + +module.exports = FileEntry; + +}); + +// file: lib/common/plugin/FileError.js +define("cordova/plugin/FileError", function(require, exports, module) { + +/** + * FileError + */ +function FileError(error) { + this.code = error || null; +} + +// File error codes +// Found in DOMException +FileError.NOT_FOUND_ERR = 1; +FileError.SECURITY_ERR = 2; +FileError.ABORT_ERR = 3; + +// Added by File API specification +FileError.NOT_READABLE_ERR = 4; +FileError.ENCODING_ERR = 5; +FileError.NO_MODIFICATION_ALLOWED_ERR = 6; +FileError.INVALID_STATE_ERR = 7; +FileError.SYNTAX_ERR = 8; +FileError.INVALID_MODIFICATION_ERR = 9; +FileError.QUOTA_EXCEEDED_ERR = 10; +FileError.TYPE_MISMATCH_ERR = 11; +FileError.PATH_EXISTS_ERR = 12; + +module.exports = FileError; + +}); + +// file: lib/common/plugin/FileReader.js +define("cordova/plugin/FileReader", function(require, exports, module) { + +var exec = require('cordova/exec'), + modulemapper = require('cordova/modulemapper'), + utils = require('cordova/utils'), + File = require('cordova/plugin/File'), + FileError = require('cordova/plugin/FileError'), + ProgressEvent = require('cordova/plugin/ProgressEvent'), + origFileReader = modulemapper.getOriginalSymbol(this, 'FileReader'); + +/** + * This class reads the mobile device file system. + * + * For Android: + * The root directory is the root of the file system. + * To read from the SD card, the file name is "sdcard/my_file.txt" + * @constructor + */ +var FileReader = function() { + this._readyState = 0; + this._error = null; + this._result = null; + this._fileName = ''; + this._realReader = origFileReader ? new origFileReader() : {}; +}; + +// States +FileReader.EMPTY = 0; +FileReader.LOADING = 1; +FileReader.DONE = 2; + +utils.defineGetter(FileReader.prototype, 'readyState', function() { + return this._fileName ? this._readyState : this._realReader.readyState; +}); + +utils.defineGetter(FileReader.prototype, 'error', function() { + return this._fileName ? this._error: this._realReader.error; +}); + +utils.defineGetter(FileReader.prototype, 'result', function() { + return this._fileName ? this._result: this._realReader.result; +}); + +function defineEvent(eventName) { + utils.defineGetterSetter(FileReader.prototype, eventName, function() { + return this._realReader[eventName] || null; + }, function(value) { + this._realReader[eventName] = value; + }); +} +defineEvent('onloadstart'); // When the read starts. +defineEvent('onprogress'); // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total) +defineEvent('onload'); // When the read has successfully completed. +defineEvent('onerror'); // When the read has failed (see errors). +defineEvent('onloadend'); // When the request has completed (either in success or failure). +defineEvent('onabort'); // When the read has been aborted. For instance, by invoking the abort() method. + +function initRead(reader, file) { + // Already loading something + if (reader.readyState == FileReader.LOADING) { + throw new FileError(FileError.INVALID_STATE_ERR); + } + + reader._result = null; + reader._error = null; + reader._readyState = FileReader.LOADING; + + if (typeof file == 'string') { + // Deprecated in Cordova 2.4. + console.warning('Using a string argument with FileReader.readAs functions is deprecated.'); + reader._fileName = file; + } else if (typeof file.fullPath == 'string') { + reader._fileName = file.fullPath; + } else { + reader._fileName = ''; + return true; + } + + reader.onloadstart && reader.onloadstart(new ProgressEvent("loadstart", {target:reader})); +} + +/** + * Abort reading file. + */ +FileReader.prototype.abort = function() { + if (origFileReader && !this._fileName) { + return this._realReader.abort(); + } + this._result = null; + + if (this._readyState == FileReader.DONE || this._readyState == FileReader.EMPTY) { + return; + } + + this._readyState = FileReader.DONE; + + // If abort callback + if (typeof this.onabort === 'function') { + this.onabort(new ProgressEvent('abort', {target:this})); + } + // If load end callback + if (typeof this.onloadend === 'function') { + this.onloadend(new ProgressEvent('loadend', {target:this})); + } +}; + +/** + * Read text file. + * + * @param file {File} File object containing file properties + * @param encoding [Optional] (see http://www.iana.org/assignments/character-sets) + */ +FileReader.prototype.readAsText = function(file, encoding) { + if (initRead(this, file)) { + return this._realReader.readAsText(file, encoding); + } + + // Default encoding is UTF-8 + var enc = encoding ? encoding : "UTF-8"; + var me = this; + var execArgs = [this._fileName, enc]; + + // Maybe add slice parameters. + if (file.end < file.size) { + execArgs.push(file.start, file.end); + } else if (file.start > 0) { + execArgs.push(file.start); + } + + // Read file + exec( + // Success callback + function(r) { + // 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") { + me.onload(new ProgressEvent("load", {target:me})); + } + + // DONE state + me._readyState = FileReader.DONE; + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, + // Error callback + function(e) { + // If DONE (cancelled), then don't do anything + if (me._readyState === FileReader.DONE) { + return; + } + + // DONE state + me._readyState = FileReader.DONE; + + // null result + me._result = null; + + // Save error + me._error = new FileError(e); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {target:me})); + } + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, "File", "readAsText", execArgs); +}; + + +/** + * Read file and return data as a base64 encoded data url. + * A data url is of the form: + * data:[][;base64], + * + * @param file {File} File object containing file properties + */ +FileReader.prototype.readAsDataURL = function(file) { + if (initRead(this, file)) { + return this._realReader.readAsDataURL(file); + } + + var me = this; + var execArgs = [this._fileName]; + + // Maybe add slice parameters. + if (file.end < file.size) { + execArgs.push(file.start, file.end); + } else if (file.start > 0) { + execArgs.push(file.start); + } + + // Read file + exec( + // Success callback + function(r) { + // If DONE (cancelled), then don't do anything + if (me._readyState === FileReader.DONE) { + return; + } + + // DONE state + me._readyState = FileReader.DONE; + + // Save result + me._result = r; + + // If onload callback + if (typeof me.onload === "function") { + me.onload(new ProgressEvent("load", {target:me})); + } + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, + // Error callback + function(e) { + // If DONE (cancelled), then don't do anything + if (me._readyState === FileReader.DONE) { + return; + } + + // DONE state + me._readyState = FileReader.DONE; + + me._result = null; + + // Save error + me._error = new FileError(e); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {target:me})); + } + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, "File", "readAsDataURL", execArgs); +}; + +/** + * Read file and return data as a binary data. + * + * @param file {File} File object containing file properties + */ +FileReader.prototype.readAsBinaryString = function(file) { + if (initRead(this, file)) { + return this._realReader.readAsBinaryString(file); + } + // TODO - Can't return binary data to browser. + console.log('method "readAsBinaryString" is not supported at this time.'); + this.abort(); +}; + +/** + * Read file and return data as a binary data. + * + * @param file {File} File object containing file properties + */ +FileReader.prototype.readAsArrayBuffer = function(file) { + if (initRead(this, file)) { + return this._realReader.readAsArrayBuffer(file); + } + // TODO - Can't return binary data to browser. + console.log('This method is not supported at this time.'); + this.abort(); +}; + +module.exports = FileReader; + +}); + +// file: lib/common/plugin/FileSystem.js +define("cordova/plugin/FileSystem", function(require, exports, module) { + +var DirectoryEntry = require('cordova/plugin/DirectoryEntry'); + +/** + * An interface representing a file system + * + * @constructor + * {DOMString} name the unique name of the file system (readonly) + * {DirectoryEntry} root directory of the file system (readonly) + */ +var FileSystem = function(name, root) { + this.name = name || null; + if (root) { + this.root = new DirectoryEntry(root.name, root.fullPath); + } +}; + +module.exports = FileSystem; + +}); + +// file: lib/common/plugin/FileTransfer.js +define("cordova/plugin/FileTransfer", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + FileTransferError = require('cordova/plugin/FileTransferError'), + ProgressEvent = require('cordova/plugin/ProgressEvent'); + +function newProgressEvent(result) { + var pe = new ProgressEvent(); + pe.lengthComputable = result.lengthComputable; + pe.loaded = result.loaded; + pe.total = result.total; + return pe; +} + +var idCounter = 0; + +/** + * FileTransfer uploads a file to a remote server. + * @constructor + */ +var FileTransfer = function() { + this._id = ++idCounter; + this.onprogress = null; // optional callback +}; + +/** +* Given an absolute file path, uploads a file on the device to a remote server +* using a multipart HTTP request. +* @param filePath {String} Full path of the file on the device +* @param server {String} URL of the server to receive the file +* @param successCallback (Function} Callback to be invoked when upload has completed +* @param errorCallback {Function} Callback to be invoked upon error +* @param options {FileUploadOptions} Optional parameters such as file name and mimetype +* @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false +*/ +FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, trustAllHosts) { + argscheck.checkArgs('ssFFO*', 'FileTransfer.upload', arguments); + // check for options + var fileKey = null; + var fileName = null; + var mimeType = null; + var params = null; + var chunkedMode = true; + var headers = null; + if (options) { + fileKey = options.fileKey; + fileName = options.fileName; + mimeType = options.mimeType; + headers = options.headers; + if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") { + chunkedMode = options.chunkedMode; + } + if (options.params) { + params = options.params; + } + else { + params = {}; + } + } + + var fail = errorCallback && function(e) { + var error = new FileTransferError(e.code, e.source, e.target, e.http_status); + errorCallback(error); + }; + + var self = this; + var win = function(result) { + if (typeof result.lengthComputable != "undefined") { + if (self.onprogress) { + self.onprogress(newProgressEvent(result)); + } + } else { + successCallback && successCallback(result); + } + }; + exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id]); +}; + +/** + * Downloads a file form a given URL and saves it to the specified directory. + * @param source {String} URL of the server to receive the file + * @param target {String} Full path of the file on the device + * @param successCallback (Function} Callback to be invoked when upload has completed + * @param errorCallback {Function} Callback to be invoked upon error + * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false + */ +FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts) { + argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments); + var self = this; + var win = function(result) { + if (typeof result.lengthComputable != "undefined") { + if (self.onprogress) { + return self.onprogress(newProgressEvent(result)); + } + } else if (successCallback) { + var entry = null; + if (result.isDirectory) { + entry = new (require('cordova/plugin/DirectoryEntry'))(); + } + else if (result.isFile) { + entry = new (require('cordova/plugin/FileEntry'))(); + } + entry.isDirectory = result.isDirectory; + entry.isFile = result.isFile; + entry.name = result.name; + entry.fullPath = result.fullPath; + successCallback(entry); + } + }; + + var fail = errorCallback && function(e) { + var error = new FileTransferError(e.code, e.source, e.target, e.http_status); + errorCallback(error); + }; + + exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id]); +}; + +/** + * Aborts the ongoing file transfer on this object + * @param successCallback {Function} Callback to be invoked upon success + * @param errorCallback {Function} Callback to be invoked upon error + */ +FileTransfer.prototype.abort = function(successCallback, errorCallback) { + exec(successCallback, errorCallback, 'FileTransfer', 'abort', [this._id]); +}; + +module.exports = FileTransfer; + +}); + +// file: lib/common/plugin/FileTransferError.js +define("cordova/plugin/FileTransferError", function(require, exports, module) { + +/** + * FileTransferError + * @constructor + */ +var FileTransferError = function(code, source, target, status, body) { + this.code = code || null; + this.source = source || null; + this.target = target || null; + this.http_status = status || null; + this.body = body || null; +}; + +FileTransferError.FILE_NOT_FOUND_ERR = 1; +FileTransferError.INVALID_URL_ERR = 2; +FileTransferError.CONNECTION_ERR = 3; +FileTransferError.ABORT_ERR = 4; + +module.exports = FileTransferError; + +}); + +// file: lib/common/plugin/FileUploadOptions.js +define("cordova/plugin/FileUploadOptions", function(require, exports, module) { + +/** + * Options to customize the HTTP request used to upload files. + * @constructor + * @param fileKey {String} Name of file request parameter. + * @param fileName {String} Filename to be used by the server. Defaults to image.jpg. + * @param mimeType {String} Mimetype of the uploaded file. Defaults to image/jpeg. + * @param params {Object} Object with key: value params to send to the server. + * @param headers {Object} Keys are header names, values are header values. Multiple + * headers of the same name are not supported. + */ +var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers) { + this.fileKey = fileKey || null; + this.fileName = fileName || null; + this.mimeType = mimeType || null; + this.params = params || null; + this.headers = headers || null; +}; + +module.exports = FileUploadOptions; + +}); + +// file: lib/common/plugin/FileUploadResult.js +define("cordova/plugin/FileUploadResult", function(require, exports, module) { + +/** + * FileUploadResult + * @constructor + */ +var FileUploadResult = function() { + this.bytesSent = 0; + this.responseCode = null; + this.response = null; +}; + +module.exports = FileUploadResult; + +}); + +// file: lib/common/plugin/FileWriter.js +define("cordova/plugin/FileWriter", function(require, exports, module) { + +var exec = require('cordova/exec'), + FileError = require('cordova/plugin/FileError'), + ProgressEvent = require('cordova/plugin/ProgressEvent'); + +/** + * This class writes to the mobile device file system. + * + * For Android: + * The root directory is the root of the file system. + * To write to the SD card, the file name is "sdcard/my_file.txt" + * + * @constructor + * @param file {File} File object containing file properties + * @param append if true write to the end of the file, otherwise overwrite the file + */ +var 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 new FileError(FileError.INVALID_STATE_ERR); + } + + // set error + this.error = new FileError(FileError.ABORT_ERR); + + this.readyState = FileWriter.DONE; + + // If abort callback + if (typeof this.onabort === "function") { + this.onabort(new ProgressEvent("abort", {"target":this})); + } + + // If write end callback + if (typeof this.onwriteend === "function") { + this.onwriteend(new ProgressEvent("writeend", {"target":this})); + } +}; + +/** + * 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 new FileError(FileError.INVALID_STATE_ERR); + } + + // WRITING state + this.readyState = FileWriter.WRITING; + + var me = this; + + // If onwritestart callback + if (typeof me.onwritestart === "function") { + me.onwritestart(new ProgressEvent("writestart", {"target":me})); + } + + // Write file + exec( + // Success callback + function(r) { + // 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; + + // DONE state + me.readyState = FileWriter.DONE; + + // If onwrite callback + if (typeof me.onwrite === "function") { + me.onwrite(new ProgressEvent("write", {"target":me})); + } + + // If onwriteend callback + if (typeof me.onwriteend === "function") { + me.onwriteend(new ProgressEvent("writeend", {"target":me})); + } + }, + // Error callback + function(e) { + // If DONE (cancelled), then don't do anything + if (me.readyState === FileWriter.DONE) { + return; + } + + // DONE state + me.readyState = FileWriter.DONE; + + // Save error + me.error = new FileError(e); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {"target":me})); + } + + // If onwriteend callback + if (typeof me.onwriteend === "function") { + me.onwriteend(new ProgressEvent("writeend", {"target":me})); + } + }, "File", "write", [this.fileName, text, this.position]); +}; + +/** + * 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 new FileError(FileError.INVALID_STATE_ERR); + } + + if (!offset && offset !== 0) { + return; + } + + // See back from end of file. + if (offset < 0) { + this.position = Math.max(offset + this.length, 0); + } + // Offset is bigger than 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 new FileError(FileError.INVALID_STATE_ERR); + } + + // WRITING state + this.readyState = FileWriter.WRITING; + + var me = this; + + // If onwritestart callback + if (typeof me.onwritestart === "function") { + me.onwritestart(new ProgressEvent("writestart", {"target":this})); + } + + // Write file + exec( + // Success callback + function(r) { + // If DONE (cancelled), then don't do anything + if (me.readyState === FileWriter.DONE) { + return; + } + + // DONE state + me.readyState = FileWriter.DONE; + + // Update the length of the file + me.length = r; + me.position = Math.min(me.position, r); + + // If onwrite callback + if (typeof me.onwrite === "function") { + me.onwrite(new ProgressEvent("write", {"target":me})); + } + + // If onwriteend callback + if (typeof me.onwriteend === "function") { + me.onwriteend(new ProgressEvent("writeend", {"target":me})); + } + }, + // Error callback + function(e) { + // If DONE (cancelled), then don't do anything + if (me.readyState === FileWriter.DONE) { + return; + } + + // DONE state + me.readyState = FileWriter.DONE; + + // Save error + me.error = new FileError(e); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {"target":me})); + } + + // If onwriteend callback + if (typeof me.onwriteend === "function") { + me.onwriteend(new ProgressEvent("writeend", {"target":me})); + } + }, "File", "truncate", [this.fileName, size]); +}; + +module.exports = FileWriter; + +}); + +// file: lib/common/plugin/Flags.js +define("cordova/plugin/Flags", function(require, exports, module) { + +/** + * Supplies arguments to methods that lookup or create files and directories. + * + * @param create + * {boolean} file or directory if it doesn't exist + * @param exclusive + * {boolean} used with create; if true the command will fail if + * target path exists + */ +function Flags(create, exclusive) { + this.create = create || false; + this.exclusive = exclusive || false; +} + +module.exports = Flags; + +}); + +// file: lib/common/plugin/GlobalizationError.js +define("cordova/plugin/GlobalizationError", function(require, exports, module) { + + +/** + * Globalization error object + * + * @constructor + * @param code + * @param message + */ +var GlobalizationError = function(code, message) { + this.code = code || null; + this.message = message || ''; +}; + +// Globalization error codes +GlobalizationError.UNKNOWN_ERROR = 0; +GlobalizationError.FORMATTING_ERROR = 1; +GlobalizationError.PARSING_ERROR = 2; +GlobalizationError.PATTERN_ERROR = 3; + +module.exports = GlobalizationError; + +}); + +// file: lib/common/plugin/InAppBrowser.js +define("cordova/plugin/InAppBrowser", function(require, exports, module) { + +var exec = require('cordova/exec'); +var channel = require('cordova/channel'); + +function InAppBrowser() { + this.channels = { + 'loadstart': channel.create('loadstart'), + 'loadstop' : channel.create('loadstop'), + 'exit' : channel.create('exit') + }; +} + +InAppBrowser.prototype = { + _eventHandler: function (event) { + if (event.type in this.channels) { + this.channels[event.type].fire(event); + } + }, + close: function (eventname) { + exec(null, null, "InAppBrowser", "close", []); + }, + addEventListener: function (eventname,f) { + if (eventname in this.channels) { + this.channels[eventname].subscribe(f); + } + }, + removeEventListener: function(eventname, f) { + if (eventname in this.channels) { + this.channels[eventname].unsubscribe(f); + } + } +}; + +module.exports = function(strUrl, strWindowName, strWindowFeatures) { + var iab = new InAppBrowser(); + var cb = function(eventname) { + iab._eventHandler(eventname); + }; + exec(cb, null, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]); + return iab; +}; + + +}); + +// file: lib/common/plugin/LocalFileSystem.js +define("cordova/plugin/LocalFileSystem", function(require, exports, module) { + +var exec = require('cordova/exec'); + +/** + * Represents a local file system. + */ +var LocalFileSystem = function() { + +}; + +LocalFileSystem.TEMPORARY = 0; //temporary, with no guarantee of persistence +LocalFileSystem.PERSISTENT = 1; //persistent + +module.exports = LocalFileSystem; + +}); + +// file: lib/common/plugin/Media.js +define("cordova/plugin/Media", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + utils = require('cordova/utils'), + exec = require('cordova/exec'); + +var mediaObjects = {}; + +/** + * This class provides access to the device media, interfaces to both sound and video + * + * @constructor + * @param src The file name or url to play + * @param successCallback The callback to be called when the file is done playing or recording. + * successCallback() + * @param errorCallback The callback to be called if there is an error. + * errorCallback(int errorCode) - OPTIONAL + * @param statusCallback The callback to be called when media status has changed. + * statusCallback(int statusCode) - OPTIONAL + */ +var Media = function(src, successCallback, errorCallback, statusCallback) { + argscheck.checkArgs('SFFF', 'Media', arguments); + this.id = utils.createUUID(); + mediaObjects[this.id] = this; + this.src = src; + this.successCallback = successCallback; + this.errorCallback = errorCallback; + this.statusCallback = statusCallback; + this._duration = -1; + this._position = -1; + exec(null, this.errorCallback, "Media", "create", [this.id, this.src]); +}; + +// Media messages +Media.MEDIA_STATE = 1; +Media.MEDIA_DURATION = 2; +Media.MEDIA_POSITION = 3; +Media.MEDIA_ERROR = 9; + +// Media states +Media.MEDIA_NONE = 0; +Media.MEDIA_STARTING = 1; +Media.MEDIA_RUNNING = 2; +Media.MEDIA_PAUSED = 3; +Media.MEDIA_STOPPED = 4; +Media.MEDIA_MSG = ["None", "Starting", "Running", "Paused", "Stopped"]; + +// "static" function to return existing objs. +Media.get = function(id) { + return mediaObjects[id]; +}; + +/** + * Start or resume playing audio file. + */ +Media.prototype.play = function(options) { + exec(null, null, "Media", "startPlayingAudio", [this.id, this.src, options]); +}; + +/** + * Stop playing audio file. + */ +Media.prototype.stop = function() { + var me = this; + exec(function() { + me._position = 0; + }, this.errorCallback, "Media", "stopPlayingAudio", [this.id]); +}; + +/** + * Seek or jump to a new time in the track.. + */ +Media.prototype.seekTo = function(milliseconds) { + var me = this; + exec(function(p) { + me._position = p; + }, this.errorCallback, "Media", "seekToAudio", [this.id, milliseconds]); +}; + +/** + * Pause playing audio file. + */ +Media.prototype.pause = function() { + exec(null, this.errorCallback, "Media", "pausePlayingAudio", [this.id]); +}; + +/** + * Get duration of an audio file. + * The duration is only set for audio that is playing, paused or stopped. + * + * @return duration or -1 if not known. + */ +Media.prototype.getDuration = function() { + return this._duration; +}; + +/** + * Get position of audio. + */ +Media.prototype.getCurrentPosition = function(success, fail) { + var me = this; + exec(function(p) { + me._position = p; + success(p); + }, fail, "Media", "getCurrentPositionAudio", [this.id]); +}; + +/** + * Start recording audio file. + */ +Media.prototype.startRecord = function() { + exec(null, this.errorCallback, "Media", "startRecordingAudio", [this.id, this.src]); +}; + +/** + * Stop recording audio file. + */ +Media.prototype.stopRecord = function() { + exec(null, this.errorCallback, "Media", "stopRecordingAudio", [this.id]); +}; + +/** + * Release the resources. + */ +Media.prototype.release = function() { + exec(null, this.errorCallback, "Media", "release", [this.id]); +}; + +/** + * Adjust the volume. + */ +Media.prototype.setVolume = function(volume) { + exec(null, null, "Media", "setVolume", [this.id, volume]); +}; + +/** + * Audio has status update. + * PRIVATE + * + * @param id The media object id (string) + * @param msgType The 'type' of update this is + * @param value Use of value is determined by the msgType + */ +Media.onStatus = function(id, msgType, value) { + + var media = mediaObjects[id]; + + if(media) { + switch(msgType) { + case Media.MEDIA_STATE : + media.statusCallback && media.statusCallback(value); + if(value == Media.MEDIA_STOPPED) { + media.successCallback && media.successCallback(); + } + break; + case Media.MEDIA_DURATION : + media._duration = value; + break; + case Media.MEDIA_ERROR : + media.errorCallback && media.errorCallback(value); + break; + case Media.MEDIA_POSITION : + media._position = Number(value); + break; + default : + console.error && console.error("Unhandled Media.onStatus :: " + msgType); + break; + } + } + else { + console.error && console.error("Received Media.onStatus callback for unknown media :: " + id); + } + +}; + +module.exports = Media; + +}); + +// file: lib/common/plugin/MediaError.js +define("cordova/plugin/MediaError", function(require, exports, module) { + +/** + * This class contains information about any Media errors. +*/ +/* + According to :: http://dev.w3.org/html5/spec-author-view/video.html#mediaerror + We should never be creating these objects, we should just implement the interface + which has 1 property for an instance, 'code' + + instead of doing : + errorCallbackFunction( new MediaError(3,'msg') ); +we should simply use a literal : + errorCallbackFunction( {'code':3} ); + */ + + var _MediaError = window.MediaError; + + +if(!_MediaError) { + window.MediaError = _MediaError = function(code, msg) { + this.code = (typeof code != 'undefined') ? code : null; + this.message = msg || ""; // message is NON-standard! do not use! + }; +} + +_MediaError.MEDIA_ERR_NONE_ACTIVE = _MediaError.MEDIA_ERR_NONE_ACTIVE || 0; +_MediaError.MEDIA_ERR_ABORTED = _MediaError.MEDIA_ERR_ABORTED || 1; +_MediaError.MEDIA_ERR_NETWORK = _MediaError.MEDIA_ERR_NETWORK || 2; +_MediaError.MEDIA_ERR_DECODE = _MediaError.MEDIA_ERR_DECODE || 3; +_MediaError.MEDIA_ERR_NONE_SUPPORTED = _MediaError.MEDIA_ERR_NONE_SUPPORTED || 4; +// TODO: MediaError.MEDIA_ERR_NONE_SUPPORTED is legacy, the W3 spec now defines it as below. +// as defined by http://dev.w3.org/html5/spec-author-view/video.html#error-codes +_MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = _MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED || 4; + +module.exports = _MediaError; + +}); + +// file: lib/common/plugin/MediaFile.js +define("cordova/plugin/MediaFile", function(require, exports, module) { + +var utils = require('cordova/utils'), + exec = require('cordova/exec'), + File = require('cordova/plugin/File'), + CaptureError = require('cordova/plugin/CaptureError'); +/** + * Represents a single file. + * + * name {DOMString} name of the file, without path information + * fullPath {DOMString} the full path of the file, including the name + * type {DOMString} mime type + * lastModifiedDate {Date} last modified date + * size {Number} size of the file in bytes + */ +var MediaFile = function(name, fullPath, type, lastModifiedDate, size){ + MediaFile.__super__.constructor.apply(this, arguments); +}; + +utils.extend(MediaFile, File); + +/** + * Request capture format data for a specific file and type + * + * @param {Function} successCB + * @param {Function} errorCB + */ +MediaFile.prototype.getFormatData = function(successCallback, errorCallback) { + if (typeof this.fullPath === "undefined" || this.fullPath === null) { + errorCallback(new CaptureError(CaptureError.CAPTURE_INVALID_ARGUMENT)); + } else { + exec(successCallback, errorCallback, "Capture", "getFormatData", [this.fullPath, this.type]); + } +}; + +module.exports = MediaFile; + +}); + +// file: lib/common/plugin/MediaFileData.js +define("cordova/plugin/MediaFileData", function(require, exports, module) { + +/** + * MediaFileData encapsulates format information of a media file. + * + * @param {DOMString} codecs + * @param {long} bitrate + * @param {long} height + * @param {long} width + * @param {float} duration + */ +var MediaFileData = function(codecs, bitrate, height, width, duration){ + this.codecs = codecs || null; + this.bitrate = bitrate || 0; + this.height = height || 0; + this.width = width || 0; + this.duration = duration || 0; +}; + +module.exports = MediaFileData; + +}); + +// file: lib/common/plugin/Metadata.js +define("cordova/plugin/Metadata", function(require, exports, module) { + +/** + * Information about the state of the file or directory + * + * {Date} modificationTime (readonly) + */ +var Metadata = function(time) { + this.modificationTime = (typeof time != 'undefined'?new Date(time):null); +}; + +module.exports = Metadata; + +}); + +// file: lib/common/plugin/Position.js +define("cordova/plugin/Position", function(require, exports, module) { + +var Coordinates = require('cordova/plugin/Coordinates'); + +var Position = function(coords, timestamp) { + if (coords) { + this.coords = new Coordinates(coords.latitude, coords.longitude, coords.altitude, coords.accuracy, coords.heading, coords.velocity, coords.altitudeAccuracy); + } else { + this.coords = new Coordinates(); + } + this.timestamp = (timestamp !== undefined) ? timestamp : new Date(); +}; + +module.exports = Position; + +}); + +// file: lib/common/plugin/PositionError.js +define("cordova/plugin/PositionError", function(require, exports, module) { + +/** + * Position error object + * + * @constructor + * @param code + * @param message + */ +var PositionError = function(code, message) { + this.code = code || null; + this.message = message || ''; +}; + +PositionError.PERMISSION_DENIED = 1; +PositionError.POSITION_UNAVAILABLE = 2; +PositionError.TIMEOUT = 3; + +module.exports = PositionError; + +}); + +// file: lib/common/plugin/ProgressEvent.js +define("cordova/plugin/ProgressEvent", function(require, exports, module) { + +// If ProgressEvent exists in global context, use it already, otherwise use our own polyfill +// Feature test: See if we can instantiate a native ProgressEvent; +// if so, use that approach, +// otherwise fill-in with our own implementation. +// +// NOTE: right now we always fill in with our own. Down the road would be nice if we can use whatever is native in the webview. +var ProgressEvent = (function() { + /* + var createEvent = function(data) { + var event = document.createEvent('Events'); + event.initEvent('ProgressEvent', false, false); + if (data) { + for (var i in data) { + if (data.hasOwnProperty(i)) { + event[i] = data[i]; + } + } + if (data.target) { + // TODO: cannot call .dispatchEvent + // need to first figure out how to implement EventTarget + } + } + return event; + }; + try { + var ev = createEvent({type:"abort",target:document}); + return function ProgressEvent(type, data) { + data.type = type; + return createEvent(data); + }; + } catch(e){ + */ + return function ProgressEvent(type, dict) { + this.type = type; + this.bubbles = false; + this.cancelBubble = false; + this.cancelable = false; + this.lengthComputable = false; + this.loaded = dict && dict.loaded ? dict.loaded : 0; + this.total = dict && dict.total ? dict.total : 0; + this.target = dict && dict.target ? dict.target : null; + }; + //} +})(); + +module.exports = ProgressEvent; + +}); + +// file: lib/common/plugin/accelerometer.js +define("cordova/plugin/accelerometer", function(require, exports, module) { + +/** + * This class provides access to device accelerometer data. + * @constructor + */ +var argscheck = require('cordova/argscheck'), + utils = require("cordova/utils"), + exec = require("cordova/exec"), + Acceleration = require('cordova/plugin/Acceleration'); + +// Is the accel sensor running? +var running = false; + +// Keeps reference to watchAcceleration calls. +var timers = {}; + +// Array of listeners; used to keep track of when we should call start and stop. +var listeners = []; + +// Last returned acceleration object from native +var accel = null; + +// Tells native to start. +function start() { + exec(function(a) { + var tempListeners = listeners.slice(0); + accel = new Acceleration(a.x, a.y, a.z, a.timestamp); + for (var i = 0, l = tempListeners.length; i < l; i++) { + tempListeners[i].win(accel); + } + }, function(e) { + var tempListeners = listeners.slice(0); + for (var i = 0, l = tempListeners.length; i < l; i++) { + tempListeners[i].fail(e); + } + }, "Accelerometer", "start", []); + running = true; +} + +// Tells native to stop. +function stop() { + exec(null, null, "Accelerometer", "stop", []); + running = false; +} + +// Adds a callback pair to the listeners array +function createCallbackPair(win, fail) { + return {win:win, fail:fail}; +} + +// Removes a win/fail listener pair from the listeners array +function removeListeners(l) { + var idx = listeners.indexOf(l); + if (idx > -1) { + listeners.splice(idx, 1); + if (listeners.length === 0) { + stop(); + } + } +} + +var accelerometer = { + /** + * Asynchronously acquires the current acceleration. + * + * @param {Function} successCallback The function to call when the acceleration data is available + * @param {Function} errorCallback The function to call when there is an error getting the acceleration data. (OPTIONAL) + * @param {AccelerationOptions} options The options for getting the accelerometer data such as timeout. (OPTIONAL) + */ + getCurrentAcceleration: function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'accelerometer.getCurrentAcceleration', arguments); + + var p; + var win = function(a) { + removeListeners(p); + successCallback(a); + }; + var fail = function(e) { + removeListeners(p); + errorCallback && errorCallback(e); + }; + + p = createCallbackPair(win, fail); + listeners.push(p); + + if (!running) { + start(); + } + }, + + /** + * Asynchronously acquires the acceleration repeatedly at a given interval. + * + * @param {Function} successCallback The function to call each time the acceleration data is available + * @param {Function} errorCallback The function to call when there is an error getting the acceleration data. (OPTIONAL) + * @param {AccelerationOptions} options The options for getting the accelerometer data such as timeout. (OPTIONAL) + * @return String The watch id that must be passed to #clearWatch to stop watching. + */ + watchAcceleration: function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'accelerometer.watchAcceleration', arguments); + // Default interval (10 sec) + var frequency = (options && options.frequency && typeof options.frequency == 'number') ? options.frequency : 10000; + + // Keep reference to watch id, and report accel readings as often as defined in frequency + var id = utils.createUUID(); + + var p = createCallbackPair(function(){}, function(e) { + removeListeners(p); + errorCallback && errorCallback(e); + }); + listeners.push(p); + + timers[id] = { + timer:window.setInterval(function() { + if (accel) { + successCallback(accel); + } + }, frequency), + listeners:p + }; + + if (running) { + // If we're already running then immediately invoke the success callback + // but only if we have retrieved a value, sample code does not check for null ... + if (accel) { + successCallback(accel); + } + } else { + start(); + } + + return id; + }, + + /** + * Clears the specified accelerometer watch. + * + * @param {String} id The id of the watch returned from #watchAcceleration. + */ + clearWatch: function(id) { + // Stop javascript timer & remove from timer list + if (id && timers[id]) { + window.clearInterval(timers[id].timer); + removeListeners(timers[id].listeners); + delete timers[id]; + } + } +}; + +module.exports = accelerometer; + +}); + +// file: lib/common/plugin/accelerometer/symbols.js +define("cordova/plugin/accelerometer/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.defaults('cordova/plugin/Acceleration', 'Acceleration'); +modulemapper.defaults('cordova/plugin/accelerometer', 'navigator.accelerometer'); + +}); + +// file: lib/android/plugin/android/app.js +define("cordova/plugin/android/app", function(require, exports, module) { + +var exec = require('cordova/exec'); + +module.exports = { + /** + * Clear the resource cache. + */ + clearCache:function() { + exec(null, null, "App", "clearCache", []); + }, + + /** + * Load the url into the webview or into new browser instance. + * + * @param url The URL to load + * @param props Properties that can be passed in to the activity: + * wait: int => wait msec before loading URL + * loadingDialog: "Title,Message" => display a native loading dialog + * loadUrlTimeoutValue: int => time in msec to wait before triggering a timeout error + * clearHistory: boolean => clear webview history (default=false) + * openExternal: boolean => open in a new browser (default=false) + * + * Example: + * navigator.app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000}); + */ + loadUrl:function(url, props) { + exec(null, null, "App", "loadUrl", [url, props]); + }, + + /** + * Cancel loadUrl that is waiting to be loaded. + */ + cancelLoadUrl:function() { + exec(null, null, "App", "cancelLoadUrl", []); + }, + + /** + * Clear web history in this web view. + * Instead of BACK button loading the previous web page, it will exit the app. + */ + clearHistory:function() { + exec(null, null, "App", "clearHistory", []); + }, + + /** + * Go to previous page displayed. + * This is the same as pressing the backbutton on Android device. + */ + backHistory:function() { + exec(null, null, "App", "backHistory", []); + }, + + /** + * Override the default behavior of the Android back button. + * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired. + * + * Note: The user should not have to call this method. Instead, when the user + * registers for the "backbutton" event, this is automatically done. + * + * @param override T=override, F=cancel override + */ + overrideBackbutton:function(override) { + exec(null, null, "App", "overrideBackbutton", [override]); + }, + + /** + * Exit and terminate the application. + */ + exitApp:function() { + return exec(null, null, "App", "exitApp", []); + } +}; + +}); + +// file: lib/android/plugin/android/device.js +define("cordova/plugin/android/device", function(require, exports, module) { + +var channel = require('cordova/channel'), + utils = require('cordova/utils'), + exec = require('cordova/exec'), + app = require('cordova/plugin/android/app'); + +module.exports = { + /* + * DEPRECATED + * This is only for Android. + * + * You must explicitly override the back button. + */ + overrideBackButton:function() { + console.log("Device.overrideBackButton() is deprecated. Use App.overrideBackbutton(true)."); + app.overrideBackbutton(true); + }, + + /* + * DEPRECATED + * This is only for Android. + * + * This resets the back button to the default behavior + */ + resetBackButton:function() { + console.log("Device.resetBackButton() is deprecated. Use App.overrideBackbutton(false)."); + app.overrideBackbutton(false); + }, + + /* + * DEPRECATED + * This is only for Android. + * + * This terminates the activity! + */ + exitApp:function() { + console.log("Device.exitApp() is deprecated. Use App.exitApp()."); + app.exitApp(); + } +}; + +}); + +// file: lib/android/plugin/android/nativeapiprovider.js +define("cordova/plugin/android/nativeapiprovider", function(require, exports, module) { + +var nativeApi = this._cordovaNative || require('cordova/plugin/android/promptbasednativeapi'); +var currentApi = nativeApi; + +module.exports = { + get: function() { return currentApi; }, + setPreferPrompt: function(value) { + currentApi = value ? require('cordova/plugin/android/promptbasednativeapi') : nativeApi; + }, + // Used only by tests. + set: function(value) { + currentApi = value; + } +}; + +}); + +// file: lib/android/plugin/android/notification.js +define("cordova/plugin/android/notification", function(require, exports, module) { + +var exec = require('cordova/exec'); + +/** + * Provides Android enhanced notification API. + */ +module.exports = { + activityStart : function(title, message) { + // If title and message not specified then mimic Android behavior of + // using default strings. + if (typeof title === "undefined" && typeof message == "undefined") { + title = "Busy"; + message = 'Please wait...'; + } + + exec(null, null, 'Notification', 'activityStart', [ title, message ]); + }, + + /** + * Close an activity dialog + */ + activityStop : function() { + exec(null, null, 'Notification', 'activityStop', []); + }, + + /** + * Display a progress dialog with progress bar that goes from 0 to 100. + * + * @param {String} + * title Title of the progress dialog. + * @param {String} + * message Message to display in the dialog. + */ + progressStart : function(title, message) { + exec(null, null, 'Notification', 'progressStart', [ title, message ]); + }, + + /** + * Close the progress dialog. + */ + progressStop : function() { + exec(null, null, 'Notification', 'progressStop', []); + }, + + /** + * Set the progress dialog value. + * + * @param {Number} + * value 0-100 + */ + progressValue : function(value) { + exec(null, null, 'Notification', 'progressValue', [ value ]); + } +}; + +}); + +// file: lib/android/plugin/android/promptbasednativeapi.js +define("cordova/plugin/android/promptbasednativeapi", function(require, exports, module) { + +module.exports = { + exec: function(service, action, callbackId, argsJson) { + return prompt(argsJson, 'gap:'+JSON.stringify([service, action, callbackId])); + }, + setNativeToJsBridgeMode: function(value) { + prompt(value, 'gap_bridge_mode:'); + }, + retrieveJsMessages: function() { + return prompt('', 'gap_poll:'); + } +}; + +}); + +// file: lib/android/plugin/android/storage.js +define("cordova/plugin/android/storage", function(require, exports, module) { + +var utils = require('cordova/utils'), + exec = require('cordova/exec'), + channel = require('cordova/channel'); + +var queryQueue = {}; + +/** + * SQL result set object + * PRIVATE METHOD + * @constructor + */ +var DroidDB_Rows = function() { + this.resultSet = []; // results array + this.length = 0; // number of rows +}; + +/** + * Get item from SQL result set + * + * @param row The row number to return + * @return The row object + */ +DroidDB_Rows.prototype.item = function(row) { + return this.resultSet[row]; +}; + +/** + * SQL result set that is returned to user. + * PRIVATE METHOD + * @constructor + */ +var DroidDB_Result = function() { + this.rows = new DroidDB_Rows(); +}; + +/** + * Callback from native code when query is complete. + * PRIVATE METHOD + * + * @param id Query id + */ +function completeQuery(id, data) { + var query = queryQueue[id]; + if (query) { + try { + delete queryQueue[id]; + + // Get transaction + var tx = query.tx; + + // If transaction hasn't failed + // Note: We ignore all query results if previous query + // in the same transaction failed. + if (tx && tx.queryList[id]) { + + // Save query results + var r = new DroidDB_Result(); + r.rows.resultSet = data; + r.rows.length = data.length; + try { + if (typeof query.successCallback === 'function') { + query.successCallback(query.tx, r); + } + } catch (ex) { + console.log("executeSql error calling user success callback: "+ex); + } + + tx.queryComplete(id); + } + } catch (e) { + console.log("executeSql error: "+e); + } + } +} + +/** + * Callback from native code when query fails + * PRIVATE METHOD + * + * @param reason Error message + * @param id Query id + */ +function failQuery(reason, id) { + var query = queryQueue[id]; + if (query) { + try { + delete queryQueue[id]; + + // Get transaction + var tx = query.tx; + + // If transaction hasn't failed + // Note: We ignore all query results if previous query + // in the same transaction failed. + if (tx && tx.queryList[id]) { + tx.queryList = {}; + + try { + if (typeof query.errorCallback === 'function') { + query.errorCallback(query.tx, reason); + } + } catch (ex) { + console.log("executeSql error calling user error callback: "+ex); + } + + tx.queryFailed(id, reason); + } + + } catch (e) { + console.log("executeSql error: "+e); + } + } +} + +/** + * SQL query object + * PRIVATE METHOD + * + * @constructor + * @param tx The transaction object that this query belongs to + */ +var DroidDB_Query = function(tx) { + + // Set the id of the query + this.id = utils.createUUID(); + + // Add this query to the queue + queryQueue[this.id] = this; + + // Init result + this.resultSet = []; + + // Set transaction that this query belongs to + this.tx = tx; + + // Add this query to transaction list + this.tx.queryList[this.id] = this; + + // Callbacks + this.successCallback = null; + this.errorCallback = null; + +}; + +/** + * Transaction object + * PRIVATE METHOD + * @constructor + */ +var DroidDB_Tx = function() { + + // Set the id of the transaction + this.id = utils.createUUID(); + + // Callbacks + this.successCallback = null; + this.errorCallback = null; + + // Query list + this.queryList = {}; +}; + +/** + * Mark query in transaction as complete. + * If all queries are complete, call the user's transaction success callback. + * + * @param id Query id + */ +DroidDB_Tx.prototype.queryComplete = function(id) { + delete this.queryList[id]; + + // If no more outstanding queries, then fire transaction success + if (this.successCallback) { + var count = 0; + var i; + for (i in this.queryList) { + if (this.queryList.hasOwnProperty(i)) { + count++; + } + } + if (count === 0) { + try { + this.successCallback(); + } catch(e) { + console.log("Transaction error calling user success callback: " + e); + } + } + } +}; + +/** + * Mark query in transaction as failed. + * + * @param id Query id + * @param reason Error message + */ +DroidDB_Tx.prototype.queryFailed = function(id, reason) { + + // The sql queries in this transaction have already been run, since + // we really don't have a real transaction implemented in native code. + // However, the user callbacks for the remaining sql queries in transaction + // will not be called. + this.queryList = {}; + + if (this.errorCallback) { + try { + this.errorCallback(reason); + } catch(e) { + console.log("Transaction error calling user error callback: " + e); + } + } +}; + +/** + * Execute SQL statement + * + * @param sql SQL statement to execute + * @param params Statement parameters + * @param successCallback Success callback + * @param errorCallback Error callback + */ +DroidDB_Tx.prototype.executeSql = function(sql, params, successCallback, errorCallback) { + + // Init params array + if (typeof params === 'undefined') { + params = []; + } + + // Create query and add to queue + var query = new DroidDB_Query(this); + queryQueue[query.id] = query; + + // Save callbacks + query.successCallback = successCallback; + query.errorCallback = errorCallback; + + // Call native code + exec(null, null, "Storage", "executeSql", [sql, params, query.id]); +}; + +var DatabaseShell = function() { +}; + +/** + * Start a transaction. + * Does not support rollback in event of failure. + * + * @param process {Function} The transaction function + * @param successCallback {Function} + * @param errorCallback {Function} + */ +DatabaseShell.prototype.transaction = function(process, errorCallback, successCallback) { + var tx = new DroidDB_Tx(); + tx.successCallback = successCallback; + tx.errorCallback = errorCallback; + try { + process(tx); + } catch (e) { + console.log("Transaction error: "+e); + if (tx.errorCallback) { + try { + tx.errorCallback(e); + } catch (ex) { + console.log("Transaction error calling user error callback: "+e); + } + } + } +}; + +/** + * Open database + * + * @param name Database name + * @param version Database version + * @param display_name Database display name + * @param size Database size in bytes + * @return Database object + */ +var DroidDB_openDatabase = function(name, version, display_name, size) { + exec(null, null, "Storage", "openDatabase", [name, version, display_name, size]); + var db = new DatabaseShell(); + return db; +}; + + +module.exports = { + openDatabase:DroidDB_openDatabase, + failQuery:failQuery, + completeQuery:completeQuery +}; + +}); + +// file: lib/android/plugin/android/storage/openDatabase.js +define("cordova/plugin/android/storage/openDatabase", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'), + storage = require('cordova/plugin/android/storage'); + +var originalOpenDatabase = modulemapper.getOriginalSymbol(window, 'openDatabase'); + +module.exports = function(name, version, desc, size) { + // First patch WebSQL if necessary + if (!originalOpenDatabase) { + // Not defined, create an openDatabase function for all to use! + return storage.openDatabase.apply(this, arguments); + } + + // Defined, but some Android devices will throw a SECURITY_ERR - + // so we wrap the whole thing in a try-catch and shim in our own + // if the device has Android bug 16175. + try { + return originalOpenDatabase(name, version, desc, size); + } catch (ex) { + if (ex.code !== 18) { + throw ex; + } + } + return storage.openDatabase(name, version, desc, size); +}; + + + +}); + +// file: lib/android/plugin/android/storage/symbols.js +define("cordova/plugin/android/storage/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/android/storage/openDatabase', 'openDatabase'); + + +}); + +// file: lib/common/plugin/battery.js +define("cordova/plugin/battery", function(require, exports, module) { + +/** + * This class contains information about the current battery status. + * @constructor + */ +var cordova = require('cordova'), + exec = require('cordova/exec'); + +function handlers() { + return battery.channels.batterystatus.numHandlers + + battery.channels.batterylow.numHandlers + + battery.channels.batterycritical.numHandlers; +} + +var Battery = function() { + this._level = null; + this._isPlugged = null; + // Create new event handlers on the window (returns a channel instance) + this.channels = { + batterystatus:cordova.addWindowEventHandler("batterystatus"), + batterylow:cordova.addWindowEventHandler("batterylow"), + batterycritical:cordova.addWindowEventHandler("batterycritical") + }; + for (var key in this.channels) { + this.channels[key].onHasSubscribersChange = Battery.onHasSubscribersChange; + } +}; +/** + * Event handlers for when callbacks get registered for the battery. + * Keep track of how many handlers we have so we can start and stop the native battery listener + * appropriately (and hopefully save on battery life!). + */ +Battery.onHasSubscribersChange = function() { + // If we just registered the first handler, make sure native listener is started. + if (this.numHandlers === 1 && handlers() === 1) { + exec(battery._status, battery._error, "Battery", "start", []); + } else if (handlers() === 0) { + exec(null, null, "Battery", "stop", []); + } +}; + +/** + * Callback for battery status + * + * @param {Object} info keys: level, isPlugged + */ +Battery.prototype._status = function(info) { + if (info) { + var me = battery; + var level = info.level; + if (me._level !== level || me._isPlugged !== info.isPlugged) { + // Fire batterystatus event + cordova.fireWindowEvent("batterystatus", info); + + // Fire low battery event + if (level === 20 || level === 5) { + if (level === 20) { + cordova.fireWindowEvent("batterylow", info); + } + else { + cordova.fireWindowEvent("batterycritical", info); + } + } + } + me._level = level; + me._isPlugged = info.isPlugged; + } +}; + +/** + * Error callback for battery start + */ +Battery.prototype._error = function(e) { + console.log("Error initializing Battery: " + e); +}; + +var battery = new Battery(); + +module.exports = battery; + +}); + +// file: lib/common/plugin/battery/symbols.js +define("cordova/plugin/battery/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.defaults('cordova/plugin/battery', 'navigator.battery'); + +}); + +// file: lib/common/plugin/camera/symbols.js +define("cordova/plugin/camera/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.defaults('cordova/plugin/Camera', 'navigator.camera'); +modulemapper.defaults('cordova/plugin/CameraConstants', 'Camera'); +modulemapper.defaults('cordova/plugin/CameraPopoverOptions', 'CameraPopoverOptions'); + +}); + +// file: lib/common/plugin/capture.js +define("cordova/plugin/capture", function(require, exports, module) { + +var exec = require('cordova/exec'), + MediaFile = require('cordova/plugin/MediaFile'); + +/** + * Launches a capture of different types. + * + * @param (DOMString} type + * @param {Function} successCB + * @param {Function} errorCB + * @param {CaptureVideoOptions} options + */ +function _capture(type, successCallback, errorCallback, options) { + var win = function(pluginResult) { + var mediaFiles = []; + var i; + for (i = 0; i < pluginResult.length; i++) { + var mediaFile = new MediaFile(); + mediaFile.name = pluginResult[i].name; + mediaFile.fullPath = pluginResult[i].fullPath; + mediaFile.type = pluginResult[i].type; + mediaFile.lastModifiedDate = pluginResult[i].lastModifiedDate; + mediaFile.size = pluginResult[i].size; + mediaFiles.push(mediaFile); + } + successCallback(mediaFiles); + }; + exec(win, errorCallback, "Capture", type, [options]); +} +/** + * 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 + */ +Capture.prototype.captureAudio = function(successCallback, errorCallback, options){ + _capture("captureAudio", successCallback, errorCallback, options); +}; + +/** + * Launch camera application for taking image(s). + * + * @param {Function} successCB + * @param {Function} errorCB + * @param {CaptureImageOptions} options + */ +Capture.prototype.captureImage = function(successCallback, errorCallback, options){ + _capture("captureImage", successCallback, errorCallback, options); +}; + +/** + * Launch device camera application for recording video(s). + * + * @param {Function} successCB + * @param {Function} errorCB + * @param {CaptureVideoOptions} options + */ +Capture.prototype.captureVideo = function(successCallback, errorCallback, options){ + _capture("captureVideo", successCallback, errorCallback, options); +}; + + +module.exports = new Capture(); + +}); + +// file: lib/common/plugin/capture/symbols.js +define("cordova/plugin/capture/symbols", function(require, exports, module) { + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/CaptureError', 'CaptureError'); +modulemapper.clobbers('cordova/plugin/CaptureAudioOptions', 'CaptureAudioOptions'); +modulemapper.clobbers('cordova/plugin/CaptureImageOptions', 'CaptureImageOptions'); +modulemapper.clobbers('cordova/plugin/CaptureVideoOptions', 'CaptureVideoOptions'); +modulemapper.clobbers('cordova/plugin/ConfigurationData', 'ConfigurationData'); +modulemapper.clobbers('cordova/plugin/MediaFile', 'MediaFile'); +modulemapper.clobbers('cordova/plugin/MediaFileData', 'MediaFileData'); +modulemapper.clobbers('cordova/plugin/capture', 'navigator.device.capture'); + +}); + +// file: lib/common/plugin/compass.js +define("cordova/plugin/compass", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + utils = require('cordova/utils'), + CompassHeading = require('cordova/plugin/CompassHeading'), + CompassError = require('cordova/plugin/CompassError'), + timers = {}, + compass = { + /** + * Asynchronously acquires the current heading. + * @param {Function} successCallback The function to call when the heading + * data is available + * @param {Function} errorCallback The function to call when there is an error + * getting the heading data. + * @param {CompassOptions} options The options for getting the heading data (not used). + */ + getCurrentHeading:function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'compass.getCurrentHeading', arguments); + + var win = function(result) { + var ch = new CompassHeading(result.magneticHeading, result.trueHeading, result.headingAccuracy, result.timestamp); + successCallback(ch); + }; + var fail = errorCallback && function(code) { + var ce = new CompassError(code); + errorCallback(ce); + }; + + // Get heading + exec(win, fail, "Compass", "getHeading", [options]); + }, + + /** + * Asynchronously acquires the heading repeatedly at a given interval. + * @param {Function} successCallback The function to call each time the heading + * data is available + * @param {Function} errorCallback The function to call when there is an error + * getting the heading data. + * @param {HeadingOptions} options The options for getting the heading data + * such as timeout and the frequency of the watch. For iOS, filter parameter + * specifies to watch via a distance filter rather than time. + */ + watchHeading:function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'compass.watchHeading', arguments); + // Default interval (100 msec) + var frequency = (options !== undefined && options.frequency !== undefined) ? options.frequency : 100; + var filter = (options !== undefined && options.filter !== undefined) ? options.filter : 0; + + var id = utils.createUUID(); + if (filter > 0) { + // is an iOS request for watch by filter, no timer needed + timers[id] = "iOS"; + compass.getCurrentHeading(successCallback, errorCallback, options); + } else { + // Start watch timer to get headings + timers[id] = window.setInterval(function() { + compass.getCurrentHeading(successCallback, errorCallback); + }, frequency); + } + + return id; + }, + + /** + * Clears the specified heading watch. + * @param {String} watchId The ID of the watch returned from #watchHeading. + */ + clearWatch:function(id) { + // Stop javascript timer & remove from timer list + if (id && timers[id]) { + if (timers[id] != "iOS") { + clearInterval(timers[id]); + } else { + // is iOS watch by filter so call into device to stop + exec(null, null, "Compass", "stopHeading", []); + } + delete timers[id]; + } + } + }; + +module.exports = compass; + +}); + +// file: lib/common/plugin/compass/symbols.js +define("cordova/plugin/compass/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/CompassHeading', 'CompassHeading'); +modulemapper.clobbers('cordova/plugin/CompassError', 'CompassError'); +modulemapper.clobbers('cordova/plugin/compass', 'navigator.compass'); + +}); + +// file: lib/common/plugin/console-via-logger.js +define("cordova/plugin/console-via-logger", function(require, exports, module) { + +//------------------------------------------------------------------------------ + +var logger = require("cordova/plugin/logger"); +var utils = require("cordova/utils"); + +//------------------------------------------------------------------------------ +// object that we're exporting +//------------------------------------------------------------------------------ +var console = module.exports; + +//------------------------------------------------------------------------------ +// copy of the original console object +//------------------------------------------------------------------------------ +var WinConsole = window.console; + +//------------------------------------------------------------------------------ +// whether to use the logger +//------------------------------------------------------------------------------ +var UseLogger = false; + +//------------------------------------------------------------------------------ +// Timers +//------------------------------------------------------------------------------ +var Timers = {}; + +//------------------------------------------------------------------------------ +// used for unimplemented methods +//------------------------------------------------------------------------------ +function noop() {} + +//------------------------------------------------------------------------------ +// used for unimplemented methods +//------------------------------------------------------------------------------ +console.useLogger = function (value) { + if (arguments.length) UseLogger = !!value; + + if (UseLogger) { + if (logger.useConsole()) { + throw new Error("console and logger are too intertwingly"); + } + } + + return UseLogger; +}; + +//------------------------------------------------------------------------------ +console.log = function() { + if (logger.useConsole()) return; + logger.log.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.error = function() { + if (logger.useConsole()) return; + logger.error.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.warn = function() { + if (logger.useConsole()) return; + logger.warn.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.info = function() { + if (logger.useConsole()) return; + logger.info.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.debug = function() { + if (logger.useConsole()) return; + logger.debug.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.assert = function(expression) { + if (expression) return; + + var message = utils.vformat(arguments[1], [].slice.call(arguments, 2)); + console.log("ASSERT: " + message); +}; + +//------------------------------------------------------------------------------ +console.clear = function() {}; + +//------------------------------------------------------------------------------ +console.dir = function(object) { + console.log("%o", object); +}; + +//------------------------------------------------------------------------------ +console.dirxml = function(node) { + console.log(node.innerHTML); +}; + +//------------------------------------------------------------------------------ +console.trace = noop; + +//------------------------------------------------------------------------------ +console.group = console.log; + +//------------------------------------------------------------------------------ +console.groupCollapsed = console.log; + +//------------------------------------------------------------------------------ +console.groupEnd = noop; + +//------------------------------------------------------------------------------ +console.time = function(name) { + Timers[name] = new Date().valueOf(); +}; + +//------------------------------------------------------------------------------ +console.timeEnd = function(name) { + var timeStart = Timers[name]; + if (!timeStart) { + console.warn("unknown timer: " + name); + return; + } + + var timeElapsed = new Date().valueOf() - timeStart; + console.log(name + ": " + timeElapsed + "ms"); +}; + +//------------------------------------------------------------------------------ +console.timeStamp = noop; + +//------------------------------------------------------------------------------ +console.profile = noop; + +//------------------------------------------------------------------------------ +console.profileEnd = noop; + +//------------------------------------------------------------------------------ +console.count = noop; + +//------------------------------------------------------------------------------ +console.exception = console.log; + +//------------------------------------------------------------------------------ +console.table = function(data, columns) { + console.log("%o", data); +}; + +//------------------------------------------------------------------------------ +// return a new function that calls both functions passed as args +//------------------------------------------------------------------------------ +function wrappedOrigCall(orgFunc, newFunc) { + return function() { + var args = [].slice.call(arguments); + try { orgFunc.apply(WinConsole, args); } catch (e) {} + try { newFunc.apply(console, args); } catch (e) {} + }; +} + +//------------------------------------------------------------------------------ +// For every function that exists in the original console object, that +// also exists in the new console object, wrap the new console method +// with one that calls both +//------------------------------------------------------------------------------ +for (var key in console) { + if (typeof WinConsole[key] == "function") { + console[key] = wrappedOrigCall(WinConsole[key], console[key]); + } +} + +}); + +// file: lib/common/plugin/contacts.js +define("cordova/plugin/contacts", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + ContactError = require('cordova/plugin/ContactError'), + utils = require('cordova/utils'), + Contact = require('cordova/plugin/Contact'); + +/** +* Represents a group of Contacts. +* @constructor +*/ +var contacts = { + /** + * Returns an array of Contacts matching the search criteria. + * @param fields that should be searched + * @param successCB success callback + * @param errorCB error callback + * @param {ContactFindOptions} options that can be applied to contact searching + * @return array of Contacts matching search criteria + */ + find:function(fields, successCB, errorCB, options) { + argscheck.checkArgs('afFO', 'contacts.find', arguments); + if (!fields.length) { + errorCB && errorCB(new ContactError(ContactError.INVALID_ARGUMENT_ERROR)); + } else { + var win = function(result) { + var cs = []; + for (var i = 0, l = result.length; i < l; i++) { + cs.push(contacts.create(result[i])); + } + successCB(cs); + }; + exec(win, errorCB, "Contacts", "search", [fields, options]); + } + }, + + /** + * This function creates a new contact, but it does not persist the contact + * to device storage. To persist the contact to device storage, invoke + * contact.save(). + * @param properties an object whose properties will be examined to create a new Contact + * @returns new Contact object + */ + create:function(properties) { + argscheck.checkArgs('O', 'contacts.create', arguments); + var contact = new Contact(); + for (var i in properties) { + if (typeof contact[i] !== 'undefined' && properties.hasOwnProperty(i)) { + contact[i] = properties[i]; + } + } + return contact; + } +}; + +module.exports = contacts; + +}); + +// file: lib/common/plugin/contacts/symbols.js +define("cordova/plugin/contacts/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/contacts', 'navigator.contacts'); +modulemapper.clobbers('cordova/plugin/Contact', 'Contact'); +modulemapper.clobbers('cordova/plugin/ContactAddress', 'ContactAddress'); +modulemapper.clobbers('cordova/plugin/ContactError', 'ContactError'); +modulemapper.clobbers('cordova/plugin/ContactField', 'ContactField'); +modulemapper.clobbers('cordova/plugin/ContactFindOptions', 'ContactFindOptions'); +modulemapper.clobbers('cordova/plugin/ContactName', 'ContactName'); +modulemapper.clobbers('cordova/plugin/ContactOrganization', 'ContactOrganization'); + +}); + +// file: lib/common/plugin/device.js +define("cordova/plugin/device", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + channel = require('cordova/channel'), + utils = require('cordova/utils'), + exec = require('cordova/exec'); + +// Tell cordova channel to wait on the CordovaInfoReady event +channel.waitForInitialization('onCordovaInfoReady'); + +/** + * This represents the mobile device, and provides properties for inspecting the model, version, UUID of the + * phone, etc. + * @constructor + */ +function Device() { + this.available = false; + this.platform = null; + this.version = null; + this.name = null; + this.uuid = null; + this.cordova = null; + this.model = null; + + var me = this; + + channel.onCordovaReady.subscribe(function() { + me.getInfo(function(info) { + me.available = true; + me.platform = info.platform; + me.version = info.version; + me.name = info.name; + me.uuid = info.uuid; + me.cordova = info.cordova; + me.model = info.model; + channel.onCordovaInfoReady.fire(); + },function(e) { + me.available = false; + utils.alert("[ERROR] Error initializing Cordova: " + e); + }); + }); +} + +/** + * Get device info + * + * @param {Function} successCallback The function to call when the heading data is available + * @param {Function} errorCallback The function to call when there is an error getting the heading data. (OPTIONAL) + */ +Device.prototype.getInfo = function(successCallback, errorCallback) { + argscheck.checkArgs('fF', 'Device.getInfo', arguments); + exec(successCallback, errorCallback, "Device", "getDeviceInfo", []); +}; + +module.exports = new Device(); + +}); + +// file: lib/android/plugin/device/symbols.js +define("cordova/plugin/device/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/device', 'device'); +modulemapper.merges('cordova/plugin/android/device', 'device'); + +}); + +// file: lib/common/plugin/echo.js +define("cordova/plugin/echo", function(require, exports, module) { + +var exec = require('cordova/exec'); + +/** + * Sends the given message through exec() to the Echo plugin, which sends it back to the successCallback. + * @param successCallback invoked with a FileSystem object + * @param errorCallback invoked if error occurs retrieving file system + * @param message The string to be echoed. + * @param forceAsync Whether to force an async return value (for testing native->js bridge). + */ +module.exports = function(successCallback, errorCallback, message, forceAsync) { + var action = forceAsync ? 'echoAsync' : 'echo'; + if (!forceAsync && message.constructor == ArrayBuffer) { + action = 'echoArrayBuffer'; + } + exec(successCallback, errorCallback, "Echo", action, [message]); +}; + + +}); + +// file: lib/android/plugin/file/symbols.js +define("cordova/plugin/file/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'), + symbolshelper = require('cordova/plugin/file/symbolshelper'); + +symbolshelper(modulemapper.clobbers); + +}); + +// file: lib/common/plugin/file/symbolshelper.js +define("cordova/plugin/file/symbolshelper", function(require, exports, module) { + +module.exports = function(exportFunc) { + exportFunc('cordova/plugin/DirectoryEntry', 'DirectoryEntry'); + exportFunc('cordova/plugin/DirectoryReader', 'DirectoryReader'); + exportFunc('cordova/plugin/Entry', 'Entry'); + exportFunc('cordova/plugin/File', 'File'); + exportFunc('cordova/plugin/FileEntry', 'FileEntry'); + exportFunc('cordova/plugin/FileError', 'FileError'); + exportFunc('cordova/plugin/FileReader', 'FileReader'); + exportFunc('cordova/plugin/FileSystem', 'FileSystem'); + exportFunc('cordova/plugin/FileUploadOptions', 'FileUploadOptions'); + exportFunc('cordova/plugin/FileUploadResult', 'FileUploadResult'); + exportFunc('cordova/plugin/FileWriter', 'FileWriter'); + exportFunc('cordova/plugin/Flags', 'Flags'); + exportFunc('cordova/plugin/LocalFileSystem', 'LocalFileSystem'); + exportFunc('cordova/plugin/Metadata', 'Metadata'); + exportFunc('cordova/plugin/ProgressEvent', 'ProgressEvent'); + exportFunc('cordova/plugin/requestFileSystem', 'requestFileSystem'); + exportFunc('cordova/plugin/resolveLocalFileSystemURI', 'resolveLocalFileSystemURI'); +}; + +}); + +// file: lib/common/plugin/filetransfer/symbols.js +define("cordova/plugin/filetransfer/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/FileTransfer', 'FileTransfer'); +modulemapper.clobbers('cordova/plugin/FileTransferError', 'FileTransferError'); + +}); + +// file: lib/common/plugin/geolocation.js +define("cordova/plugin/geolocation", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + utils = require('cordova/utils'), + exec = require('cordova/exec'), + PositionError = require('cordova/plugin/PositionError'), + Position = require('cordova/plugin/Position'); + +var timers = {}; // list of timers in use + +// Returns default params, overrides if provided with values +function parseParameters(options) { + var opt = { + maximumAge: 0, + enableHighAccuracy: false, + timeout: Infinity + }; + + if (options) { + if (options.maximumAge !== undefined && !isNaN(options.maximumAge) && options.maximumAge > 0) { + opt.maximumAge = options.maximumAge; + } + if (options.enableHighAccuracy !== undefined) { + opt.enableHighAccuracy = options.enableHighAccuracy; + } + if (options.timeout !== undefined && !isNaN(options.timeout)) { + if (options.timeout < 0) { + opt.timeout = 0; + } else { + opt.timeout = options.timeout; + } + } + } + + return opt; +} + +// Returns a timeout failure, closed over a specified timeout value and error callback. +function createTimeout(errorCallback, timeout) { + var t = setTimeout(function() { + clearTimeout(t); + t = null; + errorCallback({ + code:PositionError.TIMEOUT, + message:"Position retrieval timed out." + }); + }, timeout); + return t; +} + +var geolocation = { + lastPosition:null, // reference to last known (cached) position returned + /** + * Asynchronously acquires the current position. + * + * @param {Function} successCallback The function to call when the position data is available + * @param {Function} errorCallback The function to call when there is an error getting the heading position. (OPTIONAL) + * @param {PositionOptions} options The options for getting the position data. (OPTIONAL) + */ + getCurrentPosition:function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'geolocation.getCurrentPosition', arguments); + options = parseParameters(options); + + // Timer var that will fire an error callback if no position is retrieved from native + // before the "timeout" param provided expires + var timeoutTimer = {timer:null}; + + var win = function(p) { + clearTimeout(timeoutTimer.timer); + if (!(timeoutTimer.timer)) { + // Timeout already happened, or native fired error callback for + // this geo request. + // Don't continue with success callback. + return; + } + var pos = new Position( + { + latitude:p.latitude, + longitude:p.longitude, + altitude:p.altitude, + accuracy:p.accuracy, + heading:p.heading, + velocity:p.velocity, + altitudeAccuracy:p.altitudeAccuracy + }, + (p.timestamp === undefined ? new Date() : ((p.timestamp instanceof Date) ? p.timestamp : new Date(p.timestamp))) + ); + geolocation.lastPosition = pos; + successCallback(pos); + }; + var fail = function(e) { + clearTimeout(timeoutTimer.timer); + timeoutTimer.timer = null; + var err = new PositionError(e.code, e.message); + if (errorCallback) { + errorCallback(err); + } + }; + + // Check our cached position, if its timestamp difference with current time is less than the maximumAge, then just + // fire the success callback with the cached position. + if (geolocation.lastPosition && options.maximumAge && (((new Date()).getTime() - geolocation.lastPosition.timestamp.getTime()) <= options.maximumAge)) { + successCallback(geolocation.lastPosition); + // If the cached position check failed and the timeout was set to 0, error out with a TIMEOUT error object. + } else if (options.timeout === 0) { + fail({ + code:PositionError.TIMEOUT, + message:"timeout value in PositionOptions set to 0 and no cached Position object available, or cached Position object's age exceeds provided PositionOptions' maximumAge parameter." + }); + // Otherwise we have to call into native to retrieve a position. + } else { + if (options.timeout !== Infinity) { + // If the timeout value was not set to Infinity (default), then + // set up a timeout function that will fire the error callback + // if no successful position was retrieved before timeout expired. + timeoutTimer.timer = createTimeout(fail, options.timeout); + } else { + // This is here so the check in the win function doesn't mess stuff up + // may seem weird but this guarantees timeoutTimer is + // always truthy before we call into native + timeoutTimer.timer = true; + } + exec(win, fail, "Geolocation", "getLocation", [options.enableHighAccuracy, options.maximumAge]); + } + return timeoutTimer; + }, + /** + * Asynchronously watches the geolocation for changes to geolocation. When a change occurs, + * the successCallback is called with the new location. + * + * @param {Function} successCallback The function to call each time the location data is available + * @param {Function} errorCallback The function to call when there is an error getting the location data. (OPTIONAL) + * @param {PositionOptions} options The options for getting the location data such as frequency. (OPTIONAL) + * @return String The watch id that must be passed to #clearWatch to stop watching. + */ + watchPosition:function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'geolocation.getCurrentPosition', arguments); + options = parseParameters(options); + + var id = utils.createUUID(); + + // Tell device to get a position ASAP, and also retrieve a reference to the timeout timer generated in getCurrentPosition + timers[id] = geolocation.getCurrentPosition(successCallback, errorCallback, options); + + var fail = function(e) { + clearTimeout(timers[id].timer); + var err = new PositionError(e.code, e.message); + if (errorCallback) { + errorCallback(err); + } + }; + + var win = function(p) { + clearTimeout(timers[id].timer); + if (options.timeout !== Infinity) { + timers[id].timer = createTimeout(fail, options.timeout); + } + var pos = new Position( + { + latitude:p.latitude, + longitude:p.longitude, + altitude:p.altitude, + accuracy:p.accuracy, + heading:p.heading, + velocity:p.velocity, + altitudeAccuracy:p.altitudeAccuracy + }, + (p.timestamp === undefined ? new Date() : ((p.timestamp instanceof Date) ? p.timestamp : new Date(p.timestamp))) + ); + geolocation.lastPosition = pos; + successCallback(pos); + }; + + exec(win, fail, "Geolocation", "addWatch", [id, options.enableHighAccuracy]); + + return id; + }, + /** + * Clears the specified heading watch. + * + * @param {String} id The ID of the watch returned from #watchPosition + */ + clearWatch:function(id) { + if (id && timers[id] !== undefined) { + clearTimeout(timers[id].timer); + timers[id].timer = false; + exec(null, null, "Geolocation", "clearWatch", [id]); + } + } +}; + +module.exports = geolocation; + +}); + +// file: lib/common/plugin/geolocation/symbols.js +define("cordova/plugin/geolocation/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.defaults('cordova/plugin/geolocation', 'navigator.geolocation'); +modulemapper.clobbers('cordova/plugin/PositionError', 'PositionError'); +modulemapper.clobbers('cordova/plugin/Position', 'Position'); +modulemapper.clobbers('cordova/plugin/Coordinates', 'Coordinates'); + +}); + +// file: lib/common/plugin/globalization.js +define("cordova/plugin/globalization", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + GlobalizationError = require('cordova/plugin/GlobalizationError'); + +var globalization = { + +/** +* Returns the string identifier for the client's current language. +* It returns the language identifier string to the successCB callback with a +* properties object as a parameter. If there is an error getting the language, +* then the errorCB callback is invoked. +* +* @param {Function} successCB +* @param {Function} errorCB +* +* @return Object.value {String}: The language identifier +* +* @error GlobalizationError.UNKNOWN_ERROR +* +* Example +* globalization.getPreferredLanguage(function (language) {alert('language:' + language.value + '\n');}, +* function () {}); +*/ +getPreferredLanguage:function(successCB, failureCB) { + argscheck.checkArgs('fF', 'Globalization.getPreferredLanguage', arguments); + exec(successCB, failureCB, "Globalization","getPreferredLanguage", []); +}, + +/** +* Returns the string identifier for the client's current locale setting. +* It returns the locale identifier string to the successCB callback with a +* properties object as a parameter. If there is an error getting the locale, +* then the errorCB callback is invoked. +* +* @param {Function} successCB +* @param {Function} errorCB +* +* @return Object.value {String}: The locale identifier +* +* @error GlobalizationError.UNKNOWN_ERROR +* +* Example +* globalization.getLocaleName(function (locale) {alert('locale:' + locale.value + '\n');}, +* function () {}); +*/ +getLocaleName:function(successCB, failureCB) { + argscheck.checkArgs('fF', 'Globalization.getLocaleName', arguments); + exec(successCB, failureCB, "Globalization","getLocaleName", []); +}, + + +/** +* Returns a date formatted as a string according to the client's user preferences and +* calendar using the time zone of the client. It returns the formatted date string to the +* successCB callback with a properties object as a parameter. If there is an error +* formatting the date, then the errorCB callback is invoked. +* +* The defaults are: formatLenght="short" and selector="date and time" +* +* @param {Date} date +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* formatLength {String}: 'short', 'medium', 'long', or 'full' +* selector {String}: 'date', 'time', or 'date and time' +* +* @return Object.value {String}: The localized date string +* +* @error GlobalizationError.FORMATTING_ERROR +* +* Example +* globalization.dateToString(new Date(), +* function (date) {alert('date:' + date.value + '\n');}, +* function (errorCode) {alert(errorCode);}, +* {formatLength:'short'}); +*/ +dateToString:function(date, successCB, failureCB, options) { + argscheck.checkArgs('dfFO', 'Globalization.dateToString', arguments); + var dateValue = date.valueOf(); + exec(successCB, failureCB, "Globalization", "dateToString", [{"date": dateValue, "options": options}]); +}, + + +/** +* Parses a date formatted as a string according to the client's user +* preferences and calendar using the time zone of the client and returns +* the corresponding date object. It returns the date to the successCB +* callback with a properties object as a parameter. If there is an error +* parsing the date string, then the errorCB callback is invoked. +* +* The defaults are: formatLength="short" and selector="date and time" +* +* @param {String} dateString +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* formatLength {String}: 'short', 'medium', 'long', or 'full' +* selector {String}: 'date', 'time', or 'date and time' +* +* @return Object.year {Number}: The four digit year +* Object.month {Number}: The month from (0 - 11) +* Object.day {Number}: The day from (1 - 31) +* Object.hour {Number}: The hour from (0 - 23) +* Object.minute {Number}: The minute from (0 - 59) +* Object.second {Number}: The second from (0 - 59) +* Object.millisecond {Number}: The milliseconds (from 0 - 999), +* not available on all platforms +* +* @error GlobalizationError.PARSING_ERROR +* +* Example +* globalization.stringToDate('4/11/2011', +* function (date) { alert('Month:' + date.month + '\n' + +* 'Day:' + date.day + '\n' + +* 'Year:' + date.year + '\n');}, +* function (errorCode) {alert(errorCode);}, +* {selector:'date'}); +*/ +stringToDate:function(dateString, successCB, failureCB, options) { + argscheck.checkArgs('sfFO', 'Globalization.stringToDate', arguments); + exec(successCB, failureCB, "Globalization", "stringToDate", [{"dateString": dateString, "options": options}]); +}, + + +/** +* Returns a pattern string for formatting and parsing dates according to the client's +* user preferences. It returns the pattern to the successCB callback with a +* properties object as a parameter. If there is an error obtaining the pattern, +* then the errorCB callback is invoked. +* +* The defaults are: formatLength="short" and selector="date and time" +* +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* formatLength {String}: 'short', 'medium', 'long', or 'full' +* selector {String}: 'date', 'time', or 'date and time' +* +* @return Object.pattern {String}: The date and time pattern for formatting and parsing dates. +* The patterns follow Unicode Technical Standard #35 +* http://unicode.org/reports/tr35/tr35-4.html +* Object.timezone {String}: The abbreviated name of the time zone on the client +* Object.utc_offset {Number}: The current difference in seconds between the client's +* time zone and coordinated universal time. +* Object.dst_offset {Number}: The current daylight saving time offset in seconds +* between the client's non-daylight saving's time zone +* and the client's daylight saving's time zone. +* +* @error GlobalizationError.PATTERN_ERROR +* +* Example +* globalization.getDatePattern( +* function (date) {alert('pattern:' + date.pattern + '\n');}, +* function () {}, +* {formatLength:'short'}); +*/ +getDatePattern:function(successCB, failureCB, options) { + argscheck.checkArgs('fFO', 'Globalization.getDatePattern', arguments); + exec(successCB, failureCB, "Globalization", "getDatePattern", [{"options": options}]); +}, + + +/** +* Returns an array of either the names of the months or days of the week +* according to the client's user preferences and calendar. It returns the array of names to the +* successCB callback with a properties object as a parameter. If there is an error obtaining the +* names, then the errorCB callback is invoked. +* +* The defaults are: type="wide" and item="months" +* +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* type {String}: 'narrow' or 'wide' +* item {String}: 'months', or 'days' +* +* @return Object.value {Array{String}}: The array of names starting from either +* the first month in the year or the +* first day of the week. +* @error GlobalizationError.UNKNOWN_ERROR +* +* Example +* globalization.getDateNames(function (names) { +* for(var i = 0; i < names.value.length; i++) { +* alert('Month:' + names.value[i] + '\n');}}, +* function () {}); +*/ +getDateNames:function(successCB, failureCB, options) { + argscheck.checkArgs('fFO', 'Globalization.getDateNames', arguments); + exec(successCB, failureCB, "Globalization", "getDateNames", [{"options": options}]); +}, + +/** +* Returns whether daylight savings time is in effect for a given date using the client's +* time zone and calendar. It returns whether or not daylight savings time is in effect +* to the successCB callback with a properties object as a parameter. If there is an error +* reading the date, then the errorCB callback is invoked. +* +* @param {Date} date +* @param {Function} successCB +* @param {Function} errorCB +* +* @return Object.dst {Boolean}: The value "true" indicates that daylight savings time is +* in effect for the given date and "false" indicate that it is not. +* +* @error GlobalizationError.UNKNOWN_ERROR +* +* Example +* globalization.isDayLightSavingsTime(new Date(), +* function (date) {alert('dst:' + date.dst + '\n');} +* function () {}); +*/ +isDayLightSavingsTime:function(date, successCB, failureCB) { + argscheck.checkArgs('dfF', 'Globalization.isDayLightSavingsTime', arguments); + var dateValue = date.valueOf(); + exec(successCB, failureCB, "Globalization", "isDayLightSavingsTime", [{"date": dateValue}]); +}, + +/** +* Returns the first day of the week according to the client's user preferences and calendar. +* The days of the week are numbered starting from 1 where 1 is considered to be Sunday. +* It returns the day to the successCB callback with a properties object as a parameter. +* If there is an error obtaining the pattern, then the errorCB callback is invoked. +* +* @param {Function} successCB +* @param {Function} errorCB +* +* @return Object.value {Number}: The number of the first day of the week. +* +* @error GlobalizationError.UNKNOWN_ERROR +* +* Example +* globalization.getFirstDayOfWeek(function (day) +* { alert('Day:' + day.value + '\n');}, +* function () {}); +*/ +getFirstDayOfWeek:function(successCB, failureCB) { + argscheck.checkArgs('fF', 'Globalization.getFirstDayOfWeek', arguments); + exec(successCB, failureCB, "Globalization", "getFirstDayOfWeek", []); +}, + + +/** +* Returns a number formatted as a string according to the client's user preferences. +* It returns the formatted number string to the successCB callback with a properties object as a +* parameter. If there is an error formatting the number, then the errorCB callback is invoked. +* +* The defaults are: type="decimal" +* +* @param {Number} number +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* type {String}: 'decimal', "percent", or 'currency' +* +* @return Object.value {String}: The formatted number string. +* +* @error GlobalizationError.FORMATTING_ERROR +* +* Example +* globalization.numberToString(3.25, +* function (number) {alert('number:' + number.value + '\n');}, +* function () {}, +* {type:'decimal'}); +*/ +numberToString:function(number, successCB, failureCB, options) { + argscheck.checkArgs('nfFO', 'Globalization.numberToString', arguments); + exec(successCB, failureCB, "Globalization", "numberToString", [{"number": number, "options": options}]); +}, + +/** +* Parses a number formatted as a string according to the client's user preferences and +* returns the corresponding number. It returns the number to the successCB callback with a +* properties object as a parameter. If there is an error parsing the number string, then +* the errorCB callback is invoked. +* +* The defaults are: type="decimal" +* +* @param {String} numberString +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* type {String}: 'decimal', "percent", or 'currency' +* +* @return Object.value {Number}: The parsed number. +* +* @error GlobalizationError.PARSING_ERROR +* +* Example +* globalization.stringToNumber('1234.56', +* function (number) {alert('Number:' + number.value + '\n');}, +* function () { alert('Error parsing number');}); +*/ +stringToNumber:function(numberString, successCB, failureCB, options) { + argscheck.checkArgs('sfFO', 'Globalization.stringToNumber', arguments); + exec(successCB, failureCB, "Globalization", "stringToNumber", [{"numberString": numberString, "options": options}]); +}, + +/** +* Returns a pattern string for formatting and parsing numbers according to the client's user +* preferences. It returns the pattern to the successCB callback with a properties object as a +* parameter. If there is an error obtaining the pattern, then the errorCB callback is invoked. +* +* The defaults are: type="decimal" +* +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* type {String}: 'decimal', "percent", or 'currency' +* +* @return Object.pattern {String}: The number pattern for formatting and parsing numbers. +* The patterns follow Unicode Technical Standard #35. +* http://unicode.org/reports/tr35/tr35-4.html +* Object.symbol {String}: The symbol to be used when formatting and parsing +* e.g., percent or currency symbol. +* Object.fraction {Number}: The number of fractional digits to use when parsing and +* formatting numbers. +* Object.rounding {Number}: The rounding increment to use when parsing and formatting. +* Object.positive {String}: The symbol to use for positive numbers when parsing and formatting. +* Object.negative: {String}: The symbol to use for negative numbers when parsing and formatting. +* Object.decimal: {String}: The decimal symbol to use for parsing and formatting. +* Object.grouping: {String}: The grouping symbol to use for parsing and formatting. +* +* @error GlobalizationError.PATTERN_ERROR +* +* Example +* globalization.getNumberPattern( +* function (pattern) {alert('Pattern:' + pattern.pattern + '\n');}, +* function () {}); +*/ +getNumberPattern:function(successCB, failureCB, options) { + argscheck.checkArgs('fFO', 'Globalization.getNumberPattern', arguments); + exec(successCB, failureCB, "Globalization", "getNumberPattern", [{"options": options}]); +}, + +/** +* Returns a pattern string for formatting and parsing currency values according to the client's +* user preferences and ISO 4217 currency code. It returns the pattern to the successCB callback with a +* properties object as a parameter. If there is an error obtaining the pattern, then the errorCB +* callback is invoked. +* +* @param {String} currencyCode +* @param {Function} successCB +* @param {Function} errorCB +* +* @return Object.pattern {String}: The currency pattern for formatting and parsing currency values. +* The patterns follow Unicode Technical Standard #35 +* http://unicode.org/reports/tr35/tr35-4.html +* Object.code {String}: The ISO 4217 currency code for the pattern. +* Object.fraction {Number}: The number of fractional digits to use when parsing and +* formatting currency. +* Object.rounding {Number}: The rounding increment to use when parsing and formatting. +* Object.decimal: {String}: The decimal symbol to use for parsing and formatting. +* Object.grouping: {String}: The grouping symbol to use for parsing and formatting. +* +* @error GlobalizationError.FORMATTING_ERROR +* +* Example +* globalization.getCurrencyPattern('EUR', +* function (currency) {alert('Pattern:' + currency.pattern + '\n');} +* function () {}); +*/ +getCurrencyPattern:function(currencyCode, successCB, failureCB) { + argscheck.checkArgs('sfF', 'Globalization.getCurrencyPattern', arguments); + exec(successCB, failureCB, "Globalization", "getCurrencyPattern", [{"currencyCode": currencyCode}]); +} + +}; + +module.exports = globalization; + +}); + +// file: lib/common/plugin/globalization/symbols.js +define("cordova/plugin/globalization/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/globalization', 'navigator.globalization'); +modulemapper.clobbers('cordova/plugin/GlobalizationError', 'GlobalizationError'); + +}); + +// file: lib/android/plugin/inappbrowser/symbols.js +define("cordova/plugin/inappbrowser/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/InAppBrowser', 'open'); + +}); + +// file: lib/common/plugin/logger.js +define("cordova/plugin/logger", function(require, exports, module) { + +//------------------------------------------------------------------------------ +// The logger module exports the following properties/functions: +// +// LOG - constant for the level LOG +// ERROR - constant for the level ERROR +// WARN - constant for the level WARN +// INFO - constant for the level INFO +// DEBUG - constant for the level DEBUG +// logLevel() - returns current log level +// logLevel(value) - sets and returns a new log level +// useConsole() - returns whether logger is using console +// useConsole(value) - sets and returns whether logger is using console +// log(message,...) - logs a message at level LOG +// error(message,...) - logs a message at level ERROR +// warn(message,...) - logs a message at level WARN +// info(message,...) - logs a message at level INFO +// debug(message,...) - logs a message at level DEBUG +// logLevel(level,message,...) - logs a message specified level +// +//------------------------------------------------------------------------------ + +var logger = exports; + +var exec = require('cordova/exec'); +var utils = require('cordova/utils'); + +var UseConsole = true; +var Queued = []; +var DeviceReady = false; +var CurrentLevel; + +/** + * Logging levels + */ + +var Levels = [ + "LOG", + "ERROR", + "WARN", + "INFO", + "DEBUG" +]; + +/* + * add the logging levels to the logger object and + * to a separate levelsMap object for testing + */ + +var LevelsMap = {}; +for (var i=0; i CurrentLevel) return; + + // queue the message if not yet at deviceready + if (!DeviceReady && !UseConsole) { + Queued.push([level, message]); + return; + } + + // if not using the console, use the native logger + if (!UseConsole) { + exec(null, null, "Logger", "logLevel", [level, message]); + return; + } + + // make sure console is not using logger + if (console.__usingCordovaLogger) { + throw new Error("console and logger are too intertwingly"); + } + + // log to the console + switch (level) { + case logger.LOG: console.log(message); break; + case logger.ERROR: console.log("ERROR: " + message); break; + case logger.WARN: console.log("WARN: " + message); break; + case logger.INFO: console.log("INFO: " + message); break; + case logger.DEBUG: console.log("DEBUG: " + message); break; + } +}; + +// when deviceready fires, log queued messages +logger.__onDeviceReady = function() { + if (DeviceReady) return; + + DeviceReady = true; + + for (var i=0; i 3) { + fail(FileError.SYNTAX_ERR); + } else { + // if successful, return a FileSystem object + var success = function(file_system) { + if (file_system) { + if (successCallback) { + // grab the name and root from the file system object + var result = new FileSystem(file_system.name, file_system.root); + successCallback(result); + } + } + else { + // no FileSystem object returned + fail(FileError.NOT_FOUND_ERR); + } + }; + exec(success, fail, "File", "requestFileSystem", [type, size]); + } +}; + +module.exports = requestFileSystem; + +}); + +// file: lib/common/plugin/resolveLocalFileSystemURI.js +define("cordova/plugin/resolveLocalFileSystemURI", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + DirectoryEntry = require('cordova/plugin/DirectoryEntry'), + FileEntry = require('cordova/plugin/FileEntry'), + FileError = require('cordova/plugin/FileError'), + exec = require('cordova/exec'); + +/** + * Look up file system Entry referred to by local URI. + * @param {DOMString} uri URI referring to a local file or directory + * @param successCallback invoked with Entry object corresponding to URI + * @param errorCallback invoked if error occurs retrieving file system entry + */ +module.exports = function(uri, successCallback, errorCallback) { + argscheck.checkArgs('sFF', 'resolveLocalFileSystemURI', arguments); + // error callback + var fail = function(error) { + errorCallback && errorCallback(new FileError(error)); + }; + // sanity check for 'not:valid:filename' + if(!uri || uri.split(":").length > 2) { + setTimeout( function() { + fail(FileError.ENCODING_ERR); + },0); + return; + } + // if successful, return either a file or directory entry + var success = function(entry) { + var result; + if (entry) { + if (successCallback) { + // create appropriate Entry object + result = (entry.isDirectory) ? new DirectoryEntry(entry.name, entry.fullPath) : new FileEntry(entry.name, entry.fullPath); + successCallback(result); + } + } + else { + // no Entry object returned + fail(FileError.NOT_FOUND_ERR); + } + }; + + exec(success, fail, "File", "resolveLocalFileSystemURI", [uri]); +}; + +}); + +// file: lib/common/plugin/splashscreen.js +define("cordova/plugin/splashscreen", function(require, exports, module) { + +var exec = require('cordova/exec'); + +var splashscreen = { + show:function() { + exec(null, null, "SplashScreen", "show", []); + }, + hide:function() { + exec(null, null, "SplashScreen", "hide", []); + } +}; + +module.exports = splashscreen; + +}); + +// file: lib/common/plugin/splashscreen/symbols.js +define("cordova/plugin/splashscreen/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/splashscreen', 'navigator.splashscreen'); + +}); + +// file: lib/common/symbols.js +define("cordova/symbols", function(require, exports, module) { + +var modulemapper = require('cordova/modulemapper'); + +// Use merges here in case others symbols files depend on this running first, +// but fail to declare the dependency with a require(). +modulemapper.merges('cordova', 'cordova'); +modulemapper.clobbers('cordova/exec', 'cordova.exec'); +modulemapper.clobbers('cordova/exec', 'Cordova.exec'); + +}); + +// file: lib/common/utils.js +define("cordova/utils", function(require, exports, module) { + +var utils = exports; + +/** + * Defines a property getter / setter for obj[key]. + */ +utils.defineGetterSetter = function(obj, key, getFunc, opt_setFunc) { + if (Object.defineProperty) { + var desc = { + get: getFunc, + configurable: true + }; + if (opt_setFunc) { + desc.set = opt_setFunc; + } + Object.defineProperty(obj, key, desc); + } else { + obj.__defineGetter__(key, getFunc); + if (opt_setFunc) { + obj.__defineSetter__(key, opt_setFunc); + } + } +}; + +/** + * Defines a property getter for obj[key]. + */ +utils.defineGetter = utils.defineGetterSetter; + +utils.arrayIndexOf = function(a, item) { + if (a.indexOf) { + return a.indexOf(item); + } + var len = a.length; + for (var i = 0; i < len; ++i) { + if (a[i] == item) { + return i; + } + } + return -1; +}; + +/** + * Returns whether the item was found in the array. + */ +utils.arrayRemove = function(a, item) { + var index = utils.arrayIndexOf(a, item); + if (index != -1) { + a.splice(index, 1); + } + return index != -1; +}; + +utils.typeName = function(val) { + return Object.prototype.toString.call(val).slice(8, -1); +}; + +/** + * Returns an indication of whether the argument is an array or not + */ +utils.isArray = function(a) { + return utils.typeName(a) == 'Array'; +}; + +/** + * Returns an indication of whether the argument is a Date or not + */ +utils.isDate = function(d) { + return utils.typeName(d) == 'Date'; +}; + +/** + * Does a deep clone of the object. + */ +utils.clone = function(obj) { + if(!obj || typeof obj == 'function' || utils.isDate(obj) || typeof obj != 'object') { + return obj; + } + + var retVal, i; + + if(utils.isArray(obj)){ + retVal = []; + for(i = 0; i < obj.length; ++i){ + retVal.push(utils.clone(obj[i])); + } + return retVal; + } + + retVal = {}; + for(i in obj){ + if(!(i in retVal) || retVal[i] != obj[i]) { + retVal[i] = utils.clone(obj[i]); + } + } + return retVal; +}; + +/** + * Returns a wrapped version of the function + */ +utils.close = function(context, func, params) { + if (typeof params == 'undefined') { + return function() { + return func.apply(context, arguments); + }; + } else { + return function() { + return func.apply(context, params); + }; + } +}; + +/** + * Create a UUID + */ +utils.createUUID = function() { + return UUIDcreatePart(4) + '-' + + UUIDcreatePart(2) + '-' + + UUIDcreatePart(2) + '-' + + UUIDcreatePart(2) + '-' + + UUIDcreatePart(6); +}; + +/** + * Extends a child object from a parent object using classical inheritance + * pattern. + */ +utils.extend = (function() { + // proxy used to establish prototype chain + var F = function() {}; + // extend Child from Parent + return function(Child, Parent) { + F.prototype = Parent.prototype; + Child.prototype = new F(); + Child.__super__ = Parent.prototype; + Child.prototype.constructor = Child; + }; +}()); + +/** + * Alerts a message in any available way: alert or console.log. + */ +utils.alert = function(msg) { + if (window.alert) { + window.alert(msg); + } else if (console && console.log) { + console.log(msg); + } +}; + +/** + * Formats a string and arguments following it ala sprintf() + * + * see utils.vformat() for more information + */ +utils.format = function(formatString /* ,... */) { + var args = [].slice.call(arguments, 1); + return utils.vformat(formatString, args); +}; + +/** + * Formats a string and arguments following it ala vsprintf() + * + * format chars: + * %j - format arg as JSON + * %o - format arg as JSON + * %c - format arg as '' + * %% - replace with '%' + * any other char following % will format it's + * arg via toString(). + * + * for rationale, see FireBug's Console API: + * http://getfirebug.com/wiki/index.php/Console_API + */ +utils.vformat = function(formatString, args) { + if (formatString === null || formatString === undefined) return ""; + if (arguments.length == 1) return formatString.toString(); + if (typeof formatString != "string") return formatString.toString(); + + var pattern = /(.*?)%(.)(.*)/; + var rest = formatString; + var result = []; + + while (args.length) { + var arg = args.shift(); + var match = pattern.exec(rest); + + if (!match) break; + + rest = match[3]; + + result.push(match[1]); + + if (match[2] == '%') { + result.push('%'); + args.unshift(arg); + continue; + } + + result.push(formatted(arg, match[2])); + } + + result.push(rest); + + return result.join(''); +}; + +//------------------------------------------------------------------------------ +function UUIDcreatePart(length) { + var uuidpart = ""; + for (var i=0; i + + + + diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml new file mode 100644 index 0000000..342ffa0 --- /dev/null +++ b/android/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Points Watcher + diff --git a/android/res/xml/config.xml b/android/res/xml/config.xml new file mode 100644 index 0000000..d15ac26 --- /dev/null +++ b/android/res/xml/config.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/src/com/moparisthebest/pointswatcher/PointsWatcher.java b/android/src/com/moparisthebest/pointswatcher/PointsWatcher.java new file mode 100644 index 0000000..30e3283 --- /dev/null +++ b/android/src/com/moparisthebest/pointswatcher/PointsWatcher.java @@ -0,0 +1,36 @@ +/* + 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. + */ + +package com.moparisthebest.pointswatcher; + +import android.os.Bundle; +import org.apache.cordova.*; + +public class PointsWatcher extends DroidGap +{ + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + // Set by in config.xml + super.loadUrl(Config.getStartUrl()); + //super.loadUrl("file:///android_asset/www/index.html") + } +} + diff --git a/blackberry/blackberry.xml b/blackberry/blackberry.xml new file mode 100644 index 0000000..c324b30 --- /dev/null +++ b/blackberry/blackberry.xml @@ -0,0 +1,456 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +NAME + ${ant.project.name} + +SYNOPSIS + ant TARGET COMMAND [-D<argument>=<value>]... + +DESCRIPTION + You can build and deploy your project to a device or simulator. + +TARGETS + blackberry ........ Builds a cod file and deploys to a device or simulator + + playbook .......... Builds a bar file and deploys to a device or simulator + +COMMANDS + help .............. Show this help menu. + ant, ant help + + load-device ....... Builds and deploys project to a connected USB device. + ant load-device + + load-simulator .... Builds and deploys project to default simulator. + ant load-simulator + + build ............. Compiles and packages the project for deployment. + ant build + + clean ............. Remove all files from the build/ directory. + ant clean + + clean-device ...... Remove this project from the connected USB device. + ant clean-device + + clean-simulator ... Remove this project from the simulator (takes a while). + ant clean-simulator + +GETTING STARTED + 1. Edit project.properties + + 2. <ant load-simulator> to run the project on the simulator + + 3. Customize your project by editing res/config.xml + + 4. To run the project on a BlackBerry device, you will need to obtain + code signing keys from RIM. Once you have the key, a project is + installed by connecting a BlackBerry via USB and running + <ant load-device>. + + + diff --git a/blackberry/build.xml b/blackberry/build.xml new file mode 100644 index 0000000..ba44856 --- /dev/null +++ b/blackberry/build.xml @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +NAME + ${ant.project.name} + +SYNOPSIS + ant TARGET COMMAND [-D<argument>=<value>]... + +DESCRIPTION + You can build and deploy your project to a device or simulator. + +TARGETS + blackberry ........ Builds a cod file and deploys to a device or simulator + + playbook .......... Builds a bar file and deploys to a device or simulator + + qnx ............... Builds a bar file and deploys to a device or simulator + +COMMANDS + help .............. Show this help menu. + ant, ant help + + load-device ....... Builds and deploys project to a connected USB device. + ant TARGET load-device + + load-simulator .... Builds and deploys project to default simulator. + ant TARGET load-simulator + + build ............. Compiles and packages the project for deployment. + ant TARGET build + + package-app ....... Packages the app into a WebWorks-compatible .zip file. + ant TARGET package-app + + clean ............. Remove all files from the build/ directory. + ant TARGET clean + + clean-device ...... Remove this project from the connected USB device. + ant TARGET clean-device + + clean-simulator ... Remove this project from the simulator (takes a while). + ant TARGET clean-simulator + +GETTING STARTED + 1. Edit project.properties + + 2. <ant load-simulator> to run the project on the simulator + + 3. Customize your project by editing res/config.xml + + 4. To run the project on a BlackBerry device, you will need to obtain + code signing keys from RIM. Once you have the key, a project is + installed by connecting a BlackBerry via USB and running + <ant load-device>. + + + diff --git a/blackberry/cordova/build b/blackberry/cordova/build new file mode 100755 index 0000000..f66c3e9 --- /dev/null +++ b/blackberry/cordova/build @@ -0,0 +1,44 @@ +#! /bin/bash +# 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. + +ANT=$(which ant) + +if [ -z "$1" ] +then + echo 'usage: build ' + echo 'where can be one of "blackberry", "playbook" or "qnx"' + echo 'NOTE: please customize the project.properties file first before using this command!' + exit 0 +fi + +function clean_after_build(){ + rm www/cordova.js + mv www/config.main.xml www/config.xml +} + +cd "$( dirname "$0" )"/.. + +if [ "$1" == "blackberry" -o "$1" == "playbook" -o "$1" == "qnx" ] +then + trap clean_after_build EXIT + cp lib/cordova.2.5.0/javascript/cordova-2.5.0.js www/cordova.js + mv www/config.xml www/config.main.xml && cp res/config.xml www/config.xml + $ANT $1 build +else + echo 'Platform not recognized! Please use one of "blackberry", "playbook", or "qnx" for the platform parameter.' +fi diff --git a/blackberry/cordova/run b/blackberry/cordova/run new file mode 100755 index 0000000..afa0ad7 --- /dev/null +++ b/blackberry/cordova/run @@ -0,0 +1,43 @@ +#! /bin/bash +# 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. + +ANT=$(which ant) + +if [ -z "$1" ] +then + echo 'usage: run ' + echo 'where can be one of "blackberry", "playbook" or "qnx"' + echo 'NOTE: please customize the project.properties file first before using this command!' + exit 0 +fi + +cd "$( dirname "$0" )"/.. + +if [ "$1" == "blackberry" -o "$1" == "playbook" -o "$1" == "qnx" ] +then + echo 'Do you have a BlackBerry device connected to your computer? (y/n)' + read DEVICE + if [ $DEVICE == "y" ] + then + $ANT $1 debug-device + else + $ANT $1 load-simulator + fi +else + echo 'Platform not recognized! Please use one of "blackberry", "playbook", or "qnx" for the platform parameter.' +fi diff --git a/blackberry/lib/ant-contrib/ant-contrib-1.0b3.jar b/blackberry/lib/ant-contrib/ant-contrib-1.0b3.jar new file mode 100644 index 0000000..0625376 Binary files /dev/null and b/blackberry/lib/ant-contrib/ant-contrib-1.0b3.jar differ diff --git a/blackberry/lib/cordova.2.5.0/ext-air/Cordova_Network/library.xml b/blackberry/lib/cordova.2.5.0/ext-air/Cordova_Network/library.xml new file mode 100644 index 0000000..c1835b4 --- /dev/null +++ b/blackberry/lib/cordova.2.5.0/ext-air/Cordova_Network/library.xml @@ -0,0 +1,40 @@ + + + + + org.apache.cordova.network.Network + + + + + + + + + + + + + + + + + + diff --git a/blackberry/lib/cordova.2.5.0/ext-air/Cordova_Network/src/org/apache/cordova/network/Network.as b/blackberry/lib/cordova.2.5.0/ext-air/Cordova_Network/src/org/apache/cordova/network/Network.as new file mode 100644 index 0000000..d2ad030 --- /dev/null +++ b/blackberry/lib/cordova.2.5.0/ext-air/Cordova_Network/src/org/apache/cordova/network/Network.as @@ -0,0 +1,88 @@ +/* + * 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. + * + * Copyright (c) 2011, Research In Motion Limited. + */ + + +package org.apache.cordova.network { + import flash.net.NetworkInfo; + import flash.net.NetworkInterface; + import flash.events.Event; + import qnx.system.Device; + + import webworks.extension.DefaultExtension; + + public class Network extends DefaultExtension{ + + private var _jsFunctionCallbackIDs:Array = []; + private const FEATURE_ID:Array = [ "org.apache.cordova" ]; + + public function Network() { + //Attach event listener once only + NetworkInfo.networkInfo.addEventListener(flash.events.Event.NETWORK_CHANGE, networkChange); + } + + override public function getFeatureList():Array { + return FEATURE_ID; + } + + public function getConnectionInfo(param:String):void{ + if(_jsFunctionCallbackIDs.indexOf(param) < 0){ + _jsFunctionCallbackIDs.push(param); + } + } + + public function getDeviceInfo(id:String):void{ + evalJavaScriptEvent(id, [{ + "uuid" : Device.device.pin, + "version": Device.device.scmBundle + }]); + } + + private function networkChange( event: Event ) : void { + + /** + * Right now, we only care if there is a connection or not, since PlayBook only has WiFi + * At the JS layer, we will map this from offline/online. + * At some point in the future where there are more connection types on PlayBook, + * we will want to attempt to map this to the real Cordova connection types... + */ + + var haveCoverage : Boolean = false; + var networkStatus : String = "offline"; + var connectionType = "none"; + + NetworkInfo.networkInfo.findInterfaces().some( + function callback(item:NetworkInterface, index:int, vector:Vector.):Boolean { + this.webView.executeJavaScript("alert('Network Interface ' + item.name)"); + haveCoverage = item.active || haveCoverage; + return haveCoverage; + }, this); + + if (haveCoverage) { + networkStatus = "online"; + connectionType = "wifi"; + } + + for (var i:Number=0; i<_jsFunctionCallbackIDs.length ; i++){ + evalJavaScriptEvent(_jsFunctionCallbackIDs[i], [{"type" : connectionType, "event" : networkStatus }] ); + } + } + } +} diff --git a/blackberry/lib/cordova.2.5.0/ext-qnx/org.apache.cordova/client.js b/blackberry/lib/cordova.2.5.0/ext-qnx/org.apache.cordova/client.js new file mode 100644 index 0000000..f8308b8 --- /dev/null +++ b/blackberry/lib/cordova.2.5.0/ext-qnx/org.apache.cordova/client.js @@ -0,0 +1,16 @@ +/* + * Copyright 2010-2011 Research In Motion Limited. + * + * Licensed 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. + */ + diff --git a/blackberry/lib/cordova.2.5.0/ext-qnx/org.apache.cordova/index.js b/blackberry/lib/cordova.2.5.0/ext-qnx/org.apache.cordova/index.js new file mode 100644 index 0000000..4a60b93 --- /dev/null +++ b/blackberry/lib/cordova.2.5.0/ext-qnx/org.apache.cordova/index.js @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2011 Research In Motion Limited. + * + * Licensed 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. + */ + +var Whitelist = require("../../lib/policy/whitelist").Whitelist, + whitelist = new Whitelist(), + noop = function () {}; + +module.exports = { + isWhitelisted: function (success, fail, args) { + var url = JSON.parse(decodeURIComponent(args[0])), + success = success || noop, + fail = fail || noop; + + if (url) { + success(whitelist.isAccessAllowed(url)); + } + else { + error("please provide an url"); + } + } +}; diff --git a/blackberry/lib/cordova.2.5.0/ext-qnx/org.apache.cordova/manifest.json b/blackberry/lib/cordova.2.5.0/ext-qnx/org.apache.cordova/manifest.json new file mode 100644 index 0000000..9efdda2 --- /dev/null +++ b/blackberry/lib/cordova.2.5.0/ext-qnx/org.apache.cordova/manifest.json @@ -0,0 +1,5 @@ +{ + "global": false, + "namespace": "org.apache.cordova", + "dependencies": [] +} diff --git a/blackberry/lib/cordova.2.5.0/ext-qnx/readme.md b/blackberry/lib/cordova.2.5.0/ext-qnx/readme.md new file mode 100644 index 0000000..6527192 --- /dev/null +++ b/blackberry/lib/cordova.2.5.0/ext-qnx/readme.md @@ -0,0 +1 @@ +Placeholder for native extensions needed on qnx diff --git a/blackberry/lib/cordova.2.5.0/ext/cordova.2.5.0.jar b/blackberry/lib/cordova.2.5.0/ext/cordova.2.5.0.jar new file mode 100644 index 0000000..43e63ff Binary files /dev/null and b/blackberry/lib/cordova.2.5.0/ext/cordova.2.5.0.jar differ diff --git a/blackberry/lib/cordova.2.5.0/javascript/cordova-2.5.0.js b/blackberry/lib/cordova.2.5.0/javascript/cordova-2.5.0.js new file mode 100644 index 0000000..988dd43 --- /dev/null +++ b/blackberry/lib/cordova.2.5.0/javascript/cordova-2.5.0.js @@ -0,0 +1,10569 @@ +// Platform: blackberry + +// commit c5437f050947a65045222c6ac9fa70cf71ba334e + +// File generated at :: Wed Feb 27 2013 13:16:46 GMT-0800 (PST) + +/* + 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. +*/ + +;(function() { + +// file: lib/scripts/require.js + +var require, + define; + +(function () { + var modules = {}; + // Stack of moduleIds currently being built. + var requireStack = []; + // Map of module ID -> index into requireStack of modules currently being built. + var inProgressModules = {}; + + function build(module) { + var factory = module.factory; + module.exports = {}; + delete module.factory; + factory(require, module.exports, module); + return module.exports; + } + + require = function (id) { + if (!modules[id]) { + throw "module " + id + " not found"; + } else if (id in inProgressModules) { + var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id; + throw "Cycle in require graph: " + cycle; + } + if (modules[id].factory) { + try { + inProgressModules[id] = requireStack.length; + requireStack.push(id); + return build(modules[id]); + } finally { + delete inProgressModules[id]; + requireStack.pop(); + } + } + return modules[id].exports; + }; + + define = function (id, factory) { + if (modules[id]) { + throw "module " + id + " already defined"; + } + + modules[id] = { + id: id, + factory: factory + }; + }; + + define.remove = function (id) { + delete modules[id]; + }; + + define.moduleMap = modules; +})(); + +//Export for use in node +if (typeof module === "object" && typeof require === "function") { + module.exports.require = require; + module.exports.define = define; +} + +// file: lib/cordova.js +define("cordova", function(require, exports, module) { + + +var channel = require('cordova/channel'); + +/** + * Listen for DOMContentLoaded and notify our channel subscribers. + */ +document.addEventListener('DOMContentLoaded', function() { + channel.onDOMContentLoaded.fire(); +}, false); +if (document.readyState == 'complete' || document.readyState == 'interactive') { + channel.onDOMContentLoaded.fire(); +} + +/** + * Intercept calls to addEventListener + removeEventListener and handle deviceready, + * resume, and pause events. + */ +var m_document_addEventListener = document.addEventListener; +var m_document_removeEventListener = document.removeEventListener; +var m_window_addEventListener = window.addEventListener; +var m_window_removeEventListener = window.removeEventListener; + +/** + * Houses custom event handlers to intercept on document + window event listeners. + */ +var documentEventHandlers = {}, + windowEventHandlers = {}; + +document.addEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + if (typeof documentEventHandlers[e] != 'undefined') { + documentEventHandlers[e].subscribe(handler); + } else { + m_document_addEventListener.call(document, evt, handler, capture); + } +}; + +window.addEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + if (typeof windowEventHandlers[e] != 'undefined') { + windowEventHandlers[e].subscribe(handler); + } else { + m_window_addEventListener.call(window, evt, handler, capture); + } +}; + +document.removeEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + // If unsubscribing from an event that is handled by a plugin + if (typeof documentEventHandlers[e] != "undefined") { + documentEventHandlers[e].unsubscribe(handler); + } else { + m_document_removeEventListener.call(document, evt, handler, capture); + } +}; + +window.removeEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + // If unsubscribing from an event that is handled by a plugin + if (typeof windowEventHandlers[e] != "undefined") { + windowEventHandlers[e].unsubscribe(handler); + } else { + m_window_removeEventListener.call(window, evt, handler, capture); + } +}; + +function createEvent(type, data) { + var event = document.createEvent('Events'); + event.initEvent(type, false, false); + if (data) { + for (var i in data) { + if (data.hasOwnProperty(i)) { + event[i] = data[i]; + } + } + } + return event; +} + +if(typeof window.console === "undefined") { + window.console = { + log:function(){} + }; +} + +var cordova = { + define:define, + require:require, + /** + * Methods to add/remove your own addEventListener hijacking on document + window. + */ + addWindowEventHandler:function(event) { + return (windowEventHandlers[event] = channel.create(event)); + }, + addStickyDocumentEventHandler:function(event) { + return (documentEventHandlers[event] = channel.createSticky(event)); + }, + addDocumentEventHandler:function(event) { + return (documentEventHandlers[event] = channel.create(event)); + }, + removeWindowEventHandler:function(event) { + delete windowEventHandlers[event]; + }, + removeDocumentEventHandler:function(event) { + delete documentEventHandlers[event]; + }, + /** + * Retrieve original event handlers that were replaced by Cordova + * + * @return object + */ + getOriginalHandlers: function() { + return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener}, + 'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}}; + }, + /** + * Method to fire event from native code + * bNoDetach is required for events which cause an exception which needs to be caught in native code + */ + fireDocumentEvent: function(type, data, bNoDetach) { + var evt = createEvent(type, data); + if (typeof documentEventHandlers[type] != 'undefined') { + if( bNoDetach ) { + documentEventHandlers[type].fire(evt); + } + else { + setTimeout(function() { + documentEventHandlers[type].fire(evt); + }, 0); + } + } else { + document.dispatchEvent(evt); + } + }, + fireWindowEvent: function(type, data) { + var evt = createEvent(type,data); + if (typeof windowEventHandlers[type] != 'undefined') { + setTimeout(function() { + windowEventHandlers[type].fire(evt); + }, 0); + } else { + window.dispatchEvent(evt); + } + }, + + /** + * Plugin callback mechanism. + */ + // Randomize the starting callbackId to avoid collisions after refreshing or navigating. + // This way, it's very unlikely that any new callback would get the same callbackId as an old callback. + callbackId: Math.floor(Math.random() * 2000000000), + callbacks: {}, + 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 + }, + + /** + * Called by native code when returning successful result from an action. + */ + callbackSuccess: function(callbackId, args) { + try { + cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback); + } catch (e) { + console.log("Error in error callback: " + callbackId + " = "+e); + } + }, + + /** + * Called by native code when returning error result from an action. + */ + callbackError: function(callbackId, args) { + // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative. + // Derive success from status. + try { + cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback); + } catch (e) { + console.log("Error in error callback: " + callbackId + " = "+e); + } + }, + + /** + * Called by native code when returning the result from an action. + */ + callbackFromNative: function(callbackId, success, status, args, keepCallback) { + var callback = cordova.callbacks[callbackId]; + if (callback) { + if (success && status == cordova.callbackStatus.OK) { + callback.success && callback.success.apply(null, args); + } else if (!success) { + callback.fail && callback.fail.apply(null, args); + } + + // Clear callback if not expecting any more results + if (!keepCallback) { + delete cordova.callbacks[callbackId]; + } + } + }, + addConstructor: function(func) { + channel.onCordovaReady.subscribe(function() { + try { + func(); + } catch(e) { + console.log("Failed to run constructor: " + e); + } + }); + } +}; + +// Register pause, resume and deviceready channels as events on document. +channel.onPause = cordova.addDocumentEventHandler('pause'); +channel.onResume = cordova.addDocumentEventHandler('resume'); +channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready'); + +module.exports = cordova; + +}); + +// file: lib/common/argscheck.js +define("cordova/argscheck", function(require, exports, module) { + +var exec = require('cordova/exec'); +var utils = require('cordova/utils'); + +var moduleExports = module.exports; + +var typeMap = { + 'A': 'Array', + 'D': 'Date', + 'N': 'Number', + 'S': 'String', + 'F': 'Function', + 'O': 'Object' +}; + +function extractParamName(callee, argIndex) { + return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex]; +} + +function checkArgs(spec, functionName, args, opt_callee) { + if (!moduleExports.enableChecks) { + return; + } + var errMsg = null; + var typeName; + for (var i = 0; i < spec.length; ++i) { + var c = spec.charAt(i), + cUpper = c.toUpperCase(), + arg = args[i]; + // Asterix means allow anything. + if (c == '*') { + continue; + } + typeName = utils.typeName(arg); + if ((arg === null || arg === undefined) && c == cUpper) { + continue; + } + if (typeName != typeMap[cUpper]) { + errMsg = 'Expected ' + typeMap[cUpper]; + break; + } + } + if (errMsg) { + errMsg += ', but got ' + typeName + '.'; + errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg; + // Don't log when running jake test. + if (typeof jasmine == 'undefined') { + console.error(errMsg); + } + throw TypeError(errMsg); + } +} + +function getValue(value, defaultValue) { + return value === undefined ? defaultValue : value; +} + +moduleExports.checkArgs = checkArgs; +moduleExports.getValue = getValue; +moduleExports.enableChecks = true; + + +}); + +// file: lib/common/builder.js +define("cordova/builder", function(require, exports, module) { + +var utils = require('cordova/utils'); + +function each(objects, func, context) { + for (var prop in objects) { + if (objects.hasOwnProperty(prop)) { + func.apply(context, [objects[prop], prop]); + } + } +} + +function clobber(obj, key, value) { + exports.replaceHookForTesting(obj, key); + obj[key] = value; + // Getters can only be overridden by getters. + if (obj[key] !== value) { + utils.defineGetter(obj, key, function() { + return value; + }); + } +} + +function assignOrWrapInDeprecateGetter(obj, key, value, message) { + if (message) { + utils.defineGetter(obj, key, function() { + console.log(message); + delete obj[key]; + clobber(obj, key, value); + return value; + }); + } else { + clobber(obj, key, value); + } +} + +function include(parent, objects, clobber, merge) { + each(objects, function (obj, key) { + try { + var result = obj.path ? require(obj.path) : {}; + + if (clobber) { + // Clobber if it doesn't exist. + if (typeof parent[key] === 'undefined') { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } else if (typeof obj.path !== 'undefined') { + // If merging, merge properties onto parent, otherwise, clobber. + if (merge) { + recursiveMerge(parent[key], result); + } else { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } + } + result = parent[key]; + } else { + // Overwrite if not currently defined. + if (typeof parent[key] == 'undefined') { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } else { + // Set result to what already exists, so we can build children into it if they exist. + result = parent[key]; + } + } + + if (obj.children) { + include(result, obj.children, clobber, merge); + } + } catch(e) { + utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"'); + } + }); +} + +/** + * Merge properties from one object onto another recursively. Properties from + * the src object will overwrite existing target property. + * + * @param target Object to merge properties into. + * @param src Object to merge properties from. + */ +function recursiveMerge(target, src) { + for (var prop in src) { + if (src.hasOwnProperty(prop)) { + if (target.prototype && target.prototype.constructor === target) { + // If the target object is a constructor override off prototype. + clobber(target.prototype, prop, src[prop]); + } else { + if (typeof src[prop] === 'object' && typeof target[prop] === 'object') { + recursiveMerge(target[prop], src[prop]); + } else { + clobber(target, prop, src[prop]); + } + } + } + } +} + +exports.buildIntoButDoNotClobber = function(objects, target) { + include(target, objects, false, false); +}; +exports.buildIntoAndClobber = function(objects, target) { + include(target, objects, true, false); +}; +exports.buildIntoAndMerge = function(objects, target) { + include(target, objects, true, true); +}; +exports.recursiveMerge = recursiveMerge; +exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter; +exports.replaceHookForTesting = function() {}; + +}); + +// file: lib/common/channel.js +define("cordova/channel", function(require, exports, module) { + +var utils = require('cordova/utils'), + nextGuid = 1; + +/** + * Custom pub-sub "channel" that can have functions subscribed to it + * This object is used to define and control firing of events for + * cordova initialization, as well as for custom events thereafter. + * + * The order of events during page load and Cordova startup is as follows: + * + * onDOMContentLoaded* Internal event that is received when the web page is loaded and parsed. + * onNativeReady* Internal event that indicates the Cordova native side is ready. + * onCordovaReady* Internal event fired when all Cordova JavaScript objects have been created. + * onCordovaInfoReady* Internal event fired when device properties are available. + * onCordovaConnectionReady* Internal event fired when the connection property has been set. + * onDeviceReady* User event fired to indicate that Cordova is ready + * onResume User event fired to indicate a start/resume lifecycle event + * onPause User event fired to indicate a pause lifecycle event + * onDestroy* Internal event fired when app is being destroyed (User should use window.onunload event, not this one). + * + * The events marked with an * are sticky. Once they have fired, they will stay in the fired state. + * All listeners that subscribe after the event is fired will be executed right away. + * + * The only Cordova events that user code should register for are: + * deviceready Cordova native code is initialized and Cordova APIs can be called from JavaScript + * pause App has moved to background + * resume App has returned to foreground + * + * Listeners can be registered as: + * document.addEventListener("deviceready", myDeviceReadyListener, false); + * document.addEventListener("resume", myResumeListener, false); + * document.addEventListener("pause", myPauseListener, false); + * + * The DOM lifecycle events should be used for saving and restoring state + * window.onload + * window.onunload + * + */ + +/** + * Channel + * @constructor + * @param type String the channel name + */ +var Channel = function(type, sticky) { + this.type = type; + // Map of guid -> function. + this.handlers = {}; + // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired. + this.state = sticky ? 1 : 0; + // Used in sticky mode to remember args passed to fire(). + this.fireArgs = null; + // Used by onHasSubscribersChange to know if there are any listeners. + this.numHandlers = 0; + // Function that is called when the first listener is subscribed, or when + // the last listener is unsubscribed. + this.onHasSubscribersChange = null; +}, + channel = { + /** + * Calls the provided function only after all of the channels specified + * have been fired. All channels must be sticky channels. + */ + join: function(h, c) { + var len = c.length, + i = len, + f = function() { + if (!(--i)) h(); + }; + for (var j=0; j -1) { + return 'qnx'; + } + else if (navigator.userAgent.indexOf("PlayBook") > -1) { + return 'air'; + } + else if (navigator.userAgent.indexOf("BlackBerry") > -1) { + return 'java'; + } + else { + console.log("Unknown user agent?!?!? defaulting to java"); + return 'java'; + } + }, + initialize: function() { + var modulemapper = require('cordova/modulemapper'), + platform = require('cordova/plugin/' + this.runtime() + '/platform'); + + modulemapper.loadMatchingModules(/cordova.*\/symbols$/); + modulemapper.loadMatchingModules(new RegExp('cordova/.*' + this.runtime() + '/.*bbsymbols$')); + modulemapper.mapModules(this.contextObj); + + platform.initialize(); + }, + contextObj: this // Used for testing. +}; + +}); + +// file: lib/common/plugin/Acceleration.js +define("cordova/plugin/Acceleration", function(require, exports, module) { + +var Acceleration = function(x, y, z, timestamp) { + this.x = x; + this.y = y; + this.z = z; + this.timestamp = timestamp || (new Date()).getTime(); +}; + +module.exports = Acceleration; + +}); + +// file: lib/common/plugin/Camera.js +define("cordova/plugin/Camera", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + Camera = require('cordova/plugin/CameraConstants'), + CameraPopoverHandle = require('cordova/plugin/CameraPopoverHandle'); + +var cameraExport = {}; + +// Tack on the Camera Constants to the base camera plugin. +for (var key in Camera) { + cameraExport[key] = Camera[key]; +} + +/** + * 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=FILE_URI. + * + * @param {Function} successCallback + * @param {Function} errorCallback + * @param {Object} options + */ +cameraExport.getPicture = function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'Camera.getPicture', arguments); + options = options || {}; + var getValue = argscheck.getValue; + + var quality = getValue(options.quality, 50); + var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI); + var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA); + var targetWidth = getValue(options.targetWidth, -1); + var targetHeight = getValue(options.targetHeight, -1); + var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG); + var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE); + var allowEdit = !!options.allowEdit; + var correctOrientation = !!options.correctOrientation; + var saveToPhotoAlbum = !!options.saveToPhotoAlbum; + var popoverOptions = getValue(options.popoverOptions, null); + + var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType, + mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions]; + + exec(successCallback, errorCallback, "Camera", "takePicture", args); + return new CameraPopoverHandle(); +}; + +cameraExport.cleanup = function(successCallback, errorCallback) { + exec(successCallback, errorCallback, "Camera", "cleanup", []); +}; + +module.exports = cameraExport; + +}); + +// file: lib/common/plugin/CameraConstants.js +define("cordova/plugin/CameraConstants", function(require, exports, module) { + +module.exports = { + DestinationType:{ + DATA_URL: 0, // Return base64 encoded string + FILE_URI: 1, // Return file uri (content://media/external/images/media/2 for Android) + NATIVE_URI: 2 // Return native uri (eg. asset-library://... for iOS) + }, + EncodingType:{ + JPEG: 0, // Return JPEG encoded image + PNG: 1 // Return PNG encoded image + }, + 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 + }, + PictureSourceType:{ + PHOTOLIBRARY : 0, // Choose image from picture library (same as SAVEDPHOTOALBUM for Android) + CAMERA : 1, // Take picture from camera + SAVEDPHOTOALBUM : 2 // Choose image from picture library (same as PHOTOLIBRARY for Android) + }, + PopoverArrowDirection:{ + ARROW_UP : 1, // matches iOS UIPopoverArrowDirection constants to specify arrow location on popover + ARROW_DOWN : 2, + ARROW_LEFT : 4, + ARROW_RIGHT : 8, + ARROW_ANY : 15 + } +}; + +}); + +// file: lib/common/plugin/CameraPopoverHandle.js +define("cordova/plugin/CameraPopoverHandle", function(require, exports, module) { + +var exec = require('cordova/exec'); + +/** + * A handle to an image picker popover. + */ +var CameraPopoverHandle = function() { + this.setPosition = function(popoverOptions) { + console.log('CameraPopoverHandle.setPosition is only supported on iOS.'); + }; +}; + +module.exports = CameraPopoverHandle; + +}); + +// file: lib/common/plugin/CameraPopoverOptions.js +define("cordova/plugin/CameraPopoverOptions", function(require, exports, module) { + +var Camera = require('cordova/plugin/CameraConstants'); + +/** + * Encapsulates options for iOS Popover image picker + */ +var CameraPopoverOptions = function(x,y,width,height,arrowDir){ + // information of rectangle that popover should be anchored to + this.x = x || 0; + this.y = y || 32; + this.width = width || 320; + this.height = height || 480; + // The direction of the popover arrow + this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY; +}; + +module.exports = CameraPopoverOptions; + +}); + +// file: lib/common/plugin/CaptureAudioOptions.js +define("cordova/plugin/CaptureAudioOptions", function(require, exports, module) { + +/** + * Encapsulates all audio capture operation configuration options. + */ +var CaptureAudioOptions = function(){ + // Upper limit of sound clips user can record. Value must be equal or greater than 1. + this.limit = 1; + // Maximum duration of a single sound clip in seconds. + this.duration = 0; + // The selected audio mode. Must match with one of the elements in supportedAudioModes array. + this.mode = null; +}; + +module.exports = CaptureAudioOptions; + +}); + +// file: lib/common/plugin/CaptureError.js +define("cordova/plugin/CaptureError", function(require, exports, module) { + +/** + * The CaptureError interface encapsulates all errors in the Capture API. + */ +var CaptureError = function(c) { + this.code = c || null; +}; + +// Camera or microphone failed to capture image or sound. +CaptureError.CAPTURE_INTERNAL_ERR = 0; +// Camera application or audio capture application is currently serving other capture request. +CaptureError.CAPTURE_APPLICATION_BUSY = 1; +// Invalid use of the API (e.g. limit parameter has value less than one). +CaptureError.CAPTURE_INVALID_ARGUMENT = 2; +// User exited camera application or audio capture application before capturing anything. +CaptureError.CAPTURE_NO_MEDIA_FILES = 3; +// The requested capture operation is not supported. +CaptureError.CAPTURE_NOT_SUPPORTED = 20; + +module.exports = CaptureError; + +}); + +// file: lib/common/plugin/CaptureImageOptions.js +define("cordova/plugin/CaptureImageOptions", function(require, exports, module) { + +/** + * Encapsulates all image capture operation configuration options. + */ +var CaptureImageOptions = function(){ + // Upper limit of images user can take. Value must be equal or greater than 1. + this.limit = 1; + // The selected image mode. Must match with one of the elements in supportedImageModes array. + this.mode = null; +}; + +module.exports = CaptureImageOptions; + +}); + +// file: lib/common/plugin/CaptureVideoOptions.js +define("cordova/plugin/CaptureVideoOptions", function(require, exports, module) { + +/** + * Encapsulates all video capture operation configuration options. + */ +var CaptureVideoOptions = function(){ + // Upper limit of videos user can record. Value must be equal or greater than 1. + this.limit = 1; + // Maximum duration of a single video clip in seconds. + this.duration = 0; + // The selected video mode. Must match with one of the elements in supportedVideoModes array. + this.mode = null; +}; + +module.exports = CaptureVideoOptions; + +}); + +// file: lib/common/plugin/CompassError.js +define("cordova/plugin/CompassError", function(require, exports, module) { + +/** + * CompassError. + * An error code assigned by an implementation when an error has occurred + * @constructor + */ +var CompassError = function(err) { + this.code = (err !== undefined ? err : null); +}; + +CompassError.COMPASS_INTERNAL_ERR = 0; +CompassError.COMPASS_NOT_SUPPORTED = 20; + +module.exports = CompassError; + +}); + +// file: lib/common/plugin/CompassHeading.js +define("cordova/plugin/CompassHeading", function(require, exports, module) { + +var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) { + this.magneticHeading = magneticHeading; + this.trueHeading = trueHeading; + this.headingAccuracy = headingAccuracy; + this.timestamp = timestamp || new Date().getTime(); +}; + +module.exports = CompassHeading; + +}); + +// file: lib/common/plugin/ConfigurationData.js +define("cordova/plugin/ConfigurationData", function(require, exports, module) { + +/** + * Encapsulates a set of parameters that the capture device supports. + */ +function ConfigurationData() { + // The ASCII-encoded string in lower case representing the media type. + this.type = null; + // The height attribute represents height of the image or video in pixels. + // In the case of a sound clip this attribute has value 0. + this.height = 0; + // The width attribute represents width of the image or video in pixels. + // In the case of a sound clip this attribute has value 0 + this.width = 0; +} + +module.exports = ConfigurationData; + +}); + +// file: lib/common/plugin/Connection.js +define("cordova/plugin/Connection", function(require, exports, module) { + +/** + * Network status + */ +module.exports = { + UNKNOWN: "unknown", + ETHERNET: "ethernet", + WIFI: "wifi", + CELL_2G: "2g", + CELL_3G: "3g", + CELL_4G: "4g", + CELL:"cellular", + NONE: "none" +}; + +}); + +// file: lib/common/plugin/Contact.js +define("cordova/plugin/Contact", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + ContactError = require('cordova/plugin/ContactError'), + utils = require('cordova/utils'); + +/** +* Converts primitives into Complex Object +* Currently only used for Date fields +*/ +function convertIn(contact) { + var value = contact.birthday; + try { + contact.birthday = new Date(parseFloat(value)); + } catch (exception){ + console.log("Cordova Contact convertIn error: exception creating date."); + } + return contact; +} + +/** +* Converts Complex objects into primitives +* Only conversion at present is for Dates. +**/ + +function convertOut(contact) { + var value = contact.birthday; + if (value !== null) { + // try to make it a Date object if it is not already + if (!utils.isDate(value)){ + try { + value = new Date(value); + } catch(exception){ + value = null; + } + } + if (utils.isDate(value)){ + value = value.valueOf(); // convert to milliseconds + } + contact.birthday = value; + } + return contact; +} + +/** +* Contains information about a single contact. +* @constructor +* @param {DOMString} id unique identifier +* @param {DOMString} displayName +* @param {ContactName} name +* @param {DOMString} nickname +* @param {Array.} phoneNumbers array of phone numbers +* @param {Array.} emails array of email addresses +* @param {Array.} addresses array of addresses +* @param {Array.} ims instant messaging user ids +* @param {Array.} organizations +* @param {DOMString} birthday contact's birthday +* @param {DOMString} note user notes about contact +* @param {Array.} photos +* @param {Array.} categories +* @param {Array.} 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.rawId = 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; + this.note = note || null; + this.photos = photos || null; // ContactField[] + this.categories = categories || null; // ContactField[] + this.urls = urls || null; // ContactField[] +}; + +/** +* Removes contact from device storage. +* @param successCB success callback +* @param errorCB error callback +*/ +Contact.prototype.remove = function(successCB, errorCB) { + argscheck.checkArgs('FF', 'Contact.remove', arguments); + var fail = errorCB && function(code) { + errorCB(new ContactError(code)); + }; + if (this.id === null) { + fail(ContactError.UNKNOWN_ERROR); + } + else { + exec(successCB, fail, "Contacts", "remove", [this.id]); + } +}; + +/** +* Creates a deep copy of this Contact. +* With the contact ID set to null. +* @return copy of this Contact +*/ +Contact.prototype.clone = function() { + var clonedContact = utils.clone(this); + clonedContact.id = null; + clonedContact.rawId = null; + + function nullIds(arr) { + if (arr) { + for (var i = 0; i < arr.length; ++i) { + arr[i].id = null; + } + } + } + + // Loop through and clear out any id's in phones, emails, etc. + nullIds(clonedContact.phoneNumbers); + nullIds(clonedContact.emails); + nullIds(clonedContact.addresses); + nullIds(clonedContact.ims); + nullIds(clonedContact.organizations); + nullIds(clonedContact.categories); + nullIds(clonedContact.photos); + nullIds(clonedContact.urls); + return clonedContact; +}; + +/** +* Persists contact to device storage. +* @param successCB success callback +* @param errorCB error callback +*/ +Contact.prototype.save = function(successCB, errorCB) { + argscheck.checkArgs('FFO', 'Contact.save', arguments); + var fail = errorCB && function(code) { + errorCB(new ContactError(code)); + }; + var success = function(result) { + if (result) { + if (successCB) { + var fullContact = require('cordova/plugin/contacts').create(result); + successCB(convertIn(fullContact)); + } + } + else { + // no Entry object returned + fail(ContactError.UNKNOWN_ERROR); + } + }; + var dupContact = convertOut(utils.clone(this)); + exec(success, fail, "Contacts", "save", [dupContact]); +}; + + +module.exports = Contact; + +}); + +// file: lib/common/plugin/ContactAddress.js +define("cordova/plugin/ContactAddress", function(require, exports, module) { + +/** +* Contact address. +* @constructor +* @param {DOMString} id unique identifier, should only be set by native code +* @param formatted // NOTE: not a W3C standard +* @param streetAddress +* @param locality +* @param region +* @param postalCode +* @param country +*/ + +var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) { + this.id = null; + this.pref = (typeof pref != 'undefined' ? pref : false); + this.type = type || null; + this.formatted = formatted || null; + this.streetAddress = streetAddress || null; + this.locality = locality || null; + this.region = region || null; + this.postalCode = postalCode || null; + this.country = country || null; +}; + +module.exports = ContactAddress; + +}); + +// file: lib/common/plugin/ContactError.js +define("cordova/plugin/ContactError", function(require, exports, module) { + +/** + * ContactError. + * An error code assigned by an implementation when an error has occurred + * @constructor + */ +var ContactError = function(err) { + this.code = (typeof err != 'undefined' ? err : null); +}; + +/** + * Error codes + */ +ContactError.UNKNOWN_ERROR = 0; +ContactError.INVALID_ARGUMENT_ERROR = 1; +ContactError.TIMEOUT_ERROR = 2; +ContactError.PENDING_OPERATION_ERROR = 3; +ContactError.IO_ERROR = 4; +ContactError.NOT_SUPPORTED_ERROR = 5; +ContactError.PERMISSION_DENIED_ERROR = 20; + +module.exports = ContactError; + +}); + +// file: lib/common/plugin/ContactField.js +define("cordova/plugin/ContactField", function(require, exports, module) { + +/** +* Generic contact field. +* @constructor +* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard +* @param type +* @param value +* @param pref +*/ +var ContactField = function(type, value, pref) { + this.id = null; + this.type = (type && type.toString()) || null; + this.value = (value && value.toString()) || null; + this.pref = (typeof pref != 'undefined' ? pref : false); +}; + +module.exports = ContactField; + +}); + +// file: lib/common/plugin/ContactFindOptions.js +define("cordova/plugin/ContactFindOptions", function(require, exports, module) { + +/** + * ContactFindOptions. + * @constructor + * @param filter used to match contacts against + * @param multiple boolean used to determine if more than one contact should be returned + */ + +var ContactFindOptions = function(filter, multiple) { + this.filter = filter || ''; + this.multiple = (typeof multiple != 'undefined' ? multiple : false); +}; + +module.exports = ContactFindOptions; + +}); + +// file: lib/common/plugin/ContactName.js +define("cordova/plugin/ContactName", function(require, exports, module) { + +/** +* Contact name. +* @constructor +* @param formatted // NOTE: not part of W3C standard +* @param familyName +* @param givenName +* @param middle +* @param prefix +* @param suffix +*/ +var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) { + this.formatted = formatted || null; + this.familyName = familyName || null; + this.givenName = givenName || null; + this.middleName = middle || null; + this.honorificPrefix = prefix || null; + this.honorificSuffix = suffix || null; +}; + +module.exports = ContactName; + +}); + +// file: lib/common/plugin/ContactOrganization.js +define("cordova/plugin/ContactOrganization", function(require, exports, module) { + +/** +* Contact organization. +* @constructor +* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard +* @param name +* @param dept +* @param title +* @param startDate +* @param endDate +* @param location +* @param desc +*/ + +var ContactOrganization = function(pref, type, name, dept, title) { + this.id = null; + this.pref = (typeof pref != 'undefined' ? pref : false); + this.type = type || null; + this.name = name || null; + this.department = dept || null; + this.title = title || null; +}; + +module.exports = ContactOrganization; + +}); + +// file: lib/common/plugin/Coordinates.js +define("cordova/plugin/Coordinates", function(require, exports, module) { + +/** + * This class contains position information. + * @param {Object} lat + * @param {Object} lng + * @param {Object} alt + * @param {Object} acc + * @param {Object} head + * @param {Object} vel + * @param {Object} altacc + * @constructor + */ +var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) { + /** + * The latitude of the position. + */ + this.latitude = lat; + /** + * The longitude of the position, + */ + this.longitude = lng; + /** + * The accuracy of the position. + */ + this.accuracy = acc; + /** + * The altitude of the position. + */ + this.altitude = (alt !== undefined ? alt : null); + /** + * The direction the device is moving at the position. + */ + this.heading = (head !== undefined ? head : null); + /** + * The velocity with which the device is moving at the position. + */ + this.speed = (vel !== undefined ? vel : null); + + if (this.speed === 0 || this.speed === null) { + this.heading = NaN; + } + + /** + * The altitude accuracy of the position. + */ + this.altitudeAccuracy = (altacc !== undefined) ? altacc : null; +}; + +module.exports = Coordinates; + +}); + +// file: lib/common/plugin/DirectoryEntry.js +define("cordova/plugin/DirectoryEntry", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + utils = require('cordova/utils'), + exec = require('cordova/exec'), + Entry = require('cordova/plugin/Entry'), + FileError = require('cordova/plugin/FileError'), + DirectoryReader = require('cordova/plugin/DirectoryReader'); + +/** + * An interface representing a directory on the file system. + * + * {boolean} isFile always false (readonly) + * {boolean} isDirectory always true (readonly) + * {DOMString} name of the directory, excluding the path leading to it (readonly) + * {DOMString} fullPath the absolute full path to the directory (readonly) + * TODO: implement this!!! {FileSystem} filesystem on which the directory resides (readonly) + */ +var DirectoryEntry = function(name, fullPath) { + DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath); +}; + +utils.extend(DirectoryEntry, Entry); + +/** + * Creates a new DirectoryReader to read entries from this directory + */ +DirectoryEntry.prototype.createReader = function() { + return new DirectoryReader(this.fullPath); +}; + +/** + * Creates or looks up a directory + * + * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory + * @param {Flags} options to create or exclusively create the directory + * @param {Function} successCallback is called with the new entry + * @param {Function} errorCallback is called with a FileError + */ +DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) { + argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments); + var win = successCallback && function(result) { + var entry = new DirectoryEntry(result.name, result.fullPath); + successCallback(entry); + }; + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; + exec(win, fail, "File", "getDirectory", [this.fullPath, path, options]); +}; + +/** + * Deletes a directory and all of it's contents + * + * @param {Function} successCallback is called with no parameters + * @param {Function} errorCallback is called with a FileError + */ +DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) { + argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments); + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; + exec(successCallback, fail, "File", "removeRecursively", [this.fullPath]); +}; + +/** + * Creates or looks up a file + * + * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file + * @param {Flags} options to create or exclusively create the file + * @param {Function} successCallback is called with the new entry + * @param {Function} errorCallback is called with a FileError + */ +DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) { + argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments); + var win = successCallback && function(result) { + var FileEntry = require('cordova/plugin/FileEntry'); + var entry = new FileEntry(result.name, result.fullPath); + successCallback(entry); + }; + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; + exec(win, fail, "File", "getFile", [this.fullPath, path, options]); +}; + +module.exports = DirectoryEntry; + +}); + +// file: lib/common/plugin/DirectoryReader.js +define("cordova/plugin/DirectoryReader", function(require, exports, module) { + +var exec = require('cordova/exec'), + FileError = require('cordova/plugin/FileError') ; + +/** + * An interface that lists the files and directories in a directory. + */ +function DirectoryReader(path) { + this.path = path || null; +} + +/** + * Returns a list of entries from a directory. + * + * @param {Function} successCallback is called with a list of entries + * @param {Function} errorCallback is called with a FileError + */ +DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) { + var win = typeof successCallback !== 'function' ? null : function(result) { + var retVal = []; + for (var i=0; i= 2) { + if (end < 0) { + newEnd = Math.max(size + end, 0); + } else { + newEnd = Math.min(end, size); + } + } + + var newFile = new File(this.name, this.fullPath, this.type, this.lastModifiedData, this.size); + newFile.start = this.start + newStart; + newFile.end = this.start + newEnd; + return newFile; +}; + + +module.exports = File; + +}); + +// file: lib/common/plugin/FileEntry.js +define("cordova/plugin/FileEntry", function(require, exports, module) { + +var utils = require('cordova/utils'), + exec = require('cordova/exec'), + Entry = require('cordova/plugin/Entry'), + FileWriter = require('cordova/plugin/FileWriter'), + File = require('cordova/plugin/File'), + FileError = require('cordova/plugin/FileError'); + +/** + * An interface representing a file on the file system. + * + * {boolean} isFile always true (readonly) + * {boolean} isDirectory always false (readonly) + * {DOMString} name of the file, excluding the path leading to it (readonly) + * {DOMString} fullPath the absolute full path to the file (readonly) + * {FileSystem} filesystem on which the file resides (readonly) + */ +var FileEntry = function(name, fullPath) { + FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath]); +}; + +utils.extend(FileEntry, Entry); + +/** + * Creates a new FileWriter associated with the file that this FileEntry represents. + * + * @param {Function} successCallback is called with the new FileWriter + * @param {Function} errorCallback is called with a FileError + */ +FileEntry.prototype.createWriter = function(successCallback, errorCallback) { + this.file(function(filePointer) { + var writer = new FileWriter(filePointer); + + if (writer.fileName === null || writer.fileName === "") { + errorCallback && errorCallback(new FileError(FileError.INVALID_STATE_ERR)); + } else { + successCallback && successCallback(writer); + } + }, errorCallback); +}; + +/** + * Returns a File that represents the current state of the file that this FileEntry represents. + * + * @param {Function} successCallback is called with the new File object + * @param {Function} errorCallback is called with a FileError + */ +FileEntry.prototype.file = function(successCallback, errorCallback) { + var win = successCallback && function(f) { + var file = new File(f.name, f.fullPath, f.type, f.lastModifiedDate, f.size); + successCallback(file); + }; + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; + exec(win, fail, "File", "getFileMetadata", [this.fullPath]); +}; + + +module.exports = FileEntry; + +}); + +// file: lib/common/plugin/FileError.js +define("cordova/plugin/FileError", function(require, exports, module) { + +/** + * FileError + */ +function FileError(error) { + this.code = error || null; +} + +// File error codes +// Found in DOMException +FileError.NOT_FOUND_ERR = 1; +FileError.SECURITY_ERR = 2; +FileError.ABORT_ERR = 3; + +// Added by File API specification +FileError.NOT_READABLE_ERR = 4; +FileError.ENCODING_ERR = 5; +FileError.NO_MODIFICATION_ALLOWED_ERR = 6; +FileError.INVALID_STATE_ERR = 7; +FileError.SYNTAX_ERR = 8; +FileError.INVALID_MODIFICATION_ERR = 9; +FileError.QUOTA_EXCEEDED_ERR = 10; +FileError.TYPE_MISMATCH_ERR = 11; +FileError.PATH_EXISTS_ERR = 12; + +module.exports = FileError; + +}); + +// file: lib/common/plugin/FileReader.js +define("cordova/plugin/FileReader", function(require, exports, module) { + +var exec = require('cordova/exec'), + modulemapper = require('cordova/modulemapper'), + utils = require('cordova/utils'), + File = require('cordova/plugin/File'), + FileError = require('cordova/plugin/FileError'), + ProgressEvent = require('cordova/plugin/ProgressEvent'), + origFileReader = modulemapper.getOriginalSymbol(this, 'FileReader'); + +/** + * This class reads the mobile device file system. + * + * For Android: + * The root directory is the root of the file system. + * To read from the SD card, the file name is "sdcard/my_file.txt" + * @constructor + */ +var FileReader = function() { + this._readyState = 0; + this._error = null; + this._result = null; + this._fileName = ''; + this._realReader = origFileReader ? new origFileReader() : {}; +}; + +// States +FileReader.EMPTY = 0; +FileReader.LOADING = 1; +FileReader.DONE = 2; + +utils.defineGetter(FileReader.prototype, 'readyState', function() { + return this._fileName ? this._readyState : this._realReader.readyState; +}); + +utils.defineGetter(FileReader.prototype, 'error', function() { + return this._fileName ? this._error: this._realReader.error; +}); + +utils.defineGetter(FileReader.prototype, 'result', function() { + return this._fileName ? this._result: this._realReader.result; +}); + +function defineEvent(eventName) { + utils.defineGetterSetter(FileReader.prototype, eventName, function() { + return this._realReader[eventName] || null; + }, function(value) { + this._realReader[eventName] = value; + }); +} +defineEvent('onloadstart'); // When the read starts. +defineEvent('onprogress'); // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total) +defineEvent('onload'); // When the read has successfully completed. +defineEvent('onerror'); // When the read has failed (see errors). +defineEvent('onloadend'); // When the request has completed (either in success or failure). +defineEvent('onabort'); // When the read has been aborted. For instance, by invoking the abort() method. + +function initRead(reader, file) { + // Already loading something + if (reader.readyState == FileReader.LOADING) { + throw new FileError(FileError.INVALID_STATE_ERR); + } + + reader._result = null; + reader._error = null; + reader._readyState = FileReader.LOADING; + + if (typeof file == 'string') { + // Deprecated in Cordova 2.4. + console.warning('Using a string argument with FileReader.readAs functions is deprecated.'); + reader._fileName = file; + } else if (typeof file.fullPath == 'string') { + reader._fileName = file.fullPath; + } else { + reader._fileName = ''; + return true; + } + + reader.onloadstart && reader.onloadstart(new ProgressEvent("loadstart", {target:reader})); +} + +/** + * Abort reading file. + */ +FileReader.prototype.abort = function() { + if (origFileReader && !this._fileName) { + return this._realReader.abort(); + } + this._result = null; + + if (this._readyState == FileReader.DONE || this._readyState == FileReader.EMPTY) { + return; + } + + this._readyState = FileReader.DONE; + + // If abort callback + if (typeof this.onabort === 'function') { + this.onabort(new ProgressEvent('abort', {target:this})); + } + // If load end callback + if (typeof this.onloadend === 'function') { + this.onloadend(new ProgressEvent('loadend', {target:this})); + } +}; + +/** + * Read text file. + * + * @param file {File} File object containing file properties + * @param encoding [Optional] (see http://www.iana.org/assignments/character-sets) + */ +FileReader.prototype.readAsText = function(file, encoding) { + if (initRead(this, file)) { + return this._realReader.readAsText(file, encoding); + } + + // Default encoding is UTF-8 + var enc = encoding ? encoding : "UTF-8"; + var me = this; + var execArgs = [this._fileName, enc]; + + // Maybe add slice parameters. + if (file.end < file.size) { + execArgs.push(file.start, file.end); + } else if (file.start > 0) { + execArgs.push(file.start); + } + + // Read file + exec( + // Success callback + function(r) { + // 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") { + me.onload(new ProgressEvent("load", {target:me})); + } + + // DONE state + me._readyState = FileReader.DONE; + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, + // Error callback + function(e) { + // If DONE (cancelled), then don't do anything + if (me._readyState === FileReader.DONE) { + return; + } + + // DONE state + me._readyState = FileReader.DONE; + + // null result + me._result = null; + + // Save error + me._error = new FileError(e); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {target:me})); + } + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, "File", "readAsText", execArgs); +}; + + +/** + * Read file and return data as a base64 encoded data url. + * A data url is of the form: + * data:[][;base64], + * + * @param file {File} File object containing file properties + */ +FileReader.prototype.readAsDataURL = function(file) { + if (initRead(this, file)) { + return this._realReader.readAsDataURL(file); + } + + var me = this; + var execArgs = [this._fileName]; + + // Maybe add slice parameters. + if (file.end < file.size) { + execArgs.push(file.start, file.end); + } else if (file.start > 0) { + execArgs.push(file.start); + } + + // Read file + exec( + // Success callback + function(r) { + // If DONE (cancelled), then don't do anything + if (me._readyState === FileReader.DONE) { + return; + } + + // DONE state + me._readyState = FileReader.DONE; + + // Save result + me._result = r; + + // If onload callback + if (typeof me.onload === "function") { + me.onload(new ProgressEvent("load", {target:me})); + } + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, + // Error callback + function(e) { + // If DONE (cancelled), then don't do anything + if (me._readyState === FileReader.DONE) { + return; + } + + // DONE state + me._readyState = FileReader.DONE; + + me._result = null; + + // Save error + me._error = new FileError(e); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {target:me})); + } + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + }, "File", "readAsDataURL", execArgs); +}; + +/** + * Read file and return data as a binary data. + * + * @param file {File} File object containing file properties + */ +FileReader.prototype.readAsBinaryString = function(file) { + if (initRead(this, file)) { + return this._realReader.readAsBinaryString(file); + } + // TODO - Can't return binary data to browser. + console.log('method "readAsBinaryString" is not supported at this time.'); + this.abort(); +}; + +/** + * Read file and return data as a binary data. + * + * @param file {File} File object containing file properties + */ +FileReader.prototype.readAsArrayBuffer = function(file) { + if (initRead(this, file)) { + return this._realReader.readAsArrayBuffer(file); + } + // TODO - Can't return binary data to browser. + console.log('This method is not supported at this time.'); + this.abort(); +}; + +module.exports = FileReader; + +}); + +// file: lib/common/plugin/FileSystem.js +define("cordova/plugin/FileSystem", function(require, exports, module) { + +var DirectoryEntry = require('cordova/plugin/DirectoryEntry'); + +/** + * An interface representing a file system + * + * @constructor + * {DOMString} name the unique name of the file system (readonly) + * {DirectoryEntry} root directory of the file system (readonly) + */ +var FileSystem = function(name, root) { + this.name = name || null; + if (root) { + this.root = new DirectoryEntry(root.name, root.fullPath); + } +}; + +module.exports = FileSystem; + +}); + +// file: lib/common/plugin/FileTransfer.js +define("cordova/plugin/FileTransfer", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + FileTransferError = require('cordova/plugin/FileTransferError'), + ProgressEvent = require('cordova/plugin/ProgressEvent'); + +function newProgressEvent(result) { + var pe = new ProgressEvent(); + pe.lengthComputable = result.lengthComputable; + pe.loaded = result.loaded; + pe.total = result.total; + return pe; +} + +var idCounter = 0; + +/** + * FileTransfer uploads a file to a remote server. + * @constructor + */ +var FileTransfer = function() { + this._id = ++idCounter; + this.onprogress = null; // optional callback +}; + +/** +* Given an absolute file path, uploads a file on the device to a remote server +* using a multipart HTTP request. +* @param filePath {String} Full path of the file on the device +* @param server {String} URL of the server to receive the file +* @param successCallback (Function} Callback to be invoked when upload has completed +* @param errorCallback {Function} Callback to be invoked upon error +* @param options {FileUploadOptions} Optional parameters such as file name and mimetype +* @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false +*/ +FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, trustAllHosts) { + argscheck.checkArgs('ssFFO*', 'FileTransfer.upload', arguments); + // check for options + var fileKey = null; + var fileName = null; + var mimeType = null; + var params = null; + var chunkedMode = true; + var headers = null; + if (options) { + fileKey = options.fileKey; + fileName = options.fileName; + mimeType = options.mimeType; + headers = options.headers; + if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") { + chunkedMode = options.chunkedMode; + } + if (options.params) { + params = options.params; + } + else { + params = {}; + } + } + + var fail = errorCallback && function(e) { + var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body); + errorCallback(error); + }; + + var self = this; + var win = function(result) { + if (typeof result.lengthComputable != "undefined") { + if (self.onprogress) { + self.onprogress(newProgressEvent(result)); + } + } else { + successCallback && successCallback(result); + } + }; + exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id]); +}; + +/** + * Downloads a file form a given URL and saves it to the specified directory. + * @param source {String} URL of the server to receive the file + * @param target {String} Full path of the file on the device + * @param successCallback (Function} Callback to be invoked when upload has completed + * @param errorCallback {Function} Callback to be invoked upon error + * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false + */ +FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts) { + argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments); + var self = this; + var win = function(result) { + if (typeof result.lengthComputable != "undefined") { + if (self.onprogress) { + return self.onprogress(newProgressEvent(result)); + } + } else if (successCallback) { + var entry = null; + if (result.isDirectory) { + entry = new (require('cordova/plugin/DirectoryEntry'))(); + } + else if (result.isFile) { + entry = new (require('cordova/plugin/FileEntry'))(); + } + entry.isDirectory = result.isDirectory; + entry.isFile = result.isFile; + entry.name = result.name; + entry.fullPath = result.fullPath; + successCallback(entry); + } + }; + + var fail = errorCallback && function(e) { + var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body); + errorCallback(error); + }; + + exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id]); +}; + +/** + * Aborts the ongoing file transfer on this object + * @param successCallback {Function} Callback to be invoked upon success + * @param errorCallback {Function} Callback to be invoked upon error + */ +FileTransfer.prototype.abort = function(successCallback, errorCallback) { + exec(successCallback, errorCallback, 'FileTransfer', 'abort', [this._id]); +}; + +module.exports = FileTransfer; + +}); + +// file: lib/common/plugin/FileTransferError.js +define("cordova/plugin/FileTransferError", function(require, exports, module) { + +/** + * FileTransferError + * @constructor + */ +var FileTransferError = function(code, source, target, status, body) { + this.code = code || null; + this.source = source || null; + this.target = target || null; + this.http_status = status || null; + this.body = body || null; +}; + +FileTransferError.FILE_NOT_FOUND_ERR = 1; +FileTransferError.INVALID_URL_ERR = 2; +FileTransferError.CONNECTION_ERR = 3; +FileTransferError.ABORT_ERR = 4; + +module.exports = FileTransferError; + +}); + +// file: lib/common/plugin/FileUploadOptions.js +define("cordova/plugin/FileUploadOptions", function(require, exports, module) { + +/** + * Options to customize the HTTP request used to upload files. + * @constructor + * @param fileKey {String} Name of file request parameter. + * @param fileName {String} Filename to be used by the server. Defaults to image.jpg. + * @param mimeType {String} Mimetype of the uploaded file. Defaults to image/jpeg. + * @param params {Object} Object with key: value params to send to the server. + * @param headers {Object} Keys are header names, values are header values. Multiple + * headers of the same name are not supported. + */ +var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers) { + this.fileKey = fileKey || null; + this.fileName = fileName || null; + this.mimeType = mimeType || null; + this.params = params || null; + this.headers = headers || null; +}; + +module.exports = FileUploadOptions; + +}); + +// file: lib/common/plugin/FileUploadResult.js +define("cordova/plugin/FileUploadResult", function(require, exports, module) { + +/** + * FileUploadResult + * @constructor + */ +var FileUploadResult = function() { + this.bytesSent = 0; + this.responseCode = null; + this.response = null; +}; + +module.exports = FileUploadResult; + +}); + +// file: lib/common/plugin/FileWriter.js +define("cordova/plugin/FileWriter", function(require, exports, module) { + +var exec = require('cordova/exec'), + FileError = require('cordova/plugin/FileError'), + ProgressEvent = require('cordova/plugin/ProgressEvent'); + +/** + * This class writes to the mobile device file system. + * + * For Android: + * The root directory is the root of the file system. + * To write to the SD card, the file name is "sdcard/my_file.txt" + * + * @constructor + * @param file {File} File object containing file properties + * @param append if true write to the end of the file, otherwise overwrite the file + */ +var 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 new FileError(FileError.INVALID_STATE_ERR); + } + + // set error + this.error = new FileError(FileError.ABORT_ERR); + + this.readyState = FileWriter.DONE; + + // If abort callback + if (typeof this.onabort === "function") { + this.onabort(new ProgressEvent("abort", {"target":this})); + } + + // If write end callback + if (typeof this.onwriteend === "function") { + this.onwriteend(new ProgressEvent("writeend", {"target":this})); + } +}; + +/** + * 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 new FileError(FileError.INVALID_STATE_ERR); + } + + // WRITING state + this.readyState = FileWriter.WRITING; + + var me = this; + + // If onwritestart callback + if (typeof me.onwritestart === "function") { + me.onwritestart(new ProgressEvent("writestart", {"target":me})); + } + + // Write file + exec( + // Success callback + function(r) { + // 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; + + // DONE state + me.readyState = FileWriter.DONE; + + // If onwrite callback + if (typeof me.onwrite === "function") { + me.onwrite(new ProgressEvent("write", {"target":me})); + } + + // If onwriteend callback + if (typeof me.onwriteend === "function") { + me.onwriteend(new ProgressEvent("writeend", {"target":me})); + } + }, + // Error callback + function(e) { + // If DONE (cancelled), then don't do anything + if (me.readyState === FileWriter.DONE) { + return; + } + + // DONE state + me.readyState = FileWriter.DONE; + + // Save error + me.error = new FileError(e); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {"target":me})); + } + + // If onwriteend callback + if (typeof me.onwriteend === "function") { + me.onwriteend(new ProgressEvent("writeend", {"target":me})); + } + }, "File", "write", [this.fileName, text, this.position]); +}; + +/** + * 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 new FileError(FileError.INVALID_STATE_ERR); + } + + if (!offset && offset !== 0) { + return; + } + + // See back from end of file. + if (offset < 0) { + this.position = Math.max(offset + this.length, 0); + } + // Offset is bigger than 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 new FileError(FileError.INVALID_STATE_ERR); + } + + // WRITING state + this.readyState = FileWriter.WRITING; + + var me = this; + + // If onwritestart callback + if (typeof me.onwritestart === "function") { + me.onwritestart(new ProgressEvent("writestart", {"target":this})); + } + + // Write file + exec( + // Success callback + function(r) { + // If DONE (cancelled), then don't do anything + if (me.readyState === FileWriter.DONE) { + return; + } + + // DONE state + me.readyState = FileWriter.DONE; + + // Update the length of the file + me.length = r; + me.position = Math.min(me.position, r); + + // If onwrite callback + if (typeof me.onwrite === "function") { + me.onwrite(new ProgressEvent("write", {"target":me})); + } + + // If onwriteend callback + if (typeof me.onwriteend === "function") { + me.onwriteend(new ProgressEvent("writeend", {"target":me})); + } + }, + // Error callback + function(e) { + // If DONE (cancelled), then don't do anything + if (me.readyState === FileWriter.DONE) { + return; + } + + // DONE state + me.readyState = FileWriter.DONE; + + // Save error + me.error = new FileError(e); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {"target":me})); + } + + // If onwriteend callback + if (typeof me.onwriteend === "function") { + me.onwriteend(new ProgressEvent("writeend", {"target":me})); + } + }, "File", "truncate", [this.fileName, size]); +}; + +module.exports = FileWriter; + +}); + +// file: lib/common/plugin/Flags.js +define("cordova/plugin/Flags", function(require, exports, module) { + +/** + * Supplies arguments to methods that lookup or create files and directories. + * + * @param create + * {boolean} file or directory if it doesn't exist + * @param exclusive + * {boolean} used with create; if true the command will fail if + * target path exists + */ +function Flags(create, exclusive) { + this.create = create || false; + this.exclusive = exclusive || false; +} + +module.exports = Flags; + +}); + +// file: lib/common/plugin/GlobalizationError.js +define("cordova/plugin/GlobalizationError", function(require, exports, module) { + + +/** + * Globalization error object + * + * @constructor + * @param code + * @param message + */ +var GlobalizationError = function(code, message) { + this.code = code || null; + this.message = message || ''; +}; + +// Globalization error codes +GlobalizationError.UNKNOWN_ERROR = 0; +GlobalizationError.FORMATTING_ERROR = 1; +GlobalizationError.PARSING_ERROR = 2; +GlobalizationError.PATTERN_ERROR = 3; + +module.exports = GlobalizationError; + +}); + +// file: lib/common/plugin/InAppBrowser.js +define("cordova/plugin/InAppBrowser", function(require, exports, module) { + +var exec = require('cordova/exec'); +var channel = require('cordova/channel'); + +function InAppBrowser() { + this.channels = { + 'loadstart': channel.create('loadstart'), + 'loadstop' : channel.create('loadstop'), + 'exit' : channel.create('exit') + }; +} + +InAppBrowser.prototype = { + _eventHandler: function (event) { + if (event.type in this.channels) { + this.channels[event.type].fire(event); + } + }, + close: function (eventname) { + exec(null, null, "InAppBrowser", "close", []); + }, + addEventListener: function (eventname,f) { + if (eventname in this.channels) { + this.channels[eventname].subscribe(f); + } + }, + removeEventListener: function(eventname, f) { + if (eventname in this.channels) { + this.channels[eventname].unsubscribe(f); + } + } +}; + +module.exports = function(strUrl, strWindowName, strWindowFeatures) { + var iab = new InAppBrowser(); + var cb = function(eventname) { + iab._eventHandler(eventname); + }; + exec(cb, null, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]); + return iab; +}; + + +}); + +// file: lib/common/plugin/LocalFileSystem.js +define("cordova/plugin/LocalFileSystem", function(require, exports, module) { + +var exec = require('cordova/exec'); + +/** + * Represents a local file system. + */ +var LocalFileSystem = function() { + +}; + +LocalFileSystem.TEMPORARY = 0; //temporary, with no guarantee of persistence +LocalFileSystem.PERSISTENT = 1; //persistent + +module.exports = LocalFileSystem; + +}); + +// file: lib/common/plugin/Media.js +define("cordova/plugin/Media", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + utils = require('cordova/utils'), + exec = require('cordova/exec'); + +var mediaObjects = {}; + +/** + * This class provides access to the device media, interfaces to both sound and video + * + * @constructor + * @param src The file name or url to play + * @param successCallback The callback to be called when the file is done playing or recording. + * successCallback() + * @param errorCallback The callback to be called if there is an error. + * errorCallback(int errorCode) - OPTIONAL + * @param statusCallback The callback to be called when media status has changed. + * statusCallback(int statusCode) - OPTIONAL + */ +var Media = function(src, successCallback, errorCallback, statusCallback) { + argscheck.checkArgs('SFFF', 'Media', arguments); + this.id = utils.createUUID(); + mediaObjects[this.id] = this; + this.src = src; + this.successCallback = successCallback; + this.errorCallback = errorCallback; + this.statusCallback = statusCallback; + this._duration = -1; + this._position = -1; + exec(null, this.errorCallback, "Media", "create", [this.id, this.src]); +}; + +// Media messages +Media.MEDIA_STATE = 1; +Media.MEDIA_DURATION = 2; +Media.MEDIA_POSITION = 3; +Media.MEDIA_ERROR = 9; + +// Media states +Media.MEDIA_NONE = 0; +Media.MEDIA_STARTING = 1; +Media.MEDIA_RUNNING = 2; +Media.MEDIA_PAUSED = 3; +Media.MEDIA_STOPPED = 4; +Media.MEDIA_MSG = ["None", "Starting", "Running", "Paused", "Stopped"]; + +// "static" function to return existing objs. +Media.get = function(id) { + return mediaObjects[id]; +}; + +/** + * Start or resume playing audio file. + */ +Media.prototype.play = function(options) { + exec(null, null, "Media", "startPlayingAudio", [this.id, this.src, options]); +}; + +/** + * Stop playing audio file. + */ +Media.prototype.stop = function() { + var me = this; + exec(function() { + me._position = 0; + }, this.errorCallback, "Media", "stopPlayingAudio", [this.id]); +}; + +/** + * Seek or jump to a new time in the track.. + */ +Media.prototype.seekTo = function(milliseconds) { + var me = this; + exec(function(p) { + me._position = p; + }, this.errorCallback, "Media", "seekToAudio", [this.id, milliseconds]); +}; + +/** + * Pause playing audio file. + */ +Media.prototype.pause = function() { + exec(null, this.errorCallback, "Media", "pausePlayingAudio", [this.id]); +}; + +/** + * Get duration of an audio file. + * The duration is only set for audio that is playing, paused or stopped. + * + * @return duration or -1 if not known. + */ +Media.prototype.getDuration = function() { + return this._duration; +}; + +/** + * Get position of audio. + */ +Media.prototype.getCurrentPosition = function(success, fail) { + var me = this; + exec(function(p) { + me._position = p; + success(p); + }, fail, "Media", "getCurrentPositionAudio", [this.id]); +}; + +/** + * Start recording audio file. + */ +Media.prototype.startRecord = function() { + exec(null, this.errorCallback, "Media", "startRecordingAudio", [this.id, this.src]); +}; + +/** + * Stop recording audio file. + */ +Media.prototype.stopRecord = function() { + exec(null, this.errorCallback, "Media", "stopRecordingAudio", [this.id]); +}; + +/** + * Release the resources. + */ +Media.prototype.release = function() { + exec(null, this.errorCallback, "Media", "release", [this.id]); +}; + +/** + * Adjust the volume. + */ +Media.prototype.setVolume = function(volume) { + exec(null, null, "Media", "setVolume", [this.id, volume]); +}; + +/** + * Audio has status update. + * PRIVATE + * + * @param id The media object id (string) + * @param msgType The 'type' of update this is + * @param value Use of value is determined by the msgType + */ +Media.onStatus = function(id, msgType, value) { + + var media = mediaObjects[id]; + + if(media) { + switch(msgType) { + case Media.MEDIA_STATE : + media.statusCallback && media.statusCallback(value); + if(value == Media.MEDIA_STOPPED) { + media.successCallback && media.successCallback(); + } + break; + case Media.MEDIA_DURATION : + media._duration = value; + break; + case Media.MEDIA_ERROR : + media.errorCallback && media.errorCallback(value); + break; + case Media.MEDIA_POSITION : + media._position = Number(value); + break; + default : + console.error && console.error("Unhandled Media.onStatus :: " + msgType); + break; + } + } + else { + console.error && console.error("Received Media.onStatus callback for unknown media :: " + id); + } + +}; + +module.exports = Media; + +}); + +// file: lib/common/plugin/MediaError.js +define("cordova/plugin/MediaError", function(require, exports, module) { + +/** + * This class contains information about any Media errors. +*/ +/* + According to :: http://dev.w3.org/html5/spec-author-view/video.html#mediaerror + We should never be creating these objects, we should just implement the interface + which has 1 property for an instance, 'code' + + instead of doing : + errorCallbackFunction( new MediaError(3,'msg') ); +we should simply use a literal : + errorCallbackFunction( {'code':3} ); + */ + + var _MediaError = window.MediaError; + + +if(!_MediaError) { + window.MediaError = _MediaError = function(code, msg) { + this.code = (typeof code != 'undefined') ? code : null; + this.message = msg || ""; // message is NON-standard! do not use! + }; +} + +_MediaError.MEDIA_ERR_NONE_ACTIVE = _MediaError.MEDIA_ERR_NONE_ACTIVE || 0; +_MediaError.MEDIA_ERR_ABORTED = _MediaError.MEDIA_ERR_ABORTED || 1; +_MediaError.MEDIA_ERR_NETWORK = _MediaError.MEDIA_ERR_NETWORK || 2; +_MediaError.MEDIA_ERR_DECODE = _MediaError.MEDIA_ERR_DECODE || 3; +_MediaError.MEDIA_ERR_NONE_SUPPORTED = _MediaError.MEDIA_ERR_NONE_SUPPORTED || 4; +// TODO: MediaError.MEDIA_ERR_NONE_SUPPORTED is legacy, the W3 spec now defines it as below. +// as defined by http://dev.w3.org/html5/spec-author-view/video.html#error-codes +_MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = _MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED || 4; + +module.exports = _MediaError; + +}); + +// file: lib/common/plugin/MediaFile.js +define("cordova/plugin/MediaFile", function(require, exports, module) { + +var utils = require('cordova/utils'), + exec = require('cordova/exec'), + File = require('cordova/plugin/File'), + CaptureError = require('cordova/plugin/CaptureError'); +/** + * Represents a single file. + * + * name {DOMString} name of the file, without path information + * fullPath {DOMString} the full path of the file, including the name + * type {DOMString} mime type + * lastModifiedDate {Date} last modified date + * size {Number} size of the file in bytes + */ +var MediaFile = function(name, fullPath, type, lastModifiedDate, size){ + MediaFile.__super__.constructor.apply(this, arguments); +}; + +utils.extend(MediaFile, File); + +/** + * Request capture format data for a specific file and type + * + * @param {Function} successCB + * @param {Function} errorCB + */ +MediaFile.prototype.getFormatData = function(successCallback, errorCallback) { + if (typeof this.fullPath === "undefined" || this.fullPath === null) { + errorCallback(new CaptureError(CaptureError.CAPTURE_INVALID_ARGUMENT)); + } else { + exec(successCallback, errorCallback, "Capture", "getFormatData", [this.fullPath, this.type]); + } +}; + +module.exports = MediaFile; + +}); + +// file: lib/common/plugin/MediaFileData.js +define("cordova/plugin/MediaFileData", function(require, exports, module) { + +/** + * MediaFileData encapsulates format information of a media file. + * + * @param {DOMString} codecs + * @param {long} bitrate + * @param {long} height + * @param {long} width + * @param {float} duration + */ +var MediaFileData = function(codecs, bitrate, height, width, duration){ + this.codecs = codecs || null; + this.bitrate = bitrate || 0; + this.height = height || 0; + this.width = width || 0; + this.duration = duration || 0; +}; + +module.exports = MediaFileData; + +}); + +// file: lib/common/plugin/Metadata.js +define("cordova/plugin/Metadata", function(require, exports, module) { + +/** + * Information about the state of the file or directory + * + * {Date} modificationTime (readonly) + */ +var Metadata = function(time) { + this.modificationTime = (typeof time != 'undefined'?new Date(time):null); +}; + +module.exports = Metadata; + +}); + +// file: lib/common/plugin/Position.js +define("cordova/plugin/Position", function(require, exports, module) { + +var Coordinates = require('cordova/plugin/Coordinates'); + +var Position = function(coords, timestamp) { + if (coords) { + this.coords = new Coordinates(coords.latitude, coords.longitude, coords.altitude, coords.accuracy, coords.heading, coords.velocity, coords.altitudeAccuracy); + } else { + this.coords = new Coordinates(); + } + this.timestamp = (timestamp !== undefined) ? timestamp : new Date(); +}; + +module.exports = Position; + +}); + +// file: lib/common/plugin/PositionError.js +define("cordova/plugin/PositionError", function(require, exports, module) { + +/** + * Position error object + * + * @constructor + * @param code + * @param message + */ +var PositionError = function(code, message) { + this.code = code || null; + this.message = message || ''; +}; + +PositionError.PERMISSION_DENIED = 1; +PositionError.POSITION_UNAVAILABLE = 2; +PositionError.TIMEOUT = 3; + +module.exports = PositionError; + +}); + +// file: lib/common/plugin/ProgressEvent.js +define("cordova/plugin/ProgressEvent", function(require, exports, module) { + +// If ProgressEvent exists in global context, use it already, otherwise use our own polyfill +// Feature test: See if we can instantiate a native ProgressEvent; +// if so, use that approach, +// otherwise fill-in with our own implementation. +// +// NOTE: right now we always fill in with our own. Down the road would be nice if we can use whatever is native in the webview. +var ProgressEvent = (function() { + /* + var createEvent = function(data) { + var event = document.createEvent('Events'); + event.initEvent('ProgressEvent', false, false); + if (data) { + for (var i in data) { + if (data.hasOwnProperty(i)) { + event[i] = data[i]; + } + } + if (data.target) { + // TODO: cannot call .dispatchEvent + // need to first figure out how to implement EventTarget + } + } + return event; + }; + try { + var ev = createEvent({type:"abort",target:document}); + return function ProgressEvent(type, data) { + data.type = type; + return createEvent(data); + }; + } catch(e){ + */ + return function ProgressEvent(type, dict) { + this.type = type; + this.bubbles = false; + this.cancelBubble = false; + this.cancelable = false; + this.lengthComputable = false; + this.loaded = dict && dict.loaded ? dict.loaded : 0; + this.total = dict && dict.total ? dict.total : 0; + this.target = dict && dict.target ? dict.target : null; + }; + //} +})(); + +module.exports = ProgressEvent; + +}); + +// file: lib/common/plugin/accelerometer.js +define("cordova/plugin/accelerometer", function(require, exports, module) { + +/** + * This class provides access to device accelerometer data. + * @constructor + */ +var argscheck = require('cordova/argscheck'), + utils = require("cordova/utils"), + exec = require("cordova/exec"), + Acceleration = require('cordova/plugin/Acceleration'); + +// Is the accel sensor running? +var running = false; + +// Keeps reference to watchAcceleration calls. +var timers = {}; + +// Array of listeners; used to keep track of when we should call start and stop. +var listeners = []; + +// Last returned acceleration object from native +var accel = null; + +// Tells native to start. +function start() { + exec(function(a) { + var tempListeners = listeners.slice(0); + accel = new Acceleration(a.x, a.y, a.z, a.timestamp); + for (var i = 0, l = tempListeners.length; i < l; i++) { + tempListeners[i].win(accel); + } + }, function(e) { + var tempListeners = listeners.slice(0); + for (var i = 0, l = tempListeners.length; i < l; i++) { + tempListeners[i].fail(e); + } + }, "Accelerometer", "start", []); + running = true; +} + +// Tells native to stop. +function stop() { + exec(null, null, "Accelerometer", "stop", []); + running = false; +} + +// Adds a callback pair to the listeners array +function createCallbackPair(win, fail) { + return {win:win, fail:fail}; +} + +// Removes a win/fail listener pair from the listeners array +function removeListeners(l) { + var idx = listeners.indexOf(l); + if (idx > -1) { + listeners.splice(idx, 1); + if (listeners.length === 0) { + stop(); + } + } +} + +var accelerometer = { + /** + * Asynchronously acquires the current acceleration. + * + * @param {Function} successCallback The function to call when the acceleration data is available + * @param {Function} errorCallback The function to call when there is an error getting the acceleration data. (OPTIONAL) + * @param {AccelerationOptions} options The options for getting the accelerometer data such as timeout. (OPTIONAL) + */ + getCurrentAcceleration: function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'accelerometer.getCurrentAcceleration', arguments); + + var p; + var win = function(a) { + removeListeners(p); + successCallback(a); + }; + var fail = function(e) { + removeListeners(p); + errorCallback && errorCallback(e); + }; + + p = createCallbackPair(win, fail); + listeners.push(p); + + if (!running) { + start(); + } + }, + + /** + * Asynchronously acquires the acceleration repeatedly at a given interval. + * + * @param {Function} successCallback The function to call each time the acceleration data is available + * @param {Function} errorCallback The function to call when there is an error getting the acceleration data. (OPTIONAL) + * @param {AccelerationOptions} options The options for getting the accelerometer data such as timeout. (OPTIONAL) + * @return String The watch id that must be passed to #clearWatch to stop watching. + */ + watchAcceleration: function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'accelerometer.watchAcceleration', arguments); + // Default interval (10 sec) + var frequency = (options && options.frequency && typeof options.frequency == 'number') ? options.frequency : 10000; + + // Keep reference to watch id, and report accel readings as often as defined in frequency + var id = utils.createUUID(); + + var p = createCallbackPair(function(){}, function(e) { + removeListeners(p); + errorCallback && errorCallback(e); + }); + listeners.push(p); + + timers[id] = { + timer:window.setInterval(function() { + if (accel) { + successCallback(accel); + } + }, frequency), + listeners:p + }; + + if (running) { + // If we're already running then immediately invoke the success callback + // but only if we have retrieved a value, sample code does not check for null ... + if (accel) { + successCallback(accel); + } + } else { + start(); + } + + return id; + }, + + /** + * Clears the specified accelerometer watch. + * + * @param {String} id The id of the watch returned from #watchAcceleration. + */ + clearWatch: function(id) { + // Stop javascript timer & remove from timer list + if (id && timers[id]) { + window.clearInterval(timers[id].timer); + removeListeners(timers[id].listeners); + delete timers[id]; + } + } +}; + +module.exports = accelerometer; + +}); + +// file: lib/common/plugin/accelerometer/symbols.js +define("cordova/plugin/accelerometer/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.defaults('cordova/plugin/Acceleration', 'Acceleration'); +modulemapper.defaults('cordova/plugin/accelerometer', 'navigator.accelerometer'); + +}); + +// file: lib/blackberry/plugin/air/DirectoryEntry.js +define("cordova/plugin/air/DirectoryEntry", function(require, exports, module) { + +var DirectoryEntry = require('cordova/plugin/DirectoryEntry'), + DirectoryReader = require('cordova/plugin/air/DirectoryReader'), + FileEntry = require('cordova/plugin/FileEntry'), + FileError = require('cordova/plugin/FileError'); + +var validFileRe = new RegExp('^[a-zA-Z][0-9a-zA-Z._ ]*$'); + +module.exports = { + createReader : function() { + return new DirectoryReader(this.fullPath); + }, + /** + * Creates or looks up a directory; override for BlackBerry. + * + * @param path + * {DOMString} either a relative or absolute path from this + * directory in which to look up or create a directory + * @param options + * {Flags} options to create or exclusively create the directory + * @param successCallback + * {Function} called with the new DirectoryEntry + * @param errorCallback + * {Function} called with a FileError + */ + getDirectory : function(path, options, successCallback, errorCallback) { + // create directory if it doesn't exist + var create = (options && options.create === true) ? true : false, + // if true, causes failure if create is true and path already exists + exclusive = (options && options.exclusive === true) ? true : false, + // directory exists + exists, + // create a new DirectoryEntry object and invoke success callback + createEntry = function() { + var path_parts = path.split('/'), + name = path_parts[path_parts.length - 1], + dirEntry = new DirectoryEntry(name, path); + + // invoke success callback + if (typeof successCallback === 'function') { + successCallback(dirEntry); + } + }; + + var fail = function(error) { + if (typeof errorCallback === 'function') { + errorCallback(new FileError(error)); + } + }; + + // invalid path + if(!validFileRe.exec(path)){ + fail(FileError.ENCODING_ERR); + return; + } + + // determine if path is relative or absolute + if (!path) { + fail(FileError.ENCODING_ERR); + return; + } else if (path.indexOf(this.fullPath) !== 0) { + // path does not begin with the fullPath of this directory + // therefore, it is relative + path = this.fullPath + '/' + path; + } + + // determine if directory exists + try { + // will return true if path exists AND is a directory + exists = blackberry.io.dir.exists(path); + } catch (e) { + // invalid path + // TODO this will not work on playbook - need to think how to find invalid urls + fail(FileError.ENCODING_ERR); + return; + } + + + // path is a directory + if (exists) { + if (create && exclusive) { + // can't guarantee exclusivity + fail(FileError.PATH_EXISTS_ERR); + } else { + // create entry for existing directory + createEntry(); + } + } + // will return true if path exists AND is a file + else if (blackberry.io.file.exists(path)) { + // the path is a file + fail(FileError.TYPE_MISMATCH_ERR); + } + // path does not exist, create it + else if (create) { + try { + // directory path must have trailing slash + var dirPath = path; + if (dirPath.substr(-1) !== '/') { + dirPath += '/'; + } + console.log('creating dir path at: ' + dirPath); + blackberry.io.dir.createNewDir(dirPath); + createEntry(); + } catch (eone) { + // unable to create directory + fail(FileError.NOT_FOUND_ERR); + } + } + // path does not exist, don't create + else { + // directory doesn't exist + fail(FileError.NOT_FOUND_ERR); + } + }, + + /** + * Create or look up a file. + * + * @param path {DOMString} + * either a relative or absolute path from this directory in + * which to look up or create a file + * @param options {Flags} + * options to create or exclusively create the file + * @param successCallback {Function} + * called with the new FileEntry object + * @param errorCallback {Function} + * called with a FileError object if error occurs + */ + getFile : function(path, options, successCallback, errorCallback) { + // create file if it doesn't exist + var create = (options && options.create === true) ? true : false, + // if true, causes failure if create is true and path already exists + exclusive = (options && options.exclusive === true) ? true : false, + // file exists + exists, + // create a new FileEntry object and invoke success callback + createEntry = function() { + var path_parts = path.split('/'), + name = path_parts[path_parts.length - 1], + fileEntry = new FileEntry(name, path); + + // invoke success callback + if (typeof successCallback === 'function') { + successCallback(fileEntry); + } + }; + + var fail = function(error) { + if (typeof errorCallback === 'function') { + errorCallback(new FileError(error)); + } + }; + + // invalid path + if(!validFileRe.exec(path)){ + fail(FileError.ENCODING_ERR); + return; + } + // determine if path is relative or absolute + if (!path) { + fail(FileError.ENCODING_ERR); + return; + } + else if (path.indexOf(this.fullPath) !== 0) { + // path does not begin with the fullPath of this directory + // therefore, it is relative + path = this.fullPath + '/' + path; + } + + // determine if file exists + try { + // will return true if path exists AND is a file + exists = blackberry.io.file.exists(path); + } + catch (e) { + // invalid path + fail(FileError.ENCODING_ERR); + return; + } + + // path is a file + if (exists) { + if (create && exclusive) { + // can't guarantee exclusivity + fail(FileError.PATH_EXISTS_ERR); + } + else { + // create entry for existing file + createEntry(); + } + } + // will return true if path exists AND is a directory + else if (blackberry.io.dir.exists(path)) { + // the path is a directory + fail(FileError.TYPE_MISMATCH_ERR); + } + // path does not exist, create it + else if (create) { + // create empty file + var emptyBlob = blackberry.utils.stringToBlob(''); + blackberry.io.file.saveFile(path,emptyBlob); + createEntry(); + } + // path does not exist, don't create + else { + // file doesn't exist + fail(FileError.NOT_FOUND_ERR); + } + }, + + /** + * Delete a directory and all of it's contents. + * + * @param successCallback {Function} called with no parameters + * @param errorCallback {Function} called with a FileError + */ + removeRecursively : function(successCallback, errorCallback) { + // we're removing THIS directory + var path = this.fullPath; + + var fail = function(error) { + if (typeof errorCallback === 'function') { + errorCallback(new FileError(error)); + } + }; + + // attempt to delete directory + if (blackberry.io.dir.exists(path)) { + // it is an error to attempt to remove the file system root + //exec(null, null, "File", "isFileSystemRoot", [ path ]) === true + if (false) { + fail(FileError.NO_MODIFICATION_ALLOWED_ERR); + } + else { + try { + // delete the directory, setting recursive flag to true + blackberry.io.dir.deleteDirectory(path, true); + if (typeof successCallback === "function") { + successCallback(); + } + } catch (e) { + // permissions don't allow deletion + console.log(e); + fail(FileError.NO_MODIFICATION_ALLOWED_ERR); + } + } + } + // it's a file, not a directory + else if (blackberry.io.file.exists(path)) { + fail(FileError.TYPE_MISMATCH_ERR); + } + // not found + else { + fail(FileError.NOT_FOUND_ERR); + } + } +}; + +}); + +// file: lib/blackberry/plugin/air/DirectoryReader.js +define("cordova/plugin/air/DirectoryReader", function(require, exports, module) { + +var FileError = require('cordova/plugin/FileError'); + +/** + * An interface that lists the files and directories in a directory. + */ +function DirectoryReader(path) { + this.path = path || null; +} + +/** + * Returns a list of entries from a directory. + * + * @param {Function} successCallback is called with a list of entries + * @param {Function} errorCallback is called with a FileError + */ +DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) { + var win = typeof successCallback !== 'function' ? null : function(result) { + var retVal = []; + for (var i=0; i=0) || blackberry.io.file.exists(dstPath)){ + // copying directory into child or is file path + fail(FileError.INVALID_MODIFICATION_ERR); + }else{ + recursiveCopy(srcPath, dstPath); + + theEntry.fullPath = dstPath; + theEntry.name = name; + theEntry.isDirectory = true; + theEntry.isFile = false; + success(theEntry); + } + }else{ + // directory onto itself + fail(FileError.INVALID_MODIFICATION_ERR); + } + } + + }, + + remove : function(successCallback, errorCallback) { + var path = this.fullPath, + // directory contents + contents = []; + + var fail = function(error) { + if (typeof errorCallback === 'function') { + errorCallback(new FileError(error)); + } + }; + + // file + if (blackberry.io.file.exists(path)) { + try { + blackberry.io.file.deleteFile(path); + if (typeof successCallback === "function") { + successCallback(); + } + } catch (e) { + // permissions don't allow + fail(FileError.INVALID_MODIFICATION_ERR); + } + } + // directory + else if (blackberry.io.dir.exists(path)) { + // it is an error to attempt to remove the file system root + console.log('entry directory'); + // TODO: gotta figure out how to get root dirs on playbook - + // getRootDirs doesn't work + if (false) { + fail(FileError.NO_MODIFICATION_ALLOWED_ERR); + } else { + // check to see if directory is empty + contents = blackberry.io.dir.listFiles(path); + if (contents.length !== 0) { + fail(FileError.INVALID_MODIFICATION_ERR); + } else { + try { + // delete + blackberry.io.dir.deleteDirectory(path, false); + if (typeof successCallback === "function") { + successCallback(); + } + } catch (eone) { + // permissions don't allow + fail(FileError.NO_MODIFICATION_ALLOWED_ERR); + } + } + } + } + // not found + else { + fail(FileError.NOT_FOUND_ERR); + } + }, + getParent : function(successCallback, errorCallback) { + var that = this; + + try { + // On BlackBerry, the TEMPORARY file system is actually a temporary + // directory that is created on a per-application basis. This is + // to help ensure that applications do not share the same temporary + // space. So we check to see if this is the TEMPORARY file system + // (directory). If it is, we must return this Entry, rather than + // the Entry for its parent. + requestFileSystem(LocalFileSystem.TEMPORARY, 0, + function(fileSystem) { + if (fileSystem.root.fullPath === that.fullPath) { + if (typeof successCallback === 'function') { + successCallback(fileSystem.root); + } + } else { + resolveLocalFileSystemURI(blackberry.io.dir + .getParentDirectory(that.fullPath), + successCallback, errorCallback); + } + }, errorCallback); + } catch (e) { + if (typeof errorCallback === 'function') { + errorCallback(new FileError(FileError.NOT_FOUND_ERR)); + } + } + } +}; + + +}); + +// file: lib/blackberry/plugin/air/File.js +define("cordova/plugin/air/File", function(require, exports, module) { + +/** + * Constructor. + * name {DOMString} name of the file, without path information + * fullPath {DOMString} the full path of the file, including the name + * type {DOMString} mime type + * lastModifiedDate {Date} last modified date + * size {Number} size of the file in bytes + */ + +var File = function(name, fullPath, type, lastModifiedDate, size){ + this.name = name || ''; + this.fullPath = fullPath || null; + this.type = type || null; + this.lastModifiedDate = lastModifiedDate || null; + this.size = size || 0; +}; + +module.exports = File; + +}); + +// file: lib/blackberry/plugin/air/FileEntry.js +define("cordova/plugin/air/FileEntry", function(require, exports, module) { + +var FileEntry = require('cordova/plugin/FileEntry'), + Entry = require('cordova/plugin/air/Entry'), + FileWriter = require('cordova/plugin/air/FileWriter'), + File = require('cordova/plugin/air/File'), + FileError = require('cordova/plugin/FileError'); + +module.exports = { + /** + * Creates a new FileWriter associated with the file that this FileEntry represents. + * + * @param {Function} successCallback is called with the new FileWriter + * @param {Function} errorCallback is called with a FileError + */ + createWriter : function(successCallback, errorCallback) { + this.file(function(filePointer) { + var writer = new FileWriter(filePointer); + + if (writer.fileName === null || writer.fileName === "") { + if (typeof errorCallback === "function") { + errorCallback(new FileError(FileError.INVALID_STATE_ERR)); + } + } else { + if (typeof successCallback === "function") { + successCallback(writer); + } + } + }, errorCallback); + }, + + /** + * Returns a File that represents the current state of the file that this FileEntry represents. + * + * @param {Function} successCallback is called with the new File object + * @param {Function} errorCallback is called with a FileError + */ + file : function(successCallback, errorCallback) { + var win = typeof successCallback !== 'function' ? null : function(f) { + var file = new File(f.name, f.fullPath, f.type, f.lastModifiedDate, f.size); + successCallback(file); + }; + var fail = typeof errorCallback !== 'function' ? null : function(code) { + errorCallback(new FileError(code)); + }; + + if(blackberry.io.file.exists(this.fullPath)){ + var theFileProperties = blackberry.io.file.getFileProperties(this.fullPath); + var theFile = {}; + + theFile.fullPath = this.fullPath; + theFile.type = theFileProperties.fileExtension; + theFile.lastModifiedDate = theFileProperties.dateModified; + theFile.size = theFileProperties.size; + win(theFile); + }else{ + fail(FileError.NOT_FOUND_ERR); + } + } +}; + + +}); + +// file: lib/blackberry/plugin/air/FileReader.js +define("cordova/plugin/air/FileReader", function(require, exports, module) { + +var FileError = require('cordova/plugin/FileError'), + ProgressEvent = require('cordova/plugin/ProgressEvent'); + +/** + * This class reads the mobile device file system. + * + * For Android: + * The root directory is the root of the file system. + * To read from the SD card, the file name is "sdcard/my_file.txt" + * @constructor + */ +var FileReader = function() { + this.fileName = ""; + + this.readyState = 0; // FileReader.EMPTY + + // File data + this.result = null; + + // Error + this.error = null; + + // Event handlers + this.onloadstart = null; // When the read starts. + this.onprogress = null; // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total) + this.onload = null; // When the read has successfully completed. + this.onerror = null; // When the read has failed (see errors). + this.onloadend = null; // When the request has completed (either in success or failure). + this.onabort = null; // When the read has been aborted. For instance, by invoking the abort() method. +}; + +// States +FileReader.EMPTY = 0; +FileReader.LOADING = 1; +FileReader.DONE = 2; + +/** + * Abort reading file. + */ +FileReader.prototype.abort = function() { + this.result = null; + + if (this.readyState == FileReader.DONE || this.readyState == FileReader.EMPTY) { + return; + } + + this.readyState = FileReader.DONE; + + // If abort callback + if (typeof this.onabort === 'function') { + this.onabort(new ProgressEvent('abort', {target:this})); + } + // If load end callback + if (typeof this.onloadend === 'function') { + this.onloadend(new ProgressEvent('loadend', {target:this})); + } +}; + +/** + * Read text file. + * + * @param file {File} File object containing file properties + * @param encoding [Optional] (see http://www.iana.org/assignments/character-sets) + */ +FileReader.prototype.readAsText = function(file, encoding) { + // Figure out pathing + this.fileName = ''; + if (typeof file.fullPath === 'undefined') { + this.fileName = file; + } else { + this.fileName = file.fullPath; + } + + // Already loading something + if (this.readyState == FileReader.LOADING) { + throw new FileError(FileError.INVALID_STATE_ERR); + } + + // LOADING state + this.readyState = FileReader.LOADING; + + // If loadstart callback + if (typeof this.onloadstart === "function") { + this.onloadstart(new ProgressEvent("loadstart", {target:this})); + } + + // Default encoding is UTF-8 + var enc = encoding ? encoding : "UTF-8"; + + var me = this; + // Read file + if(blackberry.io.file.exists(this.fileName)){ + var theText = ''; + var getFileContents = function(path,blob){ + if(blob){ + + theText = blackberry.utils.blobToString(blob, enc); + me.result = theText; + + if (typeof me.onload === "function") { + me.onload(new ProgressEvent("load", {target:me})); + } + + me.readyState = FileReader.DONE; + + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + } + }; + // setting asynch to off + blackberry.io.file.readFile(this.fileName, getFileContents, false); + + }else{ + // If DONE (cancelled), then don't do anything + if (me.readyState === FileReader.DONE) { + return; + } + + // DONE state + me.readyState = FileReader.DONE; + + me.result = null; + + // Save error + me.error = new FileError(FileError.NOT_FOUND_ERR); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {target:me})); + } + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + } +}; + + +/** + * Read file and return data as a base64 encoded data url. + * A data url is of the form: + * data:[][;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; + } + + // Already loading something + if (this.readyState == FileReader.LOADING) { + throw new FileError(FileError.INVALID_STATE_ERR); + } + + // LOADING state + this.readyState = FileReader.LOADING; + + // If loadstart callback + if (typeof this.onloadstart === "function") { + this.onloadstart(new ProgressEvent("loadstart", {target:this})); + } + + var enc = "BASE64"; + + var me = this; + + // Read file + if(blackberry.io.file.exists(this.fileName)){ + var theText = ''; + var getFileContents = function(path,blob){ + if(blob){ + theText = blackberry.utils.blobToString(blob, enc); + me.result = "data:text/plain;base64," +theText; + + if (typeof me.onload === "function") { + me.onload(new ProgressEvent("load", {target:me})); + } + + me.readyState = FileReader.DONE; + + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + } + }; + // setting asynch to off + blackberry.io.file.readFile(this.fileName, getFileContents, false); + + }else{ + // If DONE (cancelled), then don't do anything + if (me.readyState === FileReader.DONE) { + return; + } + + // DONE state + me.readyState = FileReader.DONE; + + me.result = null; + + // Save error + me.error = new FileError(FileError.NOT_FOUND_ERR); + + // If onerror callback + if (typeof me.onerror === "function") { + me.onerror(new ProgressEvent("error", {target:me})); + } + + // If onloadend callback + if (typeof me.onloadend === "function") { + me.onloadend(new ProgressEvent("loadend", {target:me})); + } + } +}; + +/** + * Read file and return data as a binary data. + * + * @param file {File} File object containing file properties + */ +FileReader.prototype.readAsBinaryString = function(file) { + // TODO - Can't return binary data to browser. + console.log('method "readAsBinaryString" is not supported at this time.'); +}; + +/** + * Read file and return data as a binary data. + * + * @param file {File} File object containing file properties + */ +FileReader.prototype.readAsArrayBuffer = function(file) { + // TODO - Can't return binary data to browser. + console.log('This method is not supported at this time.'); +}; + +module.exports = FileReader; + +}); + +// file: lib/blackberry/plugin/air/FileTransfer.js +define("cordova/plugin/air/FileTransfer", function(require, exports, module) { + +var cordova = require('cordova'), +FileTransferError = require('cordova/plugin/FileTransferError'), +FileUploadResult = require('cordova/plugin/FileUploadResult'); + +var validURLProtocol = new RegExp('^(https?|ftp):\/\/'); + +function getParentPath(filePath) { + var pos = filePath.lastIndexOf('/'); + return filePath.substring(0, pos + 1); +} + +function getFileName(filePath) { + var pos = filePath.lastIndexOf('/'); + return filePath.substring(pos + 1); +} + +module.exports = { + upload: function (args, win, fail) { + var filePath = args[0], + server = args[1], + fileKey = args[2], + fileName = args[3], + mimeType = args[4], + params = args[5], + trustAllHosts = args[6], + chunkedMode = args[7], + headers = args[8]; + + if(!validURLProtocol.exec(server)){ + return { "status" : cordova.callbackStatus.ERROR, "message" : new FileTransferError(FileTransferError.INVALID_URL_ERR) }; + } + + window.resolveLocalFileSystemURI(filePath, fileWin, fail); + + function fileWin(entryObject){ + blackberry.io.file.readFile(filePath, readWin, false); + } + + function readWin(filePath, blobFile){ + var fd = new FormData(); + + fd.append(fileKey, blobFile, fileName); + for (var prop in params) { + if(params.hasOwnProperty(prop)) { + fd.append(prop, params[prop]); + } + } + + var xhr = new XMLHttpRequest(); + xhr.open("POST", server); + xhr.onload = function(evt) { + if (xhr.status == 200) { + var result = new FileUploadResult(); + result.bytesSent = xhr.response.length; + result.responseCode = xhr.status; + result.response = xhr.response; + win(result); + } else if (xhr.status == 404) { + fail(new FileTransferError(FileTransferError.INVALID_URL_ERR, null, null, xhr.status)); + } else if (xhr.status == 403) { + fail(new FileTransferError(FileTransferError.INVALID_URL_ERR, null, null, xhr.status)); + } else { + fail(new FileTransferError(FileTransferError.CONNECTION_ERR, null, null, xhr.status)); + } + }; + xhr.ontimeout = function(evt) { + fail(new FileTransferError(FileTransferError.CONNECTION_ERR, null, null, xhr.status)); + }; + + if(headers){ + for(var i in headers){ + xhr.setRequestHeader(i, headers[i]); + } + } + xhr.send(fd); + } + + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "WebWorks Is On It" }; + }, + + download: function(args, win, fail){ + var url = args[0], + filePath = args[1]; + + if(!validURLProtocol.exec(url)){ + return { "status" : cordova.callbackStatus.ERROR, "message" : new FileTransferError(FileTransferError.INVALID_URL_ERR) }; + } + + var xhr = new XMLHttpRequest(); + + function writeFile(fileEntry) { + fileEntry.createWriter(function(writer) { + writer.onwriteend = function(evt) { + if (!evt.target.error) { + win(new window.FileEntry(fileEntry.name, fileEntry.toURL())); + } else { + fail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR)); + } + }; + + writer.onerror = function(evt) { + fail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR)); + }; + + var blob = blackberry.utils.stringToBlob(xhr.response); + writer.write(blob); + + }, + function(error) { + fail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR)); + }); + } + + xhr.onreadystatechange = function () { + if (xhr.readyState == xhr.DONE) { + if (xhr.status == 200 && xhr.response) { + window.resolveLocalFileSystemURI(getParentPath(filePath), function(dir) { + dir.getFile(getFileName(filePath), {create: true}, writeFile, function(error) { + fail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR)); + }); + }, function(error) { + fail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR)); + }); + } else if (xhr.status == 404) { + fail(new FileTransferError(FileTransferError.INVALID_URL_ERR, null, null, xhr.status)); + } else { + fail(new FileTransferError(FileTransferError.CONNECTION_ERR, null, null, xhr.status)); + } + } + }; + + xhr.open("GET", url, true); + xhr.responseType = "arraybuffer"; + xhr.send(); + + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "WebWorks Is On It" }; + } +}; + +}); + +// file: lib/blackberry/plugin/air/FileWriter.js +define("cordova/plugin/air/FileWriter", function(require, exports, module) { + +var FileError = require('cordova/plugin/FileError'), + ProgressEvent = require('cordova/plugin/ProgressEvent'); + +/** + * @constructor + * @param file {File} File object containing file properties + * @param append if true write to the end of the file, otherwise overwrite the file + */ +var 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 new FileError(FileError.INVALID_STATE_ERR); + } + + // set error + this.error = new FileError(FileError.ABORT_ERR); + + this.readyState = FileWriter.DONE; + + // If abort callback + if (typeof this.onabort === "function") { + this.onabort(new ProgressEvent("abort", {"target":this})); + } + + // If write end callback + if (typeof this.onwriteend === "function") { + this.onwriteend(new ProgressEvent("writeend", {"target":this})); + } +}; + +/** + * 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 new FileError(FileError.INVALID_STATE_ERR); + } + + // WRITING state + this.readyState = FileWriter.WRITING; + + var me = this; + + // If onwritestart callback + if (typeof me.onwritestart === "function") { + me.onwritestart(new ProgressEvent("writestart", {"target":me})); + } + + var textBlob = blackberry.utils.stringToBlob(text); + + if(blackberry.io.file.exists(this.fileName)){ + + var oldText = ''; + var newText = text; + + var getFileContents = function(path,blob){ + + if(blob){ + oldText = blackberry.utils.blobToString(blob); + if(oldText.length>0){ + newText = oldText.substr(0,me.position) + text; + } + } + + var tempFile = me.fileName+'temp'; + if(blackberry.io.file.exists(tempFile)){ + blackberry.io.file.deleteFile(tempFile); + } + + var newTextBlob = blackberry.utils.stringToBlob(newText); + + // crete a temp file, delete file we are 'overwriting', then rename temp file + blackberry.io.file.saveFile(tempFile, newTextBlob); + blackberry.io.file.deleteFile(me.fileName); + blackberry.io.file.rename(tempFile, me.fileName.split('/').pop()); + + me.position = newText.length; + me.length = me.position; + + if (typeof me.onwrite === "function") { + me.onwrite(new ProgressEvent("write", {"target":me})); + } + }; + + // setting asynch to off + blackberry.io.file.readFile(this.fileName, getFileContents, false); + + }else{ + + // file is new so just save it + blackberry.io.file.saveFile(this.fileName, textBlob); + me.position = text.length; + me.length = me.position; + } + + me.readyState = FileWriter.DONE; + + if (typeof me.onwriteend === "function") { + me.onwriteend(new ProgressEvent("writeend", {"target":me})); + } +}; + +/** + * 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 new FileError(FileError.INVALID_STATE_ERR); + } + + if (!offset && offset !== 0) { + return; + } + + // See back from end of file. + if (offset < 0) { + this.position = Math.max(offset + this.length, 0); + } + // Offset is bigger than 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 new FileError(FileError.INVALID_STATE_ERR); + } + + // WRITING state + this.readyState = FileWriter.WRITING; + + var me = this; + + // If onwritestart callback + if (typeof me.onwritestart === "function") { + me.onwritestart(new ProgressEvent("writestart", {"target":this})); + } + + if(blackberry.io.file.exists(this.fileName)){ + + var oldText = ''; + var newText = ''; + + var getFileContents = function(path,blob){ + + if(blob){ + oldText = blackberry.utils.blobToString(blob); + if(oldText.length>0){ + newText = oldText.slice(0,size); + }else{ + // TODO: throw error + } + } + + var tempFile = me.fileName+'temp'; + if(blackberry.io.file.exists(tempFile)){ + blackberry.io.file.deleteFile(tempFile); + } + + var newTextBlob = blackberry.utils.stringToBlob(newText); + + // crete a temp file, delete file we are 'overwriting', then rename temp file + blackberry.io.file.saveFile(tempFile, newTextBlob); + blackberry.io.file.deleteFile(me.fileName); + blackberry.io.file.rename(tempFile, me.fileName.split('/').pop()); + + me.position = newText.length; + me.length = me.position; + + if (typeof me.onwrite === "function") { + me.onwrite(new ProgressEvent("write", {"target":me})); + } + }; + + // setting asynch to off - worry about making this all callbacks later + blackberry.io.file.readFile(this.fileName, getFileContents, false); + + }else{ + + // TODO: file doesn't exist - throw error + + } + + me.readyState = FileWriter.DONE; + + if (typeof me.onwriteend === "function") { + me.onwriteend(new ProgressEvent("writeend", {"target":me})); + } +}; + +module.exports = FileWriter; + +}); + +// file: lib/blackberry/plugin/air/battery.js +define("cordova/plugin/air/battery", function(require, exports, module) { + +var cordova = require('cordova'); + +module.exports = { + start: function (args, win, fail) { + // Register one listener to each of the level and state change + // events using WebWorks API. + blackberry.system.event.deviceBatteryStateChange(function(state) { + var me = navigator.battery; + // state is either CHARGING or UNPLUGGED + if (state === 2 || state === 3) { + var info = { + "level" : me._level, + "isPlugged" : state === 2 + }; + + if (me._isPlugged !== info.isPlugged && typeof win === 'function') { + win(info); + } + } + }); + blackberry.system.event.deviceBatteryLevelChange(function(level) { + var me = navigator.battery; + if (level != me._level && typeof win === 'function') { + win({'level' : level, 'isPlugged' : me._isPlugged}); + } + }); + + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "WebWorks Is On It" }; + }, + stop: function (args, win, fail) { + // Unregister battery listeners. + blackberry.system.event.deviceBatteryStateChange(null); + blackberry.system.event.deviceBatteryLevelChange(null); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "WebWorks Is On It" }; + } +}; + +}); + +// file: lib/blackberry/plugin/air/camera.js +define("cordova/plugin/air/camera", function(require, exports, module) { + +var cordova = require('cordova'); + +module.exports = { + takePicture: function (args, win, fail) { + var onCaptured = blackberry.events.registerEventHandler("onCaptured", win), + onCameraClosed = blackberry.events.registerEventHandler("onCameraClosed", function () {}), + onError = blackberry.events.registerEventHandler("onError", fail), + request = new blackberry.transport.RemoteFunctionCall('blackberry/media/camera/takePicture'); + + request.addParam("onCaptured", onCaptured); + request.addParam("onCameraClosed", onCameraClosed); + request.addParam("onError", onError); + + //HACK: this is a sync call due to: + //https://github.com/blackberry/WebWorks-TabletOS/issues/51 + request.makeSyncCall(); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "WebWorks Is On It" }; + } +}; + +}); + +// file: lib/blackberry/plugin/air/capture.js +define("cordova/plugin/air/capture", function(require, exports, module) { + +var cordova = require('cordova'); + +function capture(action, win, fail) { + var onCaptured = blackberry.events.registerEventHandler("onCaptured", function (path) { + var file = blackberry.io.file.getFileProperties(path); + win([{ + fullPath: path, + lastModifiedDate: file.dateModified, + name: path.replace(file.directory + "/", ""), + size: file.size, + type: file.fileExtension + }]); + }), + onCameraClosed = blackberry.events.registerEventHandler("onCameraClosed", function () {}), + onError = blackberry.events.registerEventHandler("onError", fail), + request = new blackberry.transport.RemoteFunctionCall('blackberry/media/camera/' + action); + + request.addParam("onCaptured", onCaptured); + request.addParam("onCameraClosed", onCameraClosed); + request.addParam("onError", onError); + + //HACK: this is a sync call due to: + //https://github.com/blackberry/WebWorks-TabletOS/issues/51 + request.makeSyncCall(); +} + +module.exports = { + getSupportedAudioModes: function (args, win, fail) { + return {"status": cordova.callbackStatus.OK, "message": []}; + }, + getSupportedImageModes: function (args, win, fail) { + return {"status": cordova.callbackStatus.OK, "message": []}; + }, + getSupportedVideoModes: function (args, win, fail) { + return {"status": cordova.callbackStatus.OK, "message": []}; + }, + captureImage: function (args, win, fail) { + if (args[0].limit > 0) { + capture("takePicture", win, fail); + } + else { + win([]); + } + + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "WebWorks Is On It" }; + }, + captureVideo: function (args, win, fail) { + if (args[0].limit > 0) { + capture("takeVideo", win, fail); + } + else { + win([]); + } + + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "WebWorks Is On It" }; + }, + captureAudio: function (args, win, fail) { + var onCaptureAudioWin = function(filePath){ + // for some reason the filePath is coming back as a string between two double quotes + filePath = filePath.slice(1, filePath.length-1); + var file = blackberry.io.file.getFileProperties(filePath); + + win([{ + fullPath: filePath, + lastModifiedDate: file.dateModified, + name: filePath.replace(file.directory + "/", ""), + size: file.size, + type: file.fileExtension + }]); + }; + + var onCaptureAudioFail = function(){ + fail([]); + }; + + if (args[0].limit > 0 && args[0].duration){ + // a sloppy way of creating a uuid since there's no built in date function to get milliseconds since epoch + // might be better to instead check files within directory and then figure out the next file name should be + // ie, img000 -> img001 though that would take awhile and would add a whole bunch of checks + var id = new Date(); + id = (id.getDay()).toString() + (id.getHours()).toString() + (id.getSeconds()).toString() + (id.getMilliseconds()).toString() + (id.getYear()).toString(); + + var fileName = blackberry.io.dir.appDirs.shared.music.path+'/audio'+id+'.wav'; + blackberry.media.microphone.record(fileName, onCaptureAudioWin, onCaptureAudioFail); + // multiple duration by a 1000 since it comes in as seconds + setTimeout(blackberry.media.microphone.stop,args[0].duration*1000); + } + else { + win([]); + } + return {"status": cordova.callbackStatus.NO_RESULT, "message": "WebWorks Is On It"}; + } +}; + +}); + +// file: lib/blackberry/plugin/air/device.js +define("cordova/plugin/air/device", function(require, exports, module) { + +var channel = require('cordova/channel'), + cordova = require('cordova'); + +// Tell cordova channel to wait on the CordovaInfoReady event +channel.waitForInitialization('onCordovaInfoReady'); + +module.exports = { + getDeviceInfo : function(args, win, fail){ + //Register an event handler for the networkChange event + var callback = blackberry.events.registerEventHandler("deviceInfo", function (info) { + win({ + platform: "BlackBerry", + version: info.version, + model: "PlayBook", + name: "PlayBook", // deprecated: please use device.model + uuid: info.uuid, + cordova: "2.5.0" + }); + }), + request = new blackberry.transport.RemoteFunctionCall("org/apache/cordova/getDeviceInfo"); + + request.addParam("id", callback); + request.makeSyncCall(); + + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "" }; + } +}; + +}); + +// file: lib/blackberry/plugin/air/file/bbsymbols.js +define("cordova/plugin/air/file/bbsymbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/air/DirectoryReader', 'DirectoryReader'); +modulemapper.clobbers('cordova/plugin/air/File', 'File'); +modulemapper.clobbers('cordova/plugin/air/FileReader', 'FileReader'); +modulemapper.clobbers('cordova/plugin/air/FileWriter', 'FileWriter'); +modulemapper.clobbers('cordova/plugin/air/requestFileSystem', 'requestFileSystem'); +modulemapper.clobbers('cordova/plugin/air/resolveLocalFileSystemURI', 'resolveLocalFileSystemURI'); +modulemapper.merges('cordova/plugin/air/DirectoryEntry', 'DirectoryEntry'); +modulemapper.merges('cordova/plugin/air/Entry', 'Entry'); +modulemapper.merges('cordova/plugin/air/FileEntry', 'FileEntry'); + + +}); + +// file: lib/blackberry/plugin/air/manager.js +define("cordova/plugin/air/manager", function(require, exports, module) { + +var cordova = require('cordova'), + plugins = { + 'Device' : require('cordova/plugin/air/device'), + 'Battery' : require('cordova/plugin/air/battery'), + 'Camera' : require('cordova/plugin/air/camera'), + 'Logger' : require('cordova/plugin/webworks/logger'), + 'Media' : require('cordova/plugin/webworks/media'), + 'Capture' : require('cordova/plugin/air/capture'), + 'Accelerometer' : require('cordova/plugin/webworks/accelerometer'), + 'NetworkStatus' : require('cordova/plugin/air/network'), + 'Notification' : require('cordova/plugin/webworks/notification'), + 'FileTransfer' : require('cordova/plugin/air/FileTransfer') + }; + +module.exports = { + addPlugin: function (key, module) { + plugins[key] = require(module); + }, + exec: function (win, fail, clazz, action, args) { + var result = {"status" : cordova.callbackStatus.CLASS_NOT_FOUND_EXCEPTION, "message" : "Class " + clazz + " cannot be found"}; + + if (plugins[clazz]) { + if (plugins[clazz][action]) { + result = plugins[clazz][action](args, win, fail); + } + else { + result = { "status" : cordova.callbackStatus.INVALID_ACTION, "message" : "Action not found: " + action }; + } + } + + return result; + }, + resume: function () {}, + pause: function () {}, + destroy: function () {} +}; + +}); + +// file: lib/blackberry/plugin/air/network.js +define("cordova/plugin/air/network", function(require, exports, module) { + +var cordova = require('cordova'), + connection = require('cordova/plugin/Connection'); + +module.exports = { + getConnectionInfo: function (args, win, fail) { + var connectionType = connection.NONE, + eventType = "offline", + callbackID, + request; + + /** + * For PlayBooks, we currently only have WiFi connections, so + * return WiFi if there is any access at all. + * TODO: update if/when PlayBook gets other connection types... + */ + if (blackberry.system.hasDataCoverage()) { + connectionType = connection.WIFI; + eventType = "online"; + } + + //Register an event handler for the networkChange event + callbackID = blackberry.events.registerEventHandler("networkChange", function (status) { + win(status.type); + }); + + //pass our callback id down to our network extension + request = new blackberry.transport.RemoteFunctionCall("org/apache/cordova/getConnectionInfo"); + request.addParam("networkStatusChangedID", callbackID); + request.makeSyncCall(); + + return { "status": cordova.callbackStatus.OK, "message": connectionType}; + } +}; + +}); + +// file: lib/blackberry/plugin/air/platform.js +define("cordova/plugin/air/platform", function(require, exports, module) { + +module.exports = { + id: "playbook", + initialize:function() {} +}; + +}); + +// file: lib/blackberry/plugin/air/requestFileSystem.js +define("cordova/plugin/air/requestFileSystem", function(require, exports, module) { + +var DirectoryEntry = require('cordova/plugin/DirectoryEntry'), +FileError = require('cordova/plugin/FileError'), +FileSystem = require('cordova/plugin/FileSystem'), +LocalFileSystem = require('cordova/plugin/LocalFileSystem'); + +/** + * Request a file system in which to store application data. + * @param type local file system type + * @param size indicates how much storage space, in bytes, the application expects to need + * @param successCallback invoked with a FileSystem object + * @param errorCallback invoked if error occurs retrieving file system + */ +var requestFileSystem = function(type, size, successCallback, errorCallback) { + var fail = function(code) { + if (typeof errorCallback === 'function') { + errorCallback(new FileError(code)); + } + }; + + if (type < 0 || type > 3) { + fail(FileError.SYNTAX_ERR); + } else { + // if successful, return a FileSystem object + var success = function(file_system) { + if (file_system) { + if (typeof successCallback === 'function') { + successCallback(file_system); + } + } + else { + // no FileSystem object returned + fail(FileError.NOT_FOUND_ERR); + } + }; + + // guessing the max file size is 2GB - 1 bytes? + // https://bdsc.webapps.blackberry.com/native/documentation/com.qnx.doc.neutrino.user_guide/topic/limits_filesystems.html + + if(size>=2147483648){ + fail(FileError.QUOTA_EXCEEDED_ERR); + return; + } + + + var theFileSystem; + try{ + // is there a way to get space for the app that doesn't point to the appDirs folder? + if(type==LocalFileSystem.TEMPORARY){ + theFileSystem = new FileSystem('temporary', new DirectoryEntry('root', blackberry.io.dir.appDirs.app.storage.path)); + }else if(type==LocalFileSystem.PERSISTENT){ + theFileSystem = new FileSystem('persistent', new DirectoryEntry('root', blackberry.io.dir.appDirs.app.storage.path)); + } + success(theFileSystem); + }catch(e){ + fail(FileError.SYNTAX_ERR); + } + } +}; +module.exports = requestFileSystem; + +}); + +// file: lib/blackberry/plugin/air/resolveLocalFileSystemURI.js +define("cordova/plugin/air/resolveLocalFileSystemURI", function(require, exports, module) { + +var DirectoryEntry = require('cordova/plugin/DirectoryEntry'), + FileEntry = require('cordova/plugin/FileEntry'), + FileError = require('cordova/plugin/FileError'); + +/** + * Look up file system Entry referred to by local URI. + * @param {DOMString} uri URI referring to a local file or directory + * @param successCallback invoked with Entry object corresponding to URI + * @param errorCallback invoked if error occurs retrieving file system entry + */ +module.exports = function(uri, successCallback, errorCallback) { + // error callback + var fail = function(error) { + if (typeof errorCallback === 'function') { + errorCallback(new FileError(error)); + } + }; + // if successful, return either a file or directory entry + var success = function(entry) { + var result; + + if (entry) { + if (typeof successCallback === 'function') { + // create appropriate Entry object + result = (entry.isDirectory) ? new DirectoryEntry(entry.name, entry.fullPath) : new FileEntry(entry.name, entry.fullPath); + try { + successCallback(result); + } + catch (e) { + console.log('Error invoking callback: ' + e); + } + } + } + else { + // no Entry object returned + fail(FileError.NOT_FOUND_ERR); + return; + } + }; + + if(!uri || uri === ""){ + fail(FileError.NOT_FOUND_ERR); + return; + } + + // decode uri if % char found + if(uri.indexOf('%')>=0){ + uri = decodeURI(uri); + } + + // pop the parameters if any + if(uri.indexOf('?')>=0){ + uri = uri.split('?')[0]; + } + + // check for leading / + if(uri.indexOf('/')===0){ + fail(FileError.ENCODING_ERR); + return; + } + + // Entry object is borked - unable to instantiate a new Entry object so just create one + var theEntry = {}; + if(blackberry.io.dir.exists(uri)){ + theEntry.isDirectory = true; + theEntry.name = uri.split('/').pop(); + theEntry.fullPath = uri; + + success(theEntry); + }else if(blackberry.io.file.exists(uri)){ + theEntry.isDirectory = false; + theEntry.name = uri.split('/').pop(); + theEntry.fullPath = uri; + success(theEntry); + return; + }else{ + fail(FileError.NOT_FOUND_ERR); + return; + } + +}; + +}); + +// file: lib/common/plugin/battery.js +define("cordova/plugin/battery", function(require, exports, module) { + +/** + * This class contains information about the current battery status. + * @constructor + */ +var cordova = require('cordova'), + exec = require('cordova/exec'); + +function handlers() { + return battery.channels.batterystatus.numHandlers + + battery.channels.batterylow.numHandlers + + battery.channels.batterycritical.numHandlers; +} + +var Battery = function() { + this._level = null; + this._isPlugged = null; + // Create new event handlers on the window (returns a channel instance) + this.channels = { + batterystatus:cordova.addWindowEventHandler("batterystatus"), + batterylow:cordova.addWindowEventHandler("batterylow"), + batterycritical:cordova.addWindowEventHandler("batterycritical") + }; + for (var key in this.channels) { + this.channels[key].onHasSubscribersChange = Battery.onHasSubscribersChange; + } +}; +/** + * Event handlers for when callbacks get registered for the battery. + * Keep track of how many handlers we have so we can start and stop the native battery listener + * appropriately (and hopefully save on battery life!). + */ +Battery.onHasSubscribersChange = function() { + // If we just registered the first handler, make sure native listener is started. + if (this.numHandlers === 1 && handlers() === 1) { + exec(battery._status, battery._error, "Battery", "start", []); + } else if (handlers() === 0) { + exec(null, null, "Battery", "stop", []); + } +}; + +/** + * Callback for battery status + * + * @param {Object} info keys: level, isPlugged + */ +Battery.prototype._status = function(info) { + if (info) { + var me = battery; + var level = info.level; + if (me._level !== level || me._isPlugged !== info.isPlugged) { + // Fire batterystatus event + cordova.fireWindowEvent("batterystatus", info); + + // Fire low battery event + if (level === 20 || level === 5) { + if (level === 20) { + cordova.fireWindowEvent("batterylow", info); + } + else { + cordova.fireWindowEvent("batterycritical", info); + } + } + } + me._level = level; + me._isPlugged = info.isPlugged; + } +}; + +/** + * Error callback for battery start + */ +Battery.prototype._error = function(e) { + console.log("Error initializing Battery: " + e); +}; + +var battery = new Battery(); + +module.exports = battery; + +}); + +// file: lib/common/plugin/battery/symbols.js +define("cordova/plugin/battery/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.defaults('cordova/plugin/battery', 'navigator.battery'); + +}); + +// file: lib/common/plugin/camera/symbols.js +define("cordova/plugin/camera/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.defaults('cordova/plugin/Camera', 'navigator.camera'); +modulemapper.defaults('cordova/plugin/CameraConstants', 'Camera'); +modulemapper.defaults('cordova/plugin/CameraPopoverOptions', 'CameraPopoverOptions'); + +}); + +// file: lib/common/plugin/capture.js +define("cordova/plugin/capture", function(require, exports, module) { + +var exec = require('cordova/exec'), + MediaFile = require('cordova/plugin/MediaFile'); + +/** + * Launches a capture of different types. + * + * @param (DOMString} type + * @param {Function} successCB + * @param {Function} errorCB + * @param {CaptureVideoOptions} options + */ +function _capture(type, successCallback, errorCallback, options) { + var win = function(pluginResult) { + var mediaFiles = []; + var i; + for (i = 0; i < pluginResult.length; i++) { + var mediaFile = new MediaFile(); + mediaFile.name = pluginResult[i].name; + mediaFile.fullPath = pluginResult[i].fullPath; + mediaFile.type = pluginResult[i].type; + mediaFile.lastModifiedDate = pluginResult[i].lastModifiedDate; + mediaFile.size = pluginResult[i].size; + mediaFiles.push(mediaFile); + } + successCallback(mediaFiles); + }; + exec(win, errorCallback, "Capture", type, [options]); +} +/** + * 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 + */ +Capture.prototype.captureAudio = function(successCallback, errorCallback, options){ + _capture("captureAudio", successCallback, errorCallback, options); +}; + +/** + * Launch camera application for taking image(s). + * + * @param {Function} successCB + * @param {Function} errorCB + * @param {CaptureImageOptions} options + */ +Capture.prototype.captureImage = function(successCallback, errorCallback, options){ + _capture("captureImage", successCallback, errorCallback, options); +}; + +/** + * Launch device camera application for recording video(s). + * + * @param {Function} successCB + * @param {Function} errorCB + * @param {CaptureVideoOptions} options + */ +Capture.prototype.captureVideo = function(successCallback, errorCallback, options){ + _capture("captureVideo", successCallback, errorCallback, options); +}; + + +module.exports = new Capture(); + +}); + +// file: lib/common/plugin/capture/symbols.js +define("cordova/plugin/capture/symbols", function(require, exports, module) { + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/CaptureError', 'CaptureError'); +modulemapper.clobbers('cordova/plugin/CaptureAudioOptions', 'CaptureAudioOptions'); +modulemapper.clobbers('cordova/plugin/CaptureImageOptions', 'CaptureImageOptions'); +modulemapper.clobbers('cordova/plugin/CaptureVideoOptions', 'CaptureVideoOptions'); +modulemapper.clobbers('cordova/plugin/ConfigurationData', 'ConfigurationData'); +modulemapper.clobbers('cordova/plugin/MediaFile', 'MediaFile'); +modulemapper.clobbers('cordova/plugin/MediaFileData', 'MediaFileData'); +modulemapper.clobbers('cordova/plugin/capture', 'navigator.device.capture'); + +}); + +// file: lib/common/plugin/compass.js +define("cordova/plugin/compass", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + utils = require('cordova/utils'), + CompassHeading = require('cordova/plugin/CompassHeading'), + CompassError = require('cordova/plugin/CompassError'), + timers = {}, + compass = { + /** + * Asynchronously acquires the current heading. + * @param {Function} successCallback The function to call when the heading + * data is available + * @param {Function} errorCallback The function to call when there is an error + * getting the heading data. + * @param {CompassOptions} options The options for getting the heading data (not used). + */ + getCurrentHeading:function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'compass.getCurrentHeading', arguments); + + var win = function(result) { + var ch = new CompassHeading(result.magneticHeading, result.trueHeading, result.headingAccuracy, result.timestamp); + successCallback(ch); + }; + var fail = errorCallback && function(code) { + var ce = new CompassError(code); + errorCallback(ce); + }; + + // Get heading + exec(win, fail, "Compass", "getHeading", [options]); + }, + + /** + * Asynchronously acquires the heading repeatedly at a given interval. + * @param {Function} successCallback The function to call each time the heading + * data is available + * @param {Function} errorCallback The function to call when there is an error + * getting the heading data. + * @param {HeadingOptions} options The options for getting the heading data + * such as timeout and the frequency of the watch. For iOS, filter parameter + * specifies to watch via a distance filter rather than time. + */ + watchHeading:function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'compass.watchHeading', arguments); + // Default interval (100 msec) + var frequency = (options !== undefined && options.frequency !== undefined) ? options.frequency : 100; + var filter = (options !== undefined && options.filter !== undefined) ? options.filter : 0; + + var id = utils.createUUID(); + if (filter > 0) { + // is an iOS request for watch by filter, no timer needed + timers[id] = "iOS"; + compass.getCurrentHeading(successCallback, errorCallback, options); + } else { + // Start watch timer to get headings + timers[id] = window.setInterval(function() { + compass.getCurrentHeading(successCallback, errorCallback); + }, frequency); + } + + return id; + }, + + /** + * Clears the specified heading watch. + * @param {String} watchId The ID of the watch returned from #watchHeading. + */ + clearWatch:function(id) { + // Stop javascript timer & remove from timer list + if (id && timers[id]) { + if (timers[id] != "iOS") { + clearInterval(timers[id]); + } else { + // is iOS watch by filter so call into device to stop + exec(null, null, "Compass", "stopHeading", []); + } + delete timers[id]; + } + } + }; + +module.exports = compass; + +}); + +// file: lib/common/plugin/compass/symbols.js +define("cordova/plugin/compass/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/CompassHeading', 'CompassHeading'); +modulemapper.clobbers('cordova/plugin/CompassError', 'CompassError'); +modulemapper.clobbers('cordova/plugin/compass', 'navigator.compass'); + +}); + +// file: lib/common/plugin/console-via-logger.js +define("cordova/plugin/console-via-logger", function(require, exports, module) { + +//------------------------------------------------------------------------------ + +var logger = require("cordova/plugin/logger"); +var utils = require("cordova/utils"); + +//------------------------------------------------------------------------------ +// object that we're exporting +//------------------------------------------------------------------------------ +var console = module.exports; + +//------------------------------------------------------------------------------ +// copy of the original console object +//------------------------------------------------------------------------------ +var WinConsole = window.console; + +//------------------------------------------------------------------------------ +// whether to use the logger +//------------------------------------------------------------------------------ +var UseLogger = false; + +//------------------------------------------------------------------------------ +// Timers +//------------------------------------------------------------------------------ +var Timers = {}; + +//------------------------------------------------------------------------------ +// used for unimplemented methods +//------------------------------------------------------------------------------ +function noop() {} + +//------------------------------------------------------------------------------ +// used for unimplemented methods +//------------------------------------------------------------------------------ +console.useLogger = function (value) { + if (arguments.length) UseLogger = !!value; + + if (UseLogger) { + if (logger.useConsole()) { + throw new Error("console and logger are too intertwingly"); + } + } + + return UseLogger; +}; + +//------------------------------------------------------------------------------ +console.log = function() { + if (logger.useConsole()) return; + logger.log.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.error = function() { + if (logger.useConsole()) return; + logger.error.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.warn = function() { + if (logger.useConsole()) return; + logger.warn.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.info = function() { + if (logger.useConsole()) return; + logger.info.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.debug = function() { + if (logger.useConsole()) return; + logger.debug.apply(logger, [].slice.call(arguments)); +}; + +//------------------------------------------------------------------------------ +console.assert = function(expression) { + if (expression) return; + + var message = utils.vformat(arguments[1], [].slice.call(arguments, 2)); + console.log("ASSERT: " + message); +}; + +//------------------------------------------------------------------------------ +console.clear = function() {}; + +//------------------------------------------------------------------------------ +console.dir = function(object) { + console.log("%o", object); +}; + +//------------------------------------------------------------------------------ +console.dirxml = function(node) { + console.log(node.innerHTML); +}; + +//------------------------------------------------------------------------------ +console.trace = noop; + +//------------------------------------------------------------------------------ +console.group = console.log; + +//------------------------------------------------------------------------------ +console.groupCollapsed = console.log; + +//------------------------------------------------------------------------------ +console.groupEnd = noop; + +//------------------------------------------------------------------------------ +console.time = function(name) { + Timers[name] = new Date().valueOf(); +}; + +//------------------------------------------------------------------------------ +console.timeEnd = function(name) { + var timeStart = Timers[name]; + if (!timeStart) { + console.warn("unknown timer: " + name); + return; + } + + var timeElapsed = new Date().valueOf() - timeStart; + console.log(name + ": " + timeElapsed + "ms"); +}; + +//------------------------------------------------------------------------------ +console.timeStamp = noop; + +//------------------------------------------------------------------------------ +console.profile = noop; + +//------------------------------------------------------------------------------ +console.profileEnd = noop; + +//------------------------------------------------------------------------------ +console.count = noop; + +//------------------------------------------------------------------------------ +console.exception = console.log; + +//------------------------------------------------------------------------------ +console.table = function(data, columns) { + console.log("%o", data); +}; + +//------------------------------------------------------------------------------ +// return a new function that calls both functions passed as args +//------------------------------------------------------------------------------ +function wrappedOrigCall(orgFunc, newFunc) { + return function() { + var args = [].slice.call(arguments); + try { orgFunc.apply(WinConsole, args); } catch (e) {} + try { newFunc.apply(console, args); } catch (e) {} + }; +} + +//------------------------------------------------------------------------------ +// For every function that exists in the original console object, that +// also exists in the new console object, wrap the new console method +// with one that calls both +//------------------------------------------------------------------------------ +for (var key in console) { + if (typeof WinConsole[key] == "function") { + console[key] = wrappedOrigCall(WinConsole[key], console[key]); + } +} + +}); + +// file: lib/common/plugin/contacts.js +define("cordova/plugin/contacts", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + ContactError = require('cordova/plugin/ContactError'), + utils = require('cordova/utils'), + Contact = require('cordova/plugin/Contact'); + +/** +* Represents a group of Contacts. +* @constructor +*/ +var contacts = { + /** + * Returns an array of Contacts matching the search criteria. + * @param fields that should be searched + * @param successCB success callback + * @param errorCB error callback + * @param {ContactFindOptions} options that can be applied to contact searching + * @return array of Contacts matching search criteria + */ + find:function(fields, successCB, errorCB, options) { + argscheck.checkArgs('afFO', 'contacts.find', arguments); + if (!fields.length) { + errorCB && errorCB(new ContactError(ContactError.INVALID_ARGUMENT_ERROR)); + } else { + var win = function(result) { + var cs = []; + for (var i = 0, l = result.length; i < l; i++) { + cs.push(contacts.create(result[i])); + } + successCB(cs); + }; + exec(win, errorCB, "Contacts", "search", [fields, options]); + } + }, + + /** + * This function creates a new contact, but it does not persist the contact + * to device storage. To persist the contact to device storage, invoke + * contact.save(). + * @param properties an object whose properties will be examined to create a new Contact + * @returns new Contact object + */ + create:function(properties) { + argscheck.checkArgs('O', 'contacts.create', arguments); + var contact = new Contact(); + for (var i in properties) { + if (typeof contact[i] !== 'undefined' && properties.hasOwnProperty(i)) { + contact[i] = properties[i]; + } + } + return contact; + } +}; + +module.exports = contacts; + +}); + +// file: lib/common/plugin/contacts/symbols.js +define("cordova/plugin/contacts/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/contacts', 'navigator.contacts'); +modulemapper.clobbers('cordova/plugin/Contact', 'Contact'); +modulemapper.clobbers('cordova/plugin/ContactAddress', 'ContactAddress'); +modulemapper.clobbers('cordova/plugin/ContactError', 'ContactError'); +modulemapper.clobbers('cordova/plugin/ContactField', 'ContactField'); +modulemapper.clobbers('cordova/plugin/ContactFindOptions', 'ContactFindOptions'); +modulemapper.clobbers('cordova/plugin/ContactName', 'ContactName'); +modulemapper.clobbers('cordova/plugin/ContactOrganization', 'ContactOrganization'); + +}); + +// file: lib/common/plugin/device.js +define("cordova/plugin/device", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + channel = require('cordova/channel'), + utils = require('cordova/utils'), + exec = require('cordova/exec'); + +// Tell cordova channel to wait on the CordovaInfoReady event +channel.waitForInitialization('onCordovaInfoReady'); + +/** + * This represents the mobile device, and provides properties for inspecting the model, version, UUID of the + * phone, etc. + * @constructor + */ +function Device() { + this.available = false; + this.platform = null; + this.version = null; + this.name = null; + this.uuid = null; + this.cordova = null; + this.model = null; + + var me = this; + + channel.onCordovaReady.subscribe(function() { + me.getInfo(function(info) { + me.available = true; + me.platform = info.platform; + me.version = info.version; + me.name = info.name; + me.uuid = info.uuid; + me.cordova = info.cordova; + me.model = info.model; + channel.onCordovaInfoReady.fire(); + },function(e) { + me.available = false; + utils.alert("[ERROR] Error initializing Cordova: " + e); + }); + }); +} + +/** + * Get device info + * + * @param {Function} successCallback The function to call when the heading data is available + * @param {Function} errorCallback The function to call when there is an error getting the heading data. (OPTIONAL) + */ +Device.prototype.getInfo = function(successCallback, errorCallback) { + argscheck.checkArgs('fF', 'Device.getInfo', arguments); + exec(successCallback, errorCallback, "Device", "getDeviceInfo", []); +}; + +module.exports = new Device(); + +}); + +// file: lib/common/plugin/device/symbols.js +define("cordova/plugin/device/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/device', 'device'); + +}); + +// file: lib/common/plugin/echo.js +define("cordova/plugin/echo", function(require, exports, module) { + +var exec = require('cordova/exec'), + utils = require('cordova/utils'); + +/** + * Sends the given message through exec() to the Echo plugin, which sends it back to the successCallback. + * @param successCallback invoked with a FileSystem object + * @param errorCallback invoked if error occurs retrieving file system + * @param message The string to be echoed. + * @param forceAsync Whether to force an async return value (for testing native->js bridge). + */ +module.exports = function(successCallback, errorCallback, message, forceAsync) { + var action = 'echo'; + var messageIsMultipart = (utils.typeName(message) == "Array"); + var args = messageIsMultipart ? message : [message]; + + if (utils.typeName(message) == 'ArrayBuffer') { + if (forceAsync) { + console.warn('Cannot echo ArrayBuffer with forced async, falling back to sync.'); + } + action += 'ArrayBuffer'; + } else if (messageIsMultipart) { + if (forceAsync) { + console.warn('Cannot echo MultiPart Array with forced async, falling back to sync.'); + } + action += 'MultiPart'; + } else if (forceAsync) { + action += 'Async'; + } + + exec(successCallback, errorCallback, "Echo", action, args); +}; + + +}); + +// file: lib/common/plugin/file/symbols.js +define("cordova/plugin/file/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'), + symbolshelper = require('cordova/plugin/file/symbolshelper'); + +symbolshelper(modulemapper.defaults); + +}); + +// file: lib/common/plugin/file/symbolshelper.js +define("cordova/plugin/file/symbolshelper", function(require, exports, module) { + +module.exports = function(exportFunc) { + exportFunc('cordova/plugin/DirectoryEntry', 'DirectoryEntry'); + exportFunc('cordova/plugin/DirectoryReader', 'DirectoryReader'); + exportFunc('cordova/plugin/Entry', 'Entry'); + exportFunc('cordova/plugin/File', 'File'); + exportFunc('cordova/plugin/FileEntry', 'FileEntry'); + exportFunc('cordova/plugin/FileError', 'FileError'); + exportFunc('cordova/plugin/FileReader', 'FileReader'); + exportFunc('cordova/plugin/FileSystem', 'FileSystem'); + exportFunc('cordova/plugin/FileUploadOptions', 'FileUploadOptions'); + exportFunc('cordova/plugin/FileUploadResult', 'FileUploadResult'); + exportFunc('cordova/plugin/FileWriter', 'FileWriter'); + exportFunc('cordova/plugin/Flags', 'Flags'); + exportFunc('cordova/plugin/LocalFileSystem', 'LocalFileSystem'); + exportFunc('cordova/plugin/Metadata', 'Metadata'); + exportFunc('cordova/plugin/ProgressEvent', 'ProgressEvent'); + exportFunc('cordova/plugin/requestFileSystem', 'requestFileSystem'); + exportFunc('cordova/plugin/resolveLocalFileSystemURI', 'resolveLocalFileSystemURI'); +}; + +}); + +// file: lib/common/plugin/filetransfer/symbols.js +define("cordova/plugin/filetransfer/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/FileTransfer', 'FileTransfer'); +modulemapper.clobbers('cordova/plugin/FileTransferError', 'FileTransferError'); + +}); + +// file: lib/common/plugin/geolocation.js +define("cordova/plugin/geolocation", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + utils = require('cordova/utils'), + exec = require('cordova/exec'), + PositionError = require('cordova/plugin/PositionError'), + Position = require('cordova/plugin/Position'); + +var timers = {}; // list of timers in use + +// Returns default params, overrides if provided with values +function parseParameters(options) { + var opt = { + maximumAge: 0, + enableHighAccuracy: false, + timeout: Infinity + }; + + if (options) { + if (options.maximumAge !== undefined && !isNaN(options.maximumAge) && options.maximumAge > 0) { + opt.maximumAge = options.maximumAge; + } + if (options.enableHighAccuracy !== undefined) { + opt.enableHighAccuracy = options.enableHighAccuracy; + } + if (options.timeout !== undefined && !isNaN(options.timeout)) { + if (options.timeout < 0) { + opt.timeout = 0; + } else { + opt.timeout = options.timeout; + } + } + } + + return opt; +} + +// Returns a timeout failure, closed over a specified timeout value and error callback. +function createTimeout(errorCallback, timeout) { + var t = setTimeout(function() { + clearTimeout(t); + t = null; + errorCallback({ + code:PositionError.TIMEOUT, + message:"Position retrieval timed out." + }); + }, timeout); + return t; +} + +var geolocation = { + lastPosition:null, // reference to last known (cached) position returned + /** + * Asynchronously acquires the current position. + * + * @param {Function} successCallback The function to call when the position data is available + * @param {Function} errorCallback The function to call when there is an error getting the heading position. (OPTIONAL) + * @param {PositionOptions} options The options for getting the position data. (OPTIONAL) + */ + getCurrentPosition:function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'geolocation.getCurrentPosition', arguments); + options = parseParameters(options); + + // Timer var that will fire an error callback if no position is retrieved from native + // before the "timeout" param provided expires + var timeoutTimer = {timer:null}; + + var win = function(p) { + clearTimeout(timeoutTimer.timer); + if (!(timeoutTimer.timer)) { + // Timeout already happened, or native fired error callback for + // this geo request. + // Don't continue with success callback. + return; + } + var pos = new Position( + { + latitude:p.latitude, + longitude:p.longitude, + altitude:p.altitude, + accuracy:p.accuracy, + heading:p.heading, + velocity:p.velocity, + altitudeAccuracy:p.altitudeAccuracy + }, + (p.timestamp === undefined ? new Date() : ((p.timestamp instanceof Date) ? p.timestamp : new Date(p.timestamp))) + ); + geolocation.lastPosition = pos; + successCallback(pos); + }; + var fail = function(e) { + clearTimeout(timeoutTimer.timer); + timeoutTimer.timer = null; + var err = new PositionError(e.code, e.message); + if (errorCallback) { + errorCallback(err); + } + }; + + // Check our cached position, if its timestamp difference with current time is less than the maximumAge, then just + // fire the success callback with the cached position. + if (geolocation.lastPosition && options.maximumAge && (((new Date()).getTime() - geolocation.lastPosition.timestamp.getTime()) <= options.maximumAge)) { + successCallback(geolocation.lastPosition); + // If the cached position check failed and the timeout was set to 0, error out with a TIMEOUT error object. + } else if (options.timeout === 0) { + fail({ + code:PositionError.TIMEOUT, + message:"timeout value in PositionOptions set to 0 and no cached Position object available, or cached Position object's age exceeds provided PositionOptions' maximumAge parameter." + }); + // Otherwise we have to call into native to retrieve a position. + } else { + if (options.timeout !== Infinity) { + // If the timeout value was not set to Infinity (default), then + // set up a timeout function that will fire the error callback + // if no successful position was retrieved before timeout expired. + timeoutTimer.timer = createTimeout(fail, options.timeout); + } else { + // This is here so the check in the win function doesn't mess stuff up + // may seem weird but this guarantees timeoutTimer is + // always truthy before we call into native + timeoutTimer.timer = true; + } + exec(win, fail, "Geolocation", "getLocation", [options.enableHighAccuracy, options.maximumAge]); + } + return timeoutTimer; + }, + /** + * Asynchronously watches the geolocation for changes to geolocation. When a change occurs, + * the successCallback is called with the new location. + * + * @param {Function} successCallback The function to call each time the location data is available + * @param {Function} errorCallback The function to call when there is an error getting the location data. (OPTIONAL) + * @param {PositionOptions} options The options for getting the location data such as frequency. (OPTIONAL) + * @return String The watch id that must be passed to #clearWatch to stop watching. + */ + watchPosition:function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'geolocation.getCurrentPosition', arguments); + options = parseParameters(options); + + var id = utils.createUUID(); + + // Tell device to get a position ASAP, and also retrieve a reference to the timeout timer generated in getCurrentPosition + timers[id] = geolocation.getCurrentPosition(successCallback, errorCallback, options); + + var fail = function(e) { + clearTimeout(timers[id].timer); + var err = new PositionError(e.code, e.message); + if (errorCallback) { + errorCallback(err); + } + }; + + var win = function(p) { + clearTimeout(timers[id].timer); + if (options.timeout !== Infinity) { + timers[id].timer = createTimeout(fail, options.timeout); + } + var pos = new Position( + { + latitude:p.latitude, + longitude:p.longitude, + altitude:p.altitude, + accuracy:p.accuracy, + heading:p.heading, + velocity:p.velocity, + altitudeAccuracy:p.altitudeAccuracy + }, + (p.timestamp === undefined ? new Date() : ((p.timestamp instanceof Date) ? p.timestamp : new Date(p.timestamp))) + ); + geolocation.lastPosition = pos; + successCallback(pos); + }; + + exec(win, fail, "Geolocation", "addWatch", [id, options.enableHighAccuracy]); + + return id; + }, + /** + * Clears the specified heading watch. + * + * @param {String} id The ID of the watch returned from #watchPosition + */ + clearWatch:function(id) { + if (id && timers[id] !== undefined) { + clearTimeout(timers[id].timer); + timers[id].timer = false; + exec(null, null, "Geolocation", "clearWatch", [id]); + } + } +}; + +module.exports = geolocation; + +}); + +// file: lib/common/plugin/geolocation/symbols.js +define("cordova/plugin/geolocation/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.defaults('cordova/plugin/geolocation', 'navigator.geolocation'); +modulemapper.clobbers('cordova/plugin/PositionError', 'PositionError'); +modulemapper.clobbers('cordova/plugin/Position', 'Position'); +modulemapper.clobbers('cordova/plugin/Coordinates', 'Coordinates'); + +}); + +// file: lib/common/plugin/globalization.js +define("cordova/plugin/globalization", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), + GlobalizationError = require('cordova/plugin/GlobalizationError'); + +var globalization = { + +/** +* Returns the string identifier for the client's current language. +* It returns the language identifier string to the successCB callback with a +* properties object as a parameter. If there is an error getting the language, +* then the errorCB callback is invoked. +* +* @param {Function} successCB +* @param {Function} errorCB +* +* @return Object.value {String}: The language identifier +* +* @error GlobalizationError.UNKNOWN_ERROR +* +* Example +* globalization.getPreferredLanguage(function (language) {alert('language:' + language.value + '\n');}, +* function () {}); +*/ +getPreferredLanguage:function(successCB, failureCB) { + argscheck.checkArgs('fF', 'Globalization.getPreferredLanguage', arguments); + exec(successCB, failureCB, "Globalization","getPreferredLanguage", []); +}, + +/** +* Returns the string identifier for the client's current locale setting. +* It returns the locale identifier string to the successCB callback with a +* properties object as a parameter. If there is an error getting the locale, +* then the errorCB callback is invoked. +* +* @param {Function} successCB +* @param {Function} errorCB +* +* @return Object.value {String}: The locale identifier +* +* @error GlobalizationError.UNKNOWN_ERROR +* +* Example +* globalization.getLocaleName(function (locale) {alert('locale:' + locale.value + '\n');}, +* function () {}); +*/ +getLocaleName:function(successCB, failureCB) { + argscheck.checkArgs('fF', 'Globalization.getLocaleName', arguments); + exec(successCB, failureCB, "Globalization","getLocaleName", []); +}, + + +/** +* Returns a date formatted as a string according to the client's user preferences and +* calendar using the time zone of the client. It returns the formatted date string to the +* successCB callback with a properties object as a parameter. If there is an error +* formatting the date, then the errorCB callback is invoked. +* +* The defaults are: formatLenght="short" and selector="date and time" +* +* @param {Date} date +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* formatLength {String}: 'short', 'medium', 'long', or 'full' +* selector {String}: 'date', 'time', or 'date and time' +* +* @return Object.value {String}: The localized date string +* +* @error GlobalizationError.FORMATTING_ERROR +* +* Example +* globalization.dateToString(new Date(), +* function (date) {alert('date:' + date.value + '\n');}, +* function (errorCode) {alert(errorCode);}, +* {formatLength:'short'}); +*/ +dateToString:function(date, successCB, failureCB, options) { + argscheck.checkArgs('dfFO', 'Globalization.dateToString', arguments); + var dateValue = date.valueOf(); + exec(successCB, failureCB, "Globalization", "dateToString", [{"date": dateValue, "options": options}]); +}, + + +/** +* Parses a date formatted as a string according to the client's user +* preferences and calendar using the time zone of the client and returns +* the corresponding date object. It returns the date to the successCB +* callback with a properties object as a parameter. If there is an error +* parsing the date string, then the errorCB callback is invoked. +* +* The defaults are: formatLength="short" and selector="date and time" +* +* @param {String} dateString +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* formatLength {String}: 'short', 'medium', 'long', or 'full' +* selector {String}: 'date', 'time', or 'date and time' +* +* @return Object.year {Number}: The four digit year +* Object.month {Number}: The month from (0 - 11) +* Object.day {Number}: The day from (1 - 31) +* Object.hour {Number}: The hour from (0 - 23) +* Object.minute {Number}: The minute from (0 - 59) +* Object.second {Number}: The second from (0 - 59) +* Object.millisecond {Number}: The milliseconds (from 0 - 999), +* not available on all platforms +* +* @error GlobalizationError.PARSING_ERROR +* +* Example +* globalization.stringToDate('4/11/2011', +* function (date) { alert('Month:' + date.month + '\n' + +* 'Day:' + date.day + '\n' + +* 'Year:' + date.year + '\n');}, +* function (errorCode) {alert(errorCode);}, +* {selector:'date'}); +*/ +stringToDate:function(dateString, successCB, failureCB, options) { + argscheck.checkArgs('sfFO', 'Globalization.stringToDate', arguments); + exec(successCB, failureCB, "Globalization", "stringToDate", [{"dateString": dateString, "options": options}]); +}, + + +/** +* Returns a pattern string for formatting and parsing dates according to the client's +* user preferences. It returns the pattern to the successCB callback with a +* properties object as a parameter. If there is an error obtaining the pattern, +* then the errorCB callback is invoked. +* +* The defaults are: formatLength="short" and selector="date and time" +* +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* formatLength {String}: 'short', 'medium', 'long', or 'full' +* selector {String}: 'date', 'time', or 'date and time' +* +* @return Object.pattern {String}: The date and time pattern for formatting and parsing dates. +* The patterns follow Unicode Technical Standard #35 +* http://unicode.org/reports/tr35/tr35-4.html +* Object.timezone {String}: The abbreviated name of the time zone on the client +* Object.utc_offset {Number}: The current difference in seconds between the client's +* time zone and coordinated universal time. +* Object.dst_offset {Number}: The current daylight saving time offset in seconds +* between the client's non-daylight saving's time zone +* and the client's daylight saving's time zone. +* +* @error GlobalizationError.PATTERN_ERROR +* +* Example +* globalization.getDatePattern( +* function (date) {alert('pattern:' + date.pattern + '\n');}, +* function () {}, +* {formatLength:'short'}); +*/ +getDatePattern:function(successCB, failureCB, options) { + argscheck.checkArgs('fFO', 'Globalization.getDatePattern', arguments); + exec(successCB, failureCB, "Globalization", "getDatePattern", [{"options": options}]); +}, + + +/** +* Returns an array of either the names of the months or days of the week +* according to the client's user preferences and calendar. It returns the array of names to the +* successCB callback with a properties object as a parameter. If there is an error obtaining the +* names, then the errorCB callback is invoked. +* +* The defaults are: type="wide" and item="months" +* +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* type {String}: 'narrow' or 'wide' +* item {String}: 'months', or 'days' +* +* @return Object.value {Array{String}}: The array of names starting from either +* the first month in the year or the +* first day of the week. +* @error GlobalizationError.UNKNOWN_ERROR +* +* Example +* globalization.getDateNames(function (names) { +* for(var i = 0; i < names.value.length; i++) { +* alert('Month:' + names.value[i] + '\n');}}, +* function () {}); +*/ +getDateNames:function(successCB, failureCB, options) { + argscheck.checkArgs('fFO', 'Globalization.getDateNames', arguments); + exec(successCB, failureCB, "Globalization", "getDateNames", [{"options": options}]); +}, + +/** +* Returns whether daylight savings time is in effect for a given date using the client's +* time zone and calendar. It returns whether or not daylight savings time is in effect +* to the successCB callback with a properties object as a parameter. If there is an error +* reading the date, then the errorCB callback is invoked. +* +* @param {Date} date +* @param {Function} successCB +* @param {Function} errorCB +* +* @return Object.dst {Boolean}: The value "true" indicates that daylight savings time is +* in effect for the given date and "false" indicate that it is not. +* +* @error GlobalizationError.UNKNOWN_ERROR +* +* Example +* globalization.isDayLightSavingsTime(new Date(), +* function (date) {alert('dst:' + date.dst + '\n');} +* function () {}); +*/ +isDayLightSavingsTime:function(date, successCB, failureCB) { + argscheck.checkArgs('dfF', 'Globalization.isDayLightSavingsTime', arguments); + var dateValue = date.valueOf(); + exec(successCB, failureCB, "Globalization", "isDayLightSavingsTime", [{"date": dateValue}]); +}, + +/** +* Returns the first day of the week according to the client's user preferences and calendar. +* The days of the week are numbered starting from 1 where 1 is considered to be Sunday. +* It returns the day to the successCB callback with a properties object as a parameter. +* If there is an error obtaining the pattern, then the errorCB callback is invoked. +* +* @param {Function} successCB +* @param {Function} errorCB +* +* @return Object.value {Number}: The number of the first day of the week. +* +* @error GlobalizationError.UNKNOWN_ERROR +* +* Example +* globalization.getFirstDayOfWeek(function (day) +* { alert('Day:' + day.value + '\n');}, +* function () {}); +*/ +getFirstDayOfWeek:function(successCB, failureCB) { + argscheck.checkArgs('fF', 'Globalization.getFirstDayOfWeek', arguments); + exec(successCB, failureCB, "Globalization", "getFirstDayOfWeek", []); +}, + + +/** +* Returns a number formatted as a string according to the client's user preferences. +* It returns the formatted number string to the successCB callback with a properties object as a +* parameter. If there is an error formatting the number, then the errorCB callback is invoked. +* +* The defaults are: type="decimal" +* +* @param {Number} number +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* type {String}: 'decimal', "percent", or 'currency' +* +* @return Object.value {String}: The formatted number string. +* +* @error GlobalizationError.FORMATTING_ERROR +* +* Example +* globalization.numberToString(3.25, +* function (number) {alert('number:' + number.value + '\n');}, +* function () {}, +* {type:'decimal'}); +*/ +numberToString:function(number, successCB, failureCB, options) { + argscheck.checkArgs('nfFO', 'Globalization.numberToString', arguments); + exec(successCB, failureCB, "Globalization", "numberToString", [{"number": number, "options": options}]); +}, + +/** +* Parses a number formatted as a string according to the client's user preferences and +* returns the corresponding number. It returns the number to the successCB callback with a +* properties object as a parameter. If there is an error parsing the number string, then +* the errorCB callback is invoked. +* +* The defaults are: type="decimal" +* +* @param {String} numberString +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* type {String}: 'decimal', "percent", or 'currency' +* +* @return Object.value {Number}: The parsed number. +* +* @error GlobalizationError.PARSING_ERROR +* +* Example +* globalization.stringToNumber('1234.56', +* function (number) {alert('Number:' + number.value + '\n');}, +* function () { alert('Error parsing number');}); +*/ +stringToNumber:function(numberString, successCB, failureCB, options) { + argscheck.checkArgs('sfFO', 'Globalization.stringToNumber', arguments); + exec(successCB, failureCB, "Globalization", "stringToNumber", [{"numberString": numberString, "options": options}]); +}, + +/** +* Returns a pattern string for formatting and parsing numbers according to the client's user +* preferences. It returns the pattern to the successCB callback with a properties object as a +* parameter. If there is an error obtaining the pattern, then the errorCB callback is invoked. +* +* The defaults are: type="decimal" +* +* @param {Function} successCB +* @param {Function} errorCB +* @param {Object} options {optional} +* type {String}: 'decimal', "percent", or 'currency' +* +* @return Object.pattern {String}: The number pattern for formatting and parsing numbers. +* The patterns follow Unicode Technical Standard #35. +* http://unicode.org/reports/tr35/tr35-4.html +* Object.symbol {String}: The symbol to be used when formatting and parsing +* e.g., percent or currency symbol. +* Object.fraction {Number}: The number of fractional digits to use when parsing and +* formatting numbers. +* Object.rounding {Number}: The rounding increment to use when parsing and formatting. +* Object.positive {String}: The symbol to use for positive numbers when parsing and formatting. +* Object.negative: {String}: The symbol to use for negative numbers when parsing and formatting. +* Object.decimal: {String}: The decimal symbol to use for parsing and formatting. +* Object.grouping: {String}: The grouping symbol to use for parsing and formatting. +* +* @error GlobalizationError.PATTERN_ERROR +* +* Example +* globalization.getNumberPattern( +* function (pattern) {alert('Pattern:' + pattern.pattern + '\n');}, +* function () {}); +*/ +getNumberPattern:function(successCB, failureCB, options) { + argscheck.checkArgs('fFO', 'Globalization.getNumberPattern', arguments); + exec(successCB, failureCB, "Globalization", "getNumberPattern", [{"options": options}]); +}, + +/** +* Returns a pattern string for formatting and parsing currency values according to the client's +* user preferences and ISO 4217 currency code. It returns the pattern to the successCB callback with a +* properties object as a parameter. If there is an error obtaining the pattern, then the errorCB +* callback is invoked. +* +* @param {String} currencyCode +* @param {Function} successCB +* @param {Function} errorCB +* +* @return Object.pattern {String}: The currency pattern for formatting and parsing currency values. +* The patterns follow Unicode Technical Standard #35 +* http://unicode.org/reports/tr35/tr35-4.html +* Object.code {String}: The ISO 4217 currency code for the pattern. +* Object.fraction {Number}: The number of fractional digits to use when parsing and +* formatting currency. +* Object.rounding {Number}: The rounding increment to use when parsing and formatting. +* Object.decimal: {String}: The decimal symbol to use for parsing and formatting. +* Object.grouping: {String}: The grouping symbol to use for parsing and formatting. +* +* @error GlobalizationError.FORMATTING_ERROR +* +* Example +* globalization.getCurrencyPattern('EUR', +* function (currency) {alert('Pattern:' + currency.pattern + '\n');} +* function () {}); +*/ +getCurrencyPattern:function(currencyCode, successCB, failureCB) { + argscheck.checkArgs('sfF', 'Globalization.getCurrencyPattern', arguments); + exec(successCB, failureCB, "Globalization", "getCurrencyPattern", [{"currencyCode": currencyCode}]); +} + +}; + +module.exports = globalization; + +}); + +// file: lib/common/plugin/globalization/symbols.js +define("cordova/plugin/globalization/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/globalization', 'navigator.globalization'); +modulemapper.clobbers('cordova/plugin/GlobalizationError', 'GlobalizationError'); + +}); + +// file: lib/blackberry/plugin/java/Contact.js +define("cordova/plugin/java/Contact", function(require, exports, module) { + +var ContactError = require('cordova/plugin/ContactError'), + ContactUtils = require('cordova/plugin/java/ContactUtils'), + utils = require('cordova/utils'), + ContactAddress = require('cordova/plugin/ContactAddress'), + exec = require('cordova/exec'); + +// ------------------ +// Utility functions +// ------------------ + +/** + * Retrieves a BlackBerry contact from the device by unique id. + * + * @param uid + * Unique id of the contact on the device + * @return {blackberry.pim.Contact} BlackBerry contact or null if contact with + * specified id is not found + */ +var findByUniqueId = function(uid) { + if (!uid) { + return null; + } + var bbContacts = blackberry.pim.Contact.find(new blackberry.find.FilterExpression("uid", "==", uid)); + return bbContacts[0] || null; +}; + +/** + * Creates a BlackBerry contact object from the W3C Contact object and persists + * it to device storage. + * + * @param {Contact} + * contact The contact to save + * @return a new contact object with all properties set + */ +var saveToDevice = function(contact) { + + if (!contact) { + return; + } + + var bbContact = null; + var update = false; + + // if the underlying BlackBerry contact already exists, retrieve it for + // update + if (contact.id) { + // we must attempt to retrieve the BlackBerry contact from the device + // because this may be an update operation + bbContact = findByUniqueId(contact.id); + } + + // contact not found on device, create a new one + if (!bbContact) { + bbContact = new blackberry.pim.Contact(); + } + // update the existing contact + else { + update = true; + } + + // NOTE: The user may be working with a partial Contact object, because only + // user-specified Contact fields are returned from a find operation (blame + // the W3C spec). If this is an update to an existing Contact, we don't + // want to clear an attribute from the contact database simply because the + // Contact object that the user passed in contains a null value for that + // attribute. So we only copy the non-null Contact attributes to the + // BlackBerry contact object before saving. + // + // This means that a user must explicitly set a Contact attribute to a + // non-null value in order to update it in the contact database. + // + // name + if (contact.name !== null) { + if (contact.name.givenName) { + bbContact.firstName = contact.name.givenName; + } + if (contact.name.familyName) { + bbContact.lastName = contact.name.familyName; + } + if (contact.name.honorificPrefix) { + bbContact.title = contact.name.honorificPrefix; + } + } + + // display name + if (contact.displayName !== null) { + bbContact.user1 = contact.displayName; + } + + // note + if (contact.note !== null) { + bbContact.note = contact.note; + } + + // birthday + // + // user may pass in Date object or a string representation of a date + // if it is a string, we don't know the date format, so try to create a + // new Date with what we're given + // + // NOTE: BlackBerry's Date.parse() does not work well, so use new Date() + // + if (contact.birthday !== null) { + if (utils.isDate(contact.birthday)) { + bbContact.birthday = contact.birthday; + } else { + var bday = contact.birthday.toString(); + bbContact.birthday = (bday.length > 0) ? new Date(bday) : ""; + } + } + + // BlackBerry supports three email addresses + if (contact.emails && utils.isArray(contact.emails)) { + + // if this is an update, re-initialize email addresses + if (update) { + bbContact.email1 = ""; + bbContact.email2 = ""; + bbContact.email3 = ""; + } + + // copy the first three email addresses found + var email = null; + for ( var i = 0; i < contact.emails.length; i += 1) { + email = contact.emails[i]; + if (!email || !email.value) { + continue; + } + if (bbContact.email1 === "") { + bbContact.email1 = email.value; + } else if (bbContact.email2 === "") { + bbContact.email2 = email.value; + } else if (bbContact.email3 === "") { + bbContact.email3 = email.value; + } + } + } + + // BlackBerry supports a finite number of phone numbers + // copy into appropriate fields based on type + if (contact.phoneNumbers && utils.isArray(contact.phoneNumbers)) { + + // if this is an update, re-initialize phone numbers + if (update) { + bbContact.homePhone = ""; + bbContact.homePhone2 = ""; + bbContact.workPhone = ""; + bbContact.workPhone2 = ""; + bbContact.mobilePhone = ""; + bbContact.faxPhone = ""; + bbContact.pagerPhone = ""; + bbContact.otherPhone = ""; + } + + var type = null; + var number = null; + for ( var j = 0; j < contact.phoneNumbers.length; j += 1) { + if (!contact.phoneNumbers[j] || !contact.phoneNumbers[j].value) { + continue; + } + type = contact.phoneNumbers[j].type; + number = contact.phoneNumbers[j].value; + if (type === 'home') { + if (bbContact.homePhone === "") { + bbContact.homePhone = number; + } else if (bbContact.homePhone2 === "") { + bbContact.homePhone2 = number; + } + } else if (type === 'work') { + if (bbContact.workPhone === "") { + bbContact.workPhone = number; + } else if (bbContact.workPhone2 === "") { + bbContact.workPhone2 = number; + } + } else if (type === 'mobile' && bbContact.mobilePhone === "") { + bbContact.mobilePhone = number; + } else if (type === 'fax' && bbContact.faxPhone === "") { + bbContact.faxPhone = number; + } else if (type === 'pager' && bbContact.pagerPhone === "") { + bbContact.pagerPhone = number; + } else if (bbContact.otherPhone === "") { + bbContact.otherPhone = number; + } + } + } + + // BlackBerry supports two addresses: home and work + // copy the first two addresses found from Contact + if (contact.addresses && utils.isArray(contact.addresses)) { + + // if this is an update, re-initialize addresses + if (update) { + bbContact.homeAddress = null; + bbContact.workAddress = null; + } + + var address = null; + var bbHomeAddress = null; + var bbWorkAddress = null; + for ( var k = 0; k < contact.addresses.length; k += 1) { + address = contact.addresses[k]; + if (!address || address.id === undefined || address.pref === undefined || address.type === undefined || address.formatted === undefined) { + continue; + } + + if (bbHomeAddress === null && (!address.type || address.type === "home")) { + bbHomeAddress = createBlackBerryAddress(address); + bbContact.homeAddress = bbHomeAddress; + } else if (bbWorkAddress === null && (!address.type || address.type === "work")) { + bbWorkAddress = createBlackBerryAddress(address); + bbContact.workAddress = bbWorkAddress; + } + } + } + + // copy first url found to BlackBerry 'webpage' field + if (contact.urls && utils.isArray(contact.urls)) { + + // if this is an update, re-initialize web page + if (update) { + bbContact.webpage = ""; + } + + var url = null; + for ( var m = 0; m < contact.urls.length; m += 1) { + url = contact.urls[m]; + if (!url || !url.value) { + continue; + } + if (bbContact.webpage === "") { + bbContact.webpage = url.value; + break; + } + } + } + + // copy fields from first organization to the + // BlackBerry 'company' and 'jobTitle' fields + if (contact.organizations && utils.isArray(contact.organizations)) { + + // if this is an update, re-initialize org attributes + if (update) { + bbContact.company = ""; + } + + var org = null; + for ( var n = 0; n < contact.organizations.length; n += 1) { + org = contact.organizations[n]; + if (!org) { + continue; + } + if (bbContact.company === "") { + bbContact.company = org.name || ""; + bbContact.jobTitle = org.title || ""; + break; + } + } + } + + // categories + if (contact.categories && utils.isArray(contact.categories)) { + bbContact.categories = []; + var category = null; + for ( var o = 0; o < contact.categories.length; o += 1) { + category = contact.categories[o]; + if (typeof category == "string") { + bbContact.categories.push(category); + } + } + } + + // save to device + bbContact.save(); + + // invoke native side to save photo + // fail gracefully if photo URL is no good, but log the error + if (contact.photos && utils.isArray(contact.photos)) { + var photo = null; + for ( var p = 0; p < contact.photos.length; p += 1) { + photo = contact.photos[p]; + if (!photo || !photo.value) { + continue; + } + exec( + // success + function() { + }, + // fail + function(e) { + console.log('Contact.setPicture failed:' + e); + }, "Contacts", "setPicture", [ bbContact.uid, photo.type, + photo.value ]); + break; + } + } + + // Use the fully populated BlackBerry contact object to create a + // corresponding W3C contact object. + return ContactUtils.createContact(bbContact, [ "*" ]); +}; + +/** + * Creates a BlackBerry Address object from a W3C ContactAddress. + * + * @return {blackberry.pim.Address} a BlackBerry address object + */ +var createBlackBerryAddress = function(address) { + var bbAddress = new blackberry.pim.Address(); + + if (!address) { + return bbAddress; + } + + bbAddress.address1 = address.streetAddress || ""; + bbAddress.city = address.locality || ""; + bbAddress.stateProvince = address.region || ""; + bbAddress.zipPostal = address.postalCode || ""; + bbAddress.country = address.country || ""; + + return bbAddress; +}; + +module.exports = { + /** + * Persists contact to device storage. + */ + save : function(success, fail) { + try { + // save the contact and store it's unique id + var fullContact = saveToDevice(this); + this.id = fullContact.id; + + // This contact object may only have a subset of properties + // if the save was an update of an existing contact. This is + // because the existing contact was likely retrieved using a + // subset of properties, so only those properties were set in the + // object. For this reason, invoke success with the contact object + // returned by saveToDevice since it is fully populated. + if (typeof success === 'function') { + success(fullContact); + } + } catch (e) { + console.log('Error saving contact: ' + e); + if (typeof fail === 'function') { + fail(new ContactError(ContactError.UNKNOWN_ERROR)); + } + } + }, + + /** + * Removes contact from device storage. + * + * @param success + * success callback + * @param fail + * error callback + */ + remove : function(success, fail) { + try { + // retrieve contact from device by id + var bbContact = null; + if (this.id) { + bbContact = findByUniqueId(this.id); + } + + // if contact was found, remove it + if (bbContact) { + console.log('removing contact: ' + bbContact.uid); + bbContact.remove(); + if (typeof success === 'function') { + success(this); + } + } + // attempting to remove a contact that hasn't been saved + else if (typeof fail === 'function') { + fail(new ContactError(ContactError.UNKNOWN_ERROR)); + } + } catch (e) { + console.log('Error removing contact ' + this.id + ": " + e); + if (typeof fail === 'function') { + fail(new ContactError(ContactError.UNKNOWN_ERROR)); + } + } + } +}; + +}); + +// file: lib/blackberry/plugin/java/ContactUtils.js +define("cordova/plugin/java/ContactUtils", function(require, exports, module) { + +var ContactAddress = require('cordova/plugin/ContactAddress'), + ContactName = require('cordova/plugin/ContactName'), + ContactField = require('cordova/plugin/ContactField'), + ContactOrganization = require('cordova/plugin/ContactOrganization'), + utils = require('cordova/utils'), + Contact = require('cordova/plugin/Contact'); + +/** + * Mappings for each Contact field that may be used in a find operation. Maps + * W3C Contact fields to one or more fields in a BlackBerry contact object. + * + * Example: user searches with a filter on the Contact 'name' field: + * + * Contacts.find(['name'], onSuccess, onFail, {filter:'Bob'}); + * + * The 'name' field does not exist in a BlackBerry contact. Instead, a filter + * expression will be built to search the BlackBerry contacts using the + * BlackBerry 'title', 'firstName' and 'lastName' fields. + */ +var fieldMappings = { + "id" : "uid", + "displayName" : "user1", + "name" : [ "title", "firstName", "lastName" ], + "name.formatted" : [ "title", "firstName", "lastName" ], + "name.givenName" : "firstName", + "name.familyName" : "lastName", + "name.honorificPrefix" : "title", + "phoneNumbers" : [ "faxPhone", "homePhone", "homePhone2", "mobilePhone", + "pagerPhone", "otherPhone", "workPhone", "workPhone2" ], + "phoneNumbers.value" : [ "faxPhone", "homePhone", "homePhone2", + "mobilePhone", "pagerPhone", "otherPhone", "workPhone", + "workPhone2" ], + "emails" : [ "email1", "email2", "email3" ], + "addresses" : [ "homeAddress.address1", "homeAddress.address2", + "homeAddress.city", "homeAddress.stateProvince", + "homeAddress.zipPostal", "homeAddress.country", + "workAddress.address1", "workAddress.address2", "workAddress.city", + "workAddress.stateProvince", "workAddress.zipPostal", + "workAddress.country" ], + "addresses.formatted" : [ "homeAddress.address1", "homeAddress.address2", + "homeAddress.city", "homeAddress.stateProvince", + "homeAddress.zipPostal", "homeAddress.country", + "workAddress.address1", "workAddress.address2", "workAddress.city", + "workAddress.stateProvince", "workAddress.zipPostal", + "workAddress.country" ], + "addresses.streetAddress" : [ "homeAddress.address1", + "homeAddress.address2", "workAddress.address1", + "workAddress.address2" ], + "addresses.locality" : [ "homeAddress.city", "workAddress.city" ], + "addresses.region" : [ "homeAddress.stateProvince", + "workAddress.stateProvince" ], + "addresses.country" : [ "homeAddress.country", "workAddress.country" ], + "organizations" : [ "company", "jobTitle" ], + "organizations.name" : "company", + "organizations.title" : "jobTitle", + "birthday" : "birthday", + "note" : "note", + "categories" : "categories", + "urls" : "webpage", + "urls.value" : "webpage" +}; + +/* + * Build an array of all of the valid W3C Contact fields. This is used to + * substitute all the fields when ["*"] is specified. + */ +var allFields = []; +for ( var key in fieldMappings) { + if (fieldMappings.hasOwnProperty(key)) { + allFields.push(key); + } +} + +/** + * Create a W3C ContactAddress object from a BlackBerry Address object. + * + * @param {String} + * type the type of address (e.g. work, home) + * @param {blackberry.pim.Address} + * bbAddress a BlackBerry Address object + * @return {ContactAddress} a contact address object or null if the specified + * address is null + */ +var createContactAddress = function(type, bbAddress) { + + if (!bbAddress) { + return null; + } + + var address1 = bbAddress.address1 || ""; + var address2 = bbAddress.address2 || ""; + var streetAddress = address1 + ", " + address2; + var locality = bbAddress.city || ""; + var region = bbAddress.stateProvince || ""; + var postalCode = bbAddress.zipPostal || ""; + var country = bbAddress.country || ""; + var formatted = streetAddress + ", " + locality + ", " + region + ", " + postalCode + ", " + country; + + return new ContactAddress(null, type, formatted, streetAddress, locality, + region, postalCode, country); +}; + +module.exports = { + /** + * Builds a BlackBerry filter expression for contact search using the + * contact fields and search filter provided. + * + * @param {String[]} + * fields Array of Contact fields to search + * @param {String} + * filter Filter, or search string + * @return filter expression or null if fields is empty or filter is null or + * empty + */ + buildFilterExpression : function(fields, filter) { + + // ensure filter exists + if (!filter || filter === "") { + return null; + } + + if (fields.length == 1 && fields[0] === "*") { + // Cordova enhancement to allow fields value of ["*"] to indicate + // all supported fields. + fields = allFields; + } + + // BlackBerry API uses specific operators to build filter expressions + // for + // querying Contact lists. The operators are + // ["!=","==","<",">","<=",">="]. + // Use of regex is also an option, and the only one we can use to + // simulate + // an SQL '%LIKE%' clause. + // + // Note: The BlackBerry regex implementation doesn't seem to support + // conventional regex switches that would enable a case insensitive + // search. + // It does not honor the (?i) switch (which causes Contact.find() to + // fail). + // We need case INsensitivity to match the W3C Contacts API spec. + // So the guys at RIM proposed this method: + // + // original filter = "norm" + // case insensitive filter = "[nN][oO][rR][mM]" + // + var ciFilter = ""; + for ( var i = 0; i < filter.length; i++) { + ciFilter = ciFilter + "[" + filter[i].toLowerCase() + filter[i].toUpperCase() + "]"; + } + + // match anything that contains our filter string + filter = ".*" + ciFilter + ".*"; + + // build a filter expression using all Contact fields provided + var filterExpression = null; + if (fields && utils.isArray(fields)) { + var fe = null; + for (var f = 0; f < fields.length; f++) { + if (!fields[f]) { + continue; + } + + // retrieve the BlackBerry contact fields that map to the one + // specified + var bbFields = fieldMappings[fields[f]]; + + // BlackBerry doesn't support the field specified + if (!bbFields) { + continue; + } + + if (!utils.isArray(bbFields)) { + bbFields = [bbFields]; + } + + // construct the filter expression using the BlackBerry fields + for (var j = 0; j < bbFields.length; j++) { + fe = new blackberry.find.FilterExpression(bbFields[j], + "REGEX", filter); + if (filterExpression === null) { + filterExpression = fe; + } else { + // combine the filters + filterExpression = new blackberry.find.FilterExpression( + filterExpression, "OR", fe); + } + } + } + } + + return filterExpression; + }, + + /** + * Creates a Contact object from a BlackBerry Contact object, copying only + * the fields specified. + * + * This is intended as a privately used function but it is made globally + * available so that a Contact.save can convert a BlackBerry contact object + * into its W3C equivalent. + * + * @param {blackberry.pim.Contact} + * bbContact BlackBerry Contact object + * @param {String[]} + * fields array of contact fields that should be copied + * @return {Contact} a contact object containing the specified fields or + * null if the specified contact is null + */ + createContact : function(bbContact, fields) { + + if (!bbContact) { + return null; + } + + // construct a new contact object + // always copy the contact id and displayName fields + var contact = new Contact(bbContact.uid, bbContact.user1); + + // nothing to do + if (!fields || !(utils.isArray(fields)) || fields.length === 0) { + return contact; + } else if (fields.length == 1 && fields[0] === "*") { + // Cordova enhancement to allow fields value of ["*"] to indicate + // all supported fields. + fields = allFields; + } + + // add the fields specified + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + + if (!field) { + continue; + } + + // name + if (field.indexOf('name') === 0) { + var formattedName = bbContact.title + ' ' + bbContact.firstName + ' ' + bbContact.lastName; + contact.name = new ContactName(formattedName, + bbContact.lastName, bbContact.firstName, null, + bbContact.title, null); + } + // phone numbers + else if (field.indexOf('phoneNumbers') === 0) { + var phoneNumbers = []; + if (bbContact.homePhone) { + phoneNumbers.push(new ContactField('home', + bbContact.homePhone)); + } + if (bbContact.homePhone2) { + phoneNumbers.push(new ContactField('home', + bbContact.homePhone2)); + } + if (bbContact.workPhone) { + phoneNumbers.push(new ContactField('work', + bbContact.workPhone)); + } + if (bbContact.workPhone2) { + phoneNumbers.push(new ContactField('work', + bbContact.workPhone2)); + } + if (bbContact.mobilePhone) { + phoneNumbers.push(new ContactField('mobile', + bbContact.mobilePhone)); + } + if (bbContact.faxPhone) { + phoneNumbers.push(new ContactField('fax', + bbContact.faxPhone)); + } + if (bbContact.pagerPhone) { + phoneNumbers.push(new ContactField('pager', + bbContact.pagerPhone)); + } + if (bbContact.otherPhone) { + phoneNumbers.push(new ContactField('other', + bbContact.otherPhone)); + } + contact.phoneNumbers = phoneNumbers.length > 0 ? phoneNumbers + : null; + } + // emails + else if (field.indexOf('emails') === 0) { + var emails = []; + if (bbContact.email1) { + emails.push(new ContactField(null, bbContact.email1, null)); + } + if (bbContact.email2) { + emails.push(new ContactField(null, bbContact.email2, null)); + } + if (bbContact.email3) { + emails.push(new ContactField(null, bbContact.email3, null)); + } + contact.emails = emails.length > 0 ? emails : null; + } + // addresses + else if (field.indexOf('addresses') === 0) { + var addresses = []; + if (bbContact.homeAddress) { + addresses.push(createContactAddress("home", + bbContact.homeAddress)); + } + if (bbContact.workAddress) { + addresses.push(createContactAddress("work", + bbContact.workAddress)); + } + contact.addresses = addresses.length > 0 ? addresses : null; + } + // birthday + else if (field.indexOf('birthday') === 0) { + if (bbContact.birthday) { + contact.birthday = bbContact.birthday; + } + } + // note + else if (field.indexOf('note') === 0) { + if (bbContact.note) { + contact.note = bbContact.note; + } + } + // organizations + else if (field.indexOf('organizations') === 0) { + var organizations = []; + if (bbContact.company || bbContact.jobTitle) { + organizations.push(new ContactOrganization(null, null, + bbContact.company, null, bbContact.jobTitle)); + } + contact.organizations = organizations.length > 0 ? organizations + : null; + } + // categories + else if (field.indexOf('categories') === 0) { + if (bbContact.categories && bbContact.categories.length > 0) { + contact.categories = bbContact.categories; + } else { + contact.categories = null; + } + } + // urls + else if (field.indexOf('urls') === 0) { + var urls = []; + if (bbContact.webpage) { + urls.push(new ContactField(null, bbContact.webpage)); + } + contact.urls = urls.length > 0 ? urls : null; + } + // photos + else if (field.indexOf('photos') === 0) { + var photos = []; + // The BlackBerry Contact object will have a picture attribute + // with Base64 encoded image + if (bbContact.picture) { + photos.push(new ContactField('base64', bbContact.picture)); + } + contact.photos = photos.length > 0 ? photos : null; + } + } + + return contact; + } +}; + +}); + +// file: lib/blackberry/plugin/java/DirectoryEntry.js +define("cordova/plugin/java/DirectoryEntry", function(require, exports, module) { + +var DirectoryEntry = require('cordova/plugin/DirectoryEntry'), + FileEntry = require('cordova/plugin/FileEntry'), + FileError = require('cordova/plugin/FileError'), + exec = require('cordova/exec'); + +module.exports = { + /** + * Creates or looks up a directory; override for BlackBerry. + * + * @param path + * {DOMString} either a relative or absolute path from this + * directory in which to look up or create a directory + * @param options + * {Flags} options to create or exclusively create the directory + * @param successCallback + * {Function} called with the new DirectoryEntry + * @param errorCallback + * {Function} called with a FileError + */ + getDirectory : function(path, options, successCallback, errorCallback) { + // create directory if it doesn't exist + var create = (options && options.create === true) ? true : false, + // if true, causes failure if create is true and path already exists + exclusive = (options && options.exclusive === true) ? true : false, + // directory exists + exists, + // create a new DirectoryEntry object and invoke success callback + createEntry = function() { + var path_parts = path.split('/'), + name = path_parts[path_parts.length - 1], + dirEntry = new DirectoryEntry(name, path); + + // invoke success callback + if (typeof successCallback === 'function') { + successCallback(dirEntry); + } + }; + + var fail = function(error) { + if (typeof errorCallback === 'function') { + errorCallback(new FileError(error)); + } + }; + + // determine if path is relative or absolute + if (!path) { + fail(FileError.ENCODING_ERR); + return; + } else if (path.indexOf(this.fullPath) !== 0) { + // path does not begin with the fullPath of this directory + // therefore, it is relative + path = this.fullPath + '/' + path; + } + + // determine if directory exists + try { + // will return true if path exists AND is a directory + exists = blackberry.io.dir.exists(path); + } catch (e) { + // invalid path + fail(FileError.ENCODING_ERR); + return; + } + + // path is a directory + if (exists) { + if (create && exclusive) { + // can't guarantee exclusivity + fail(FileError.PATH_EXISTS_ERR); + } else { + // create entry for existing directory + createEntry(); + } + } + // will return true if path exists AND is a file + else if (blackberry.io.file.exists(path)) { + // the path is a file + fail(FileError.TYPE_MISMATCH_ERR); + } + // path does not exist, create it + else if (create) { + try { + // directory path must have trailing slash + var dirPath = path; + if (dirPath.substr(-1) !== '/') { + dirPath += '/'; + } + blackberry.io.dir.createNewDir(dirPath); + createEntry(); + } catch (eone) { + // unable to create directory + fail(FileError.NOT_FOUND_ERR); + } + } + // path does not exist, don't create + else { + // directory doesn't exist + fail(FileError.NOT_FOUND_ERR); + } + }, + /** + * Create or look up a file. + * + * @param path {DOMString} + * either a relative or absolute path from this directory in + * which to look up or create a file + * @param options {Flags} + * options to create or exclusively create the file + * @param successCallback {Function} + * called with the new FileEntry object + * @param errorCallback {Function} + * called with a FileError object if error occurs + */ + getFile:function(path, options, successCallback, errorCallback) { + // create file if it doesn't exist + var create = (options && options.create === true) ? true : false, + // if true, causes failure if create is true and path already exists + exclusive = (options && options.exclusive === true) ? true : false, + // file exists + exists, + // create a new FileEntry object and invoke success callback + createEntry = function() { + var path_parts = path.split('/'), + name = path_parts[path_parts.length - 1], + fileEntry = new FileEntry(name, path); + + // invoke success callback + if (typeof successCallback === 'function') { + successCallback(fileEntry); + } + }; + + var fail = function(error) { + if (typeof errorCallback === 'function') { + errorCallback(new FileError(error)); + } + }; + + // determine if path is relative or absolute + if (!path) { + fail(FileError.ENCODING_ERR); + return; + } + else if (path.indexOf(this.fullPath) !== 0) { + // path does not begin with the fullPath of this directory + // therefore, it is relative + path = this.fullPath + '/' + path; + } + + // determine if file exists + try { + // will return true if path exists AND is a file + exists = blackberry.io.file.exists(path); + } + catch (e) { + // invalid path + fail(FileError.ENCODING_ERR); + return; + } + + // path is a file + if (exists) { + if (create && exclusive) { + // can't guarantee exclusivity + fail(FileError.PATH_EXISTS_ERR); + } + else { + // create entry for existing file + createEntry(); + } + } + // will return true if path exists AND is a directory + else if (blackberry.io.dir.exists(path)) { + // the path is a directory + fail(FileError.TYPE_MISMATCH_ERR); + } + // path does not exist, create it + else if (create) { + // create empty file + exec( + function(result) { + // file created + createEntry(); + }, + fail, "File", "write", [ path, "", 0 ]); + } + // path does not exist, don't create + else { + // file doesn't exist + fail(FileError.NOT_FOUND_ERR); + } + }, + + /** + * Delete a directory and all of it's contents. + * + * @param successCallback {Function} called with no parameters + * @param errorCallback {Function} called with a FileError + */ + removeRecursively : function(successCallback, errorCallback) { + // we're removing THIS directory + var path = this.fullPath; + + var fail = function(error) { + if (typeof errorCallback === 'function') { + errorCallback(new FileError(error)); + } + }; + + // attempt to delete directory + if (blackberry.io.dir.exists(path)) { + // it is an error to attempt to remove the file system root + if (exec(null, null, "File", "isFileSystemRoot", [ path ]) === true) { + fail(FileError.NO_MODIFICATION_ALLOWED_ERR); + } + else { + try { + // delete the directory, setting recursive flag to true + blackberry.io.dir.deleteDirectory(path, true); + if (typeof successCallback === "function") { + successCallback(); + } + } catch (e) { + // permissions don't allow deletion + console.log(e); + fail(FileError.NO_MODIFICATION_ALLOWED_ERR); + } + } + } + // it's a file, not a directory + else if (blackberry.io.file.exists(path)) { + fail(FileError.TYPE_MISMATCH_ERR); + } + // not found + else { + fail(FileError.NOT_FOUND_ERR); + } + } +}; + +}); + +// file: lib/blackberry/plugin/java/Entry.js +define("cordova/plugin/java/Entry", function(require, exports, module) { + +var FileError = require('cordova/plugin/FileError'), + LocalFileSystem = require('cordova/plugin/LocalFileSystem'), + resolveLocalFileSystemURI = require('cordova/plugin/resolveLocalFileSystemURI'), + requestFileSystem = require('cordova/plugin/requestFileSystem'), + exec = require('cordova/exec'); + +module.exports = { + remove : function(successCallback, errorCallback) { + var path = this.fullPath, + // directory contents + contents = []; + + var fail = function(error) { + if (typeof errorCallback === 'function') { + errorCallback(new FileError(error)); + } + }; + + // file + if (blackberry.io.file.exists(path)) { + try { + blackberry.io.file.deleteFile(path); + if (typeof successCallback === "function") { + successCallback(); + } + } catch (e) { + // permissions don't allow + fail(FileError.INVALID_MODIFICATION_ERR); + } + } + // directory + else if (blackberry.io.dir.exists(path)) { + // it is an error to attempt to remove the file system root + if (exec(null, null, "File", "isFileSystemRoot", [ path ]) === true) { + fail(FileError.NO_MODIFICATION_ALLOWED_ERR); + } else { + // check to see if directory is empty + contents = blackberry.io.dir.listFiles(path); + if (contents.length !== 0) { + fail(FileError.INVALID_MODIFICATION_ERR); + } else { + try { + // delete + blackberry.io.dir.deleteDirectory(path, false); + if (typeof successCallback === "function") { + successCallback(); + } + } catch (eone) { + // permissions don't allow + fail(FileError.NO_MODIFICATION_ALLOWED_ERR); + } + } + } + } + // not found + else { + fail(FileError.NOT_FOUND_ERR); + } + }, + getParent : function(successCallback, errorCallback) { + var that = this; + + try { + // On BlackBerry, the TEMPORARY file system is actually a temporary + // directory that is created on a per-application basis. This is + // to help ensure that applications do not share the same temporary + // space. So we check to see if this is the TEMPORARY file system + // (directory). If it is, we must return this Entry, rather than + // the Entry for its parent. + requestFileSystem(LocalFileSystem.TEMPORARY, 0, + function(fileSystem) { + if (fileSystem.root.fullPath === that.fullPath) { + if (typeof successCallback === 'function') { + successCallback(fileSystem.root); + } + } else { + resolveLocalFileSystemURI(blackberry.io.dir + .getParentDirectory(that.fullPath), + successCallback, errorCallback); + } + }, errorCallback); + } catch (e) { + if (typeof errorCallback === 'function') { + errorCallback(new FileError(FileError.NOT_FOUND_ERR)); + } + } + } +}; + +}); + +// file: lib/blackberry/plugin/java/MediaError.js +define("cordova/plugin/java/MediaError", function(require, exports, module) { + + +// The MediaError object exists on BB OS 6+ which prevents the Cordova version +// from being defined. This object is used to merge in differences between the BB +// MediaError object and the Cordova version. +module.exports = { + MEDIA_ERR_NONE_ACTIVE : 0, + MEDIA_ERR_NONE_SUPPORTED : 4 +}; + +}); + +// file: lib/blackberry/plugin/java/app.js +define("cordova/plugin/java/app", function(require, exports, module) { + +var exec = require('cordova/exec'), + platform = require('cordova/platform'), + manager = require('cordova/plugin/' + platform.runtime() + '/manager'); + +module.exports = { + /** + * Clear the resource cache. + */ + clearCache:function() { + if (typeof blackberry.widgetcache === "undefined" || blackberry.widgetcache === null) { + console.log("blackberry.widgetcache permission not found. Cache clear request denied."); + return; + } + blackberry.widgetcache.clearAll(); + }, + + /** + * Clear web history in this web view. + * Instead of BACK button loading the previous web page, it will exit the app. + */ + clearHistory:function() { + exec(null, null, "App", "clearHistory", []); + }, + + /** + * Go to previous page displayed. + * This is the same as pressing the backbutton on Android device. + */ + backHistory:function() { + // window.history.back() behaves oddly on BlackBerry, so use + // native implementation. + exec(null, null, "App", "backHistory", []); + }, + + /** + * Exit and terminate the application. + */ + exitApp:function() { + // Call onunload if it is defined since BlackBerry does not invoke + // on application exit. + if (typeof window.onunload === "function") { + window.onunload(); + } + + // allow Cordova JavaScript Extension opportunity to cleanup + manager.destroy(); + + // exit the app + blackberry.app.exit(); + } +}; + +}); + +// file: lib/blackberry/plugin/java/app/bbsymbols.js +define("cordova/plugin/java/app/bbsymbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/java/app', 'navigator.app'); + +}); + +// file: lib/blackberry/plugin/java/contacts.js +define("cordova/plugin/java/contacts", function(require, exports, module) { + +var ContactError = require('cordova/plugin/ContactError'), + utils = require('cordova/utils'), + ContactUtils = require('cordova/plugin/java/ContactUtils'); + +module.exports = { + /** + * Returns an array of Contacts matching the search criteria. + * + * @return array of Contacts matching search criteria + */ + find : function(fields, success, fail, options) { + // Success callback is required. Throw exception if not specified. + if (typeof success !== 'function') { + throw new TypeError( + "You must specify a success callback for the find command."); + } + + // Search qualifier is required and cannot be empty. + if (!fields || !(utils.isArray(fields)) || fields.length === 0) { + if (typeof fail == 'function') { + fail(new ContactError(ContactError.INVALID_ARGUMENT_ERROR)); + } + return; + } + + // default is to return a single contact match + var numContacts = 1; + + // search options + var filter = null; + if (options) { + // return multiple objects? + if (options.multiple === true) { + // -1 on BlackBerry will return all contact matches. + numContacts = -1; + } + filter = options.filter; + } + + // build the filter expression to use in find operation + var filterExpression = ContactUtils.buildFilterExpression(fields, filter); + + // find matching contacts + // Note: the filter expression can be null here, in which case, the find + // won't filter + var bbContacts = blackberry.pim.Contact.find(filterExpression, null, numContacts); + + // convert to Contact from blackberry.pim.Contact + var contacts = []; + for (var i = 0; i < bbContacts.length; i++) { + if (bbContacts[i]) { + // W3C Contacts API specification states that only the fields + // in the search filter should be returned, so we create + // a new Contact object, copying only the fields specified + contacts.push(ContactUtils.createContact(bbContacts[i], fields)); + } + } + + // return results + success(contacts); + } + +}; + +}); + +// file: lib/blackberry/plugin/java/contacts/bbsymbols.js +define("cordova/plugin/java/contacts/bbsymbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.merges('cordova/plugin/java/contacts', 'navigator.contacts'); +modulemapper.merges('cordova/plugin/java/Contact', 'Contact'); + +}); + +// file: lib/blackberry/plugin/java/file/bbsymbols.js +define("cordova/plugin/java/file/bbsymbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/File', 'File'); +modulemapper.merges('cordova/plugin/java/DirectoryEntry', 'DirectoryEntry'); +modulemapper.merges('cordova/plugin/java/Entry', 'Entry'); + + +}); + +// file: lib/blackberry/plugin/java/manager.js +define("cordova/plugin/java/manager", function(require, exports, module) { + +var cordova = require('cordova'); + +function _exec(win, fail, clazz, action, args) { + var callbackId = clazz + cordova.callbackId++, + origResult, + evalResult, + execResult; + + try { + if (win || fail) { + cordova.callbacks[callbackId] = {success: win, fail: fail}; + } + + // Note: Device returns string, but for some reason emulator returns object - so convert to string. + origResult = "" + org.apache.cordova.JavaPluginManager.exec(clazz, action, callbackId, JSON.stringify(args), true); + + // If a result was returned + if (origResult.length > 0) { + evalResult = JSON.parse(origResult); + + // If status is OK, then return evalResult value back to caller + if (evalResult.status === cordova.callbackStatus.OK) { + + // If there is a success callback, then call it now with returned evalResult value + if (win) { + // Clear callback if not expecting any more results + if (!evalResult.keepCallback) { + delete cordova.callbacks[callbackId]; + } + } + } else if (evalResult.status === cordova.callbackStatus.NO_RESULT) { + + // Clear callback if not expecting any more results + if (!evalResult.keepCallback) { + delete cordova.callbacks[callbackId]; + } + } else { + // If there is a fail callback, then call it now with returned evalResult value + if (fail) { + + // Clear callback if not expecting any more results + if (!evalResult.keepCallback) { + delete cordova.callbacks[callbackId]; + } + } + } + execResult = evalResult; + } else { + // Asynchronous calls return an empty string. Return a NO_RESULT + // status for those executions. + execResult = {"status" : cordova.callbackStatus.NO_RESULT, + "message" : ""}; + } + } catch (e) { + console.log("BlackBerryPluginManager Error: " + e); + execResult = {"status" : cordova.callbackStatus.ERROR, + "message" : e.message}; + } + + return execResult; +} + +module.exports = { + exec: function (win, fail, clazz, action, args) { + return _exec(win, fail, clazz, action, args); + }, + resume: org.apache.cordova.JavaPluginManager.resume, + pause: org.apache.cordova.JavaPluginManager.pause, + destroy: org.apache.cordova.JavaPluginManager.destroy +}; + +}); + +// file: lib/blackberry/plugin/java/media/bbsymbols.js +define("cordova/plugin/java/media/bbsymbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.defaults('cordova/plugin/Media', 'Media'); +modulemapper.defaults('cordova/plugin/MediaError', 'MediaError'); +// Exists natively on BB OS 6+, merge in Cordova specifics +modulemapper.merges('cordova/plugin/java/MediaError', 'MediaError'); + +}); + +// file: lib/blackberry/plugin/java/notification.js +define("cordova/plugin/java/notification", function(require, exports, module) { + +var exec = require('cordova/exec'); + +/** + * Provides BlackBerry enhanced notification API. + */ +module.exports = { + activityStart : function(title, message) { + // If title and message not specified then mimic Android behavior of + // using default strings. + if (typeof title === "undefined" && typeof message == "undefined") { + title = "Busy"; + message = 'Please wait...'; + } + + exec(null, null, 'Notification', 'activityStart', [ title, message ]); + }, + + /** + * Close an activity dialog + */ + activityStop : function() { + exec(null, null, 'Notification', 'activityStop', []); + }, + + /** + * Display a progress dialog with progress bar that goes from 0 to 100. + * + * @param {String} + * title Title of the progress dialog. + * @param {String} + * message Message to display in the dialog. + */ + progressStart : function(title, message) { + exec(null, null, 'Notification', 'progressStart', [ title, message ]); + }, + + /** + * Close the progress dialog. + */ + progressStop : function() { + exec(null, null, 'Notification', 'progressStop', []); + }, + + /** + * Set the progress dialog value. + * + * @param {Number} + * value 0-100 + */ + progressValue : function(value) { + exec(null, null, 'Notification', 'progressValue', [ value ]); + } +}; + +}); + +// file: lib/blackberry/plugin/java/notification/bbsymbols.js +define("cordova/plugin/java/notification/bbsymbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.merges('cordova/plugin/java/notification', 'navigator.notification'); + +}); + +// file: lib/blackberry/plugin/java/platform.js +define("cordova/plugin/java/platform", function(require, exports, module) { + +module.exports = { + id: "blackberry", + initialize:function() { + var cordova = require('cordova'), + exec = require('cordova/exec'), + channel = require('cordova/channel'), + platform = require('cordova/platform'), + manager = require('cordova/plugin/' + platform.runtime() + '/manager'), + app = require('cordova/plugin/java/app'); + + // BB OS 5 does not define window.console. + if (typeof window.console === 'undefined') { + window.console = {}; + } + + // Override console.log with native logging ability. + // BB OS 7 devices define console.log for use with web inspector + // debugging. If console.log is already defined, invoke it in addition + // to native logging. + var origLog = window.console.log; + window.console.log = function(msg) { + if (typeof origLog === 'function') { + origLog.call(window.console, msg); + } + org.apache.cordova.Logger.log(''+msg); + }; + + // Mapping of button events to BlackBerry key identifier. + var buttonMapping = { + 'backbutton' : blackberry.system.event.KEY_BACK, + 'conveniencebutton1' : blackberry.system.event.KEY_CONVENIENCE_1, + 'conveniencebutton2' : blackberry.system.event.KEY_CONVENIENCE_2, + 'endcallbutton' : blackberry.system.event.KEY_ENDCALL, + 'menubutton' : blackberry.system.event.KEY_MENU, + 'startcallbutton' : blackberry.system.event.KEY_STARTCALL, + 'volumedownbutton' : blackberry.system.event.KEY_VOLUMEDOWN, + 'volumeupbutton' : blackberry.system.event.KEY_VOLUMEUP + }; + + // Generates a function which fires the specified event. + var fireEvent = function(event) { + return function() { + cordova.fireDocumentEvent(event, null); + }; + }; + + var eventHandler = function(event) { + return function() { + // If we just attached the first handler, let native know we + // need to override the hardware button. + if (this.numHandlers) { + blackberry.system.event.onHardwareKey( + buttonMapping[event], fireEvent(event)); + } + // If we just detached the last handler, let native know we + // no longer override the hardware button. + else { + blackberry.system.event.onHardwareKey( + buttonMapping[event], null); + } + }; + }; + + // Inject listeners for buttons on the document. + for (var button in buttonMapping) { + if (buttonMapping.hasOwnProperty(button)) { + var buttonChannel = cordova.addDocumentEventHandler(button); + buttonChannel.onHasSubscribersChange = eventHandler(button); + } + } + + // Fires off necessary code to pause/resume app + var resume = function() { + cordova.fireDocumentEvent('resume'); + manager.resume(); + }; + var pause = function() { + cordova.fireDocumentEvent('pause'); + manager.pause(); + }; + + /************************************************ + * Patch up the generic pause/resume listeners. * + ************************************************/ + + // Unsubscribe handler - turns off native backlight change + // listener + var onHasSubscribersChange = function() { + // If we just attached the first handler and there are + // no pause handlers, start the backlight system + // listener on the native side. + if (this.numHandlers && (channel.onResume.numHandlers + channel.onPause.numHandlers === 1)) { + exec(backlightWin, backlightFail, "App", "detectBacklight", []); + } else if (channel.onResume.numHandlers === 0 && channel.onPause.numHandlers === 0) { + exec(null, null, 'App', 'ignoreBacklight', []); + } + }; + + // Native backlight detection win/fail callbacks + var backlightWin = function(isOn) { + if (isOn === true) { + resume(); + } else { + pause(); + } + }; + var backlightFail = function(e) { + console.log("Error detecting backlight on/off."); + }; + + // Override stock resume and pause listeners so we can trigger + // some native methods during attach/remove + channel.onResume = cordova.addDocumentEventHandler('resume'); + channel.onResume.onHasSubscribersChange = onHasSubscribersChange; + channel.onPause = cordova.addDocumentEventHandler('pause'); + channel.onPause.onHasSubscribersChange = onHasSubscribersChange; + + // Fire resume event when application brought to foreground. + blackberry.app.event.onForeground(resume); + + // Fire pause event when application sent to background. + blackberry.app.event.onBackground(pause); + + // Trap BlackBerry WebWorks exit. Allow plugins to clean up before exiting. + blackberry.app.event.onExit(app.exitApp); + } +}; + +}); + +// file: lib/common/plugin/logger.js +define("cordova/plugin/logger", function(require, exports, module) { + +//------------------------------------------------------------------------------ +// The logger module exports the following properties/functions: +// +// LOG - constant for the level LOG +// ERROR - constant for the level ERROR +// WARN - constant for the level WARN +// INFO - constant for the level INFO +// DEBUG - constant for the level DEBUG +// logLevel() - returns current log level +// logLevel(value) - sets and returns a new log level +// useConsole() - returns whether logger is using console +// useConsole(value) - sets and returns whether logger is using console +// log(message,...) - logs a message at level LOG +// error(message,...) - logs a message at level ERROR +// warn(message,...) - logs a message at level WARN +// info(message,...) - logs a message at level INFO +// debug(message,...) - logs a message at level DEBUG +// logLevel(level,message,...) - logs a message specified level +// +//------------------------------------------------------------------------------ + +var logger = exports; + +var exec = require('cordova/exec'); +var utils = require('cordova/utils'); + +var UseConsole = true; +var Queued = []; +var DeviceReady = false; +var CurrentLevel; + +/** + * Logging levels + */ + +var Levels = [ + "LOG", + "ERROR", + "WARN", + "INFO", + "DEBUG" +]; + +/* + * add the logging levels to the logger object and + * to a separate levelsMap object for testing + */ + +var LevelsMap = {}; +for (var i=0; i CurrentLevel) return; + + // queue the message if not yet at deviceready + if (!DeviceReady && !UseConsole) { + Queued.push([level, message]); + return; + } + + // if not using the console, use the native logger + if (!UseConsole) { + exec(null, null, "Logger", "logLevel", [level, message]); + return; + } + + // make sure console is not using logger + if (console.__usingCordovaLogger) { + throw new Error("console and logger are too intertwingly"); + } + + // log to the console + switch (level) { + case logger.LOG: console.log(message); break; + case logger.ERROR: console.log("ERROR: " + message); break; + case logger.WARN: console.log("WARN: " + message); break; + case logger.INFO: console.log("INFO: " + message); break; + case logger.DEBUG: console.log("DEBUG: " + message); break; + } +}; + +// when deviceready fires, log queued messages +logger.__onDeviceReady = function() { + if (DeviceReady) return; + + DeviceReady = true; + + for (var i=0; i 0) { + capture("photo", win, fail); + } + else { + win([]); + } + + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "WebWorks Is On It" }; + }, + captureVideo: function (args, win, fail) { + if (args[0].limit > 0) { + capture("video", win, fail); + } + else { + win([]); + } + + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "WebWorks Is On It" }; + }, + captureAudio: function (args, win, fail) { + fail("Capturing Audio not supported"); + return {"status": cordova.callbackStatus.NO_RESULT, "message": "WebWorks Is On It"}; + } +}; + +}); + +// file: lib/blackberry/plugin/qnx/compass.js +define("cordova/plugin/qnx/compass", function(require, exports, module) { + +var exec = require('cordova/exec'), + utils = require('cordova/utils'), + CompassHeading = require('cordova/plugin/CompassHeading'), + CompassError = require('cordova/plugin/CompassError'), + timers = {}, + listeners = [], + heading = null, + running = false, + start = function () { + exec(function (result) { + heading = new CompassHeading(result.magneticHeading, result.trueHeading, result.headingAccuracy, result.timestamp); + listeners.forEach(function (l) { + l.win(heading); + }); + }, function (e) { + listeners.forEach(function (l) { + l.fail(e); + }); + }, + "Compass", "start", []); + running = true; + }, + stop = function () { + exec(null, null, "Compass", "stop", []); + running = false; + }, + createCallbackPair = function (win, fail) { + return {win:win, fail:fail}; + }, + removeListeners = function (l) { + var idx = listeners.indexOf(l); + if (idx > -1) { + listeners.splice(idx, 1); + if (listeners.length === 0) { + stop(); + } + } + }, + compass = { + /** + * Asynchronously acquires the current heading. + * @param {Function} successCallback The function to call when the heading + * data is available + * @param {Function} errorCallback The function to call when there is an error + * getting the heading data. + * @param {CompassOptions} options The options for getting the heading data (not used). + */ + getCurrentHeading:function(successCallback, errorCallback, options) { + if (typeof successCallback !== "function") { + throw "getCurrentHeading must be called with at least a success callback function as first parameter."; + } + + var p; + var win = function(a) { + removeListeners(p); + successCallback(a); + }; + var fail = function(e) { + removeListeners(p); + errorCallback(e); + }; + + p = createCallbackPair(win, fail); + listeners.push(p); + + if (!running) { + start(); + } + }, + + /** + * Asynchronously acquires the heading repeatedly at a given interval. + * @param {Function} successCallback The function to call each time the heading + * data is available + * @param {Function} errorCallback The function to call when there is an error + * getting the heading data. + * @param {HeadingOptions} options The options for getting the heading data + * such as timeout and the frequency of the watch. For iOS, filter parameter + * specifies to watch via a distance filter rather than time. + */ + watchHeading:function(successCallback, errorCallback, options) { + var frequency = (options !== undefined && options.frequency !== undefined) ? options.frequency : 100; + var filter = (options !== undefined && options.filter !== undefined) ? options.filter : 0; + + // successCallback required + if (typeof successCallback !== "function") { + console.log("Compass Error: successCallback is not a function"); + return; + } + + // errorCallback optional + if (errorCallback && (typeof errorCallback !== "function")) { + console.log("Compass Error: errorCallback is not a function"); + return; + } + // Keep reference to watch id, and report heading readings as often as defined in frequency + var id = utils.createUUID(); + + var p = createCallbackPair(function(){}, function(e) { + removeListeners(p); + errorCallback(e); + }); + listeners.push(p); + + timers[id] = { + timer:window.setInterval(function() { + if (heading) { + successCallback(heading); + } + }, frequency), + listeners:p + }; + + if (running) { + // If we're already running then immediately invoke the success callback + // but only if we have retrieved a value, sample code does not check for null ... + if(heading) { + successCallback(heading); + } + } else { + start(); + } + + return id; + }, + + /** + * Clears the specified heading watch. + * @param {String} watchId The ID of the watch returned from #watchHeading. + */ + clearWatch:function(id) { + // Stop javascript timer & remove from timer list + if (id && timers[id]) { + window.clearInterval(timers[id].timer); + removeListeners(timers[id].listeners); + delete timers[id]; + } + } + }; + +module.exports = compass; + +}); + +// file: lib/blackberry/plugin/qnx/compass/bbsymbols.js +define("cordova/plugin/qnx/compass/bbsymbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.merges('cordova/plugin/qnx/compass', 'navigator.compass'); + +}); + +// file: lib/blackberry/plugin/qnx/device.js +define("cordova/plugin/qnx/device", function(require, exports, module) { + +var channel = require('cordova/channel'), + cordova = require('cordova'); + +// Tell cordova channel to wait on the CordovaInfoReady event +channel.waitForInitialization('onCordovaInfoReady'); + +module.exports = { + getDeviceInfo : function(args, win, fail){ + win({ + platform: "BlackBerry", + version: blackberry.system.softwareVersion, + model: "Dev Alpha", + name: "Dev Alpha", // deprecated: please use device.model + uuid: blackberry.identity.uuid, + cordova: "2.5.0" + }); + + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "Device info returned" }; + } +}; + +}); + +// file: lib/blackberry/plugin/qnx/file.js +define("cordova/plugin/qnx/file", function(require, exports, module) { + +/*global WebKitBlobBuilder:false */ +var cordova = require('cordova'), + FileError = require('cordova/plugin/FileError'), + DirectoryEntry = require('cordova/plugin/DirectoryEntry'), + FileEntry = require('cordova/plugin/FileEntry'), + File = require('cordova/plugin/File'), + FileSystem = require('cordova/plugin/FileSystem'), + FileReader = require('cordova/plugin/FileReader'), + nativeRequestFileSystem = window.webkitRequestFileSystem, + nativeResolveLocalFileSystemURI = function(uri, success, fail) { + if (uri.substring(0,11) !== "filesystem:") { + uri = "filesystem:" + uri; + } + window.webkitResolveLocalFileSystemURL(uri, success, fail); + }, + NativeFileReader = window.FileReader; + +window.FileReader = FileReader; +window.File = File; + +function getFileSystemName(nativeFs) { + return (nativeFs.name.indexOf("Persistent") != -1) ? "persistent" : "temporary"; +} + +function makeEntry(entry) { + if (entry.isDirectory) { + return new DirectoryEntry(entry.name, decodeURI(entry.toURL()).substring(11)); + } + else { + return new FileEntry(entry.name, decodeURI(entry.toURL()).substring(11)); + } +} + +module.exports = { + /* requestFileSystem */ + requestFileSystem: function(args, successCallback, errorCallback) { + var type = args[0], + size = args[1]; + + nativeRequestFileSystem(type, size, function(nativeFs) { + successCallback(new FileSystem(getFileSystemName(nativeFs), makeEntry(nativeFs.root))); + }, function(error) { + errorCallback(error.code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + /* resolveLocalFileSystemURI */ + resolveLocalFileSystemURI: function(args, successCallback, errorCallback) { + var uri = args[0]; + + nativeResolveLocalFileSystemURI(uri, function(entry) { + successCallback(makeEntry(entry)); + }, function(error) { + var code = error.code; + switch (code) { + case 5: + code = FileError.NOT_FOUND_ERR; + break; + + case 2: + code = FileError.ENCODING_ERR; + break; + } + errorCallback(code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + /* DirectoryReader */ + readEntries: function(args, successCallback, errorCallback) { + var uri = args[0]; + + nativeResolveLocalFileSystemURI(uri, function(dirEntry) { + var reader = dirEntry.createReader(); + reader.readEntries(function(entries) { + var retVal = []; + for (var i = 0; i < entries.length; i++) { + retVal.push(makeEntry(entries[i])); + } + successCallback(retVal); + }, function(error) { + errorCallback(error.code); + }); + }, function(error) { + errorCallback(error.code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + /* Entry */ + getMetadata: function(args, successCallback, errorCallback) { + var uri = args[0]; + + nativeResolveLocalFileSystemURI(uri, function(entry) { + entry.getMetadata(function(metaData) { + successCallback(metaData.modificationTime); + }, function(error) { + errorCallback(error.code); + }); + }, function(error) { + errorCallback(error.code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + moveTo: function(args, successCallback, errorCallback) { + var srcUri = args[0], + parentUri = args[1], + name = args[2]; + + nativeResolveLocalFileSystemURI(srcUri, function(source) { + nativeResolveLocalFileSystemURI(parentUri, function(parent) { + source.moveTo(parent, name, function(entry) { + successCallback(makeEntry(entry)); + }, function(error) { + errorCallback(error.code); + }); + }, function(error) { + errorCallback(error.code); + }); + }, function(error) { + errorCallback(error.code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + copyTo: function(args, successCallback, errorCallback) { + var srcUri = args[0], + parentUri = args[1], + name = args[2]; + + nativeResolveLocalFileSystemURI(srcUri, function(source) { + nativeResolveLocalFileSystemURI(parentUri, function(parent) { + source.copyTo(parent, name, function(entry) { + successCallback(makeEntry(entry)); + }, function(error) { + errorCallback(error.code); + }); + }, function(error) { + errorCallback(error.code); + }); + }, function(error) { + errorCallback(error.code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + remove: function(args, successCallback, errorCallback) { + var uri = args[0]; + + nativeResolveLocalFileSystemURI(uri, function(entry) { + if (entry.fullPath === "/") { + errorCallback(FileError.NO_MODIFICATION_ALLOWED_ERR); + } else { + entry.remove( + function (success) { + if (successCallback) { + successCallback(success); + } + }, + function(error) { + if (errorCallback) { + errorCallback(error.code); + } + } + ); + } + }, function(error) { + errorCallback(error.code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + getParent: function(args, successCallback, errorCallback) { + var uri = args[0]; + + nativeResolveLocalFileSystemURI(uri, function(entry) { + entry.getParent(function(entry) { + successCallback(makeEntry(entry)); + }, function(error) { + errorCallback(error.code); + }); + }, function(error) { + errorCallback(error.code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + /* FileEntry */ + getFileMetadata: function(args, successCallback, errorCallback) { + var uri = args[0]; + + nativeResolveLocalFileSystemURI(uri, function(entry) { + entry.file(function(file) { + var retVal = new File(file.name, decodeURI(entry.toURL()), file.type, file.lastModifiedDate, file.size); + successCallback(retVal); + }, function(error) { + errorCallback(error.code); + }); + }, function(error) { + errorCallback(error.code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + /* DirectoryEntry */ + getDirectory: function(args, successCallback, errorCallback) { + var uri = args[0], + path = args[1], + options = args[2]; + + nativeResolveLocalFileSystemURI(uri, function(entry) { + entry.getDirectory(path, options, function(entry) { + successCallback(makeEntry(entry)); + }, function(error) { + if (error.code === FileError.INVALID_MODIFICATION_ERR) { + if (options.create) { + errorCallback(FileError.PATH_EXISTS_ERR); + } else { + errorCallback(FileError.ENCODING_ERR); + } + } else { + errorCallback(error.code); + } + }); + }, function(error) { + errorCallback(error.code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + removeRecursively: function(args, successCallback, errorCallback) { + var uri = args[0]; + + nativeResolveLocalFileSystemURI(uri, function(entry) { + if (entry.fullPath === "/") { + errorCallback(FileError.NO_MODIFICATION_ALLOWED_ERR); + } else { + entry.removeRecursively( + function (success) { + if (successCallback) { + successCallback(success); + } + }, + function(error) { + errorCallback(error.code); + } + ); + } + }, function(error) { + errorCallback(error.code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + getFile: function(args, successCallback, errorCallback) { + var uri = args[0], + path = args[1], + options = args[2]; + + nativeResolveLocalFileSystemURI(uri, function(entry) { + entry.getFile(path, options, function(entry) { + successCallback(makeEntry(entry)); + }, function(error) { + if (error.code === FileError.INVALID_MODIFICATION_ERR) { + if (options.create) { + errorCallback(FileError.PATH_EXISTS_ERR); + } else { + errorCallback(FileError.NOT_FOUND_ERR); + } + } else { + errorCallback(error.code); + } + }); + }, function(error) { + errorCallback(error.code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + /* FileReader */ + readAsText: function(args, successCallback, errorCallback) { + var uri = args[0], + encoding = args[1]; + + nativeResolveLocalFileSystemURI(uri, function(entry) { + var onLoadEnd = function(evt) { + if (!evt.target.error) { + successCallback(evt.target.result); + } + }, + onError = function(evt) { + errorCallback(evt.target.error.code); + }; + + var reader = new NativeFileReader(); + + reader.onloadend = onLoadEnd; + reader.onerror = onError; + entry.file(function(file) { + reader.readAsText(file, encoding); + }, function(error) { + errorCallback(error.code); + }); + }, function(error) { + errorCallback(error.code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + readAsDataURL: function(args, successCallback, errorCallback) { + var uri = args[0]; + + nativeResolveLocalFileSystemURI(uri, function(entry) { + var onLoadEnd = function(evt) { + if (!evt.target.error) { + successCallback(evt.target.result); + } + }, + onError = function(evt) { + errorCallback(evt.target.error.code); + }; + + var reader = new NativeFileReader(); + + reader.onloadend = onLoadEnd; + reader.onerror = onError; + entry.file(function(file) { + reader.readAsDataURL(file); + }, function(error) { + errorCallback(error.code); + }); + }, function(error) { + errorCallback(error.code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + /* FileWriter */ + write: function(args, successCallback, errorCallback) { + var uri = args[0], + text = args[1], + position = args[2]; + + nativeResolveLocalFileSystemURI(uri, function(entry) { + var onWriteEnd = function(evt) { + if(!evt.target.error) { + successCallback(evt.target.position - position); + } else { + errorCallback(evt.target.error.code); + } + }, + onError = function(evt) { + errorCallback(evt.target.error.code); + }; + + entry.createWriter(function(writer) { + writer.onwriteend = onWriteEnd; + writer.onerror = onError; + + writer.seek(position); + writer.write(new Blob([text], {type: "text/plain"})); + }, function(error) { + errorCallback(error.code); + }); + }, function(error) { + errorCallback(error.code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + truncate: function(args, successCallback, errorCallback) { + var uri = args[0], + size = args[1]; + + nativeResolveLocalFileSystemURI(uri, function(entry) { + var onWriteEnd = function(evt) { + if(!evt.target.error) { + successCallback(evt.target.length); + } else { + errorCallback(evt.target.error.code); + } + }, + onError = function(evt) { + errorCallback(evt.target.error.code); + }; + + entry.createWriter(function(writer) { + writer.onwriteend = onWriteEnd; + writer.onerror = onError; + + writer.truncate(size); + }, function(error) { + errorCallback(error.code); + }); + }, function(error) { + errorCallback(error.code); + }); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + } +}; + +}); + +// file: lib/blackberry/plugin/qnx/fileTransfer.js +define("cordova/plugin/qnx/fileTransfer", function(require, exports, module) { + +var cordova = require('cordova'), + FileEntry = require('cordova/plugin/FileEntry'), + FileTransferError = require('cordova/plugin/FileTransferError'), + FileUploadResult = require('cordova/plugin/FileUploadResult'), + ProgressEvent = require('cordova/plugin/ProgressEvent'), + nativeResolveLocalFileSystemURI = function(uri, success, fail) { + if (uri.substring(0,11) !== "filesystem:") { + uri = "filesystem:" + uri; + } + window.webkitResolveLocalFileSystemURL(uri, success, fail); + }, + xhr; + +function getParentPath(filePath) { + var pos = filePath.lastIndexOf('/'); + return filePath.substring(0, pos + 1); +} + +function getFileName(filePath) { + var pos = filePath.lastIndexOf('/'); + return filePath.substring(pos + 1); +} + +function cleanUpPath(filePath) { + var pos = filePath.lastIndexOf('/'); + return filePath.substring(0, pos) + filePath.substring(pos + 1, filePath.length); +} + +function checkURL(url) { + return url.indexOf(' ') === -1 ? true : false; +} + +module.exports = { + abort: function () { + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + upload: function(args, win, fail) { + var filePath = args[0], + server = args[1], + fileKey = args[2], + fileName = args[3], + mimeType = args[4], + params = args[5], + /*trustAllHosts = args[6],*/ + chunkedMode = args[7], + headers = args[8]; + + if (!checkURL(server)) { + fail(new FileTransferError(FileTransferError.INVALID_URL_ERR)); + } + + nativeResolveLocalFileSystemURI(filePath, function(entry) { + entry.file(function(file) { + function uploadFile(blobFile) { + var fd = new FormData(); + + fd.append(fileKey, blobFile, fileName); + for (var prop in params) { + if(params.hasOwnProperty(prop)) { + fd.append(prop, params[prop]); + } + } + + xhr = new XMLHttpRequest(); + xhr.open("POST", server); + xhr.onload = function(evt) { + if (xhr.status == 200) { + var result = new FileUploadResult(); + result.bytesSent = file.size; + result.responseCode = xhr.status; + result.response = xhr.response; + win(result); + } else if (xhr.status == 404) { + fail(new FileTransferError(FileTransferError.INVALID_URL_ERR, server, filePath, xhr.status)); + } else { + fail(new FileTransferError(FileTransferError.CONNECTION_ERR, server, filePath, xhr.status)); + } + }; + xhr.ontimeout = function(evt) { + fail(new FileTransferError(FileTransferError.CONNECTION_ERR, server, filePath, xhr.status)); + }; + xhr.onerror = function () { + fail(new FileTransferError(FileTransferError.CONNECTION_ERR, server, filePath, this.status)); + }; + xhr.onprogress = function (evt) { + win(evt); + }; + + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + xhr.setRequestHeader(header, headers[header]); + } + } + + xhr.send(fd); + } + + var bytesPerChunk; + if (chunkedMode === true) { + bytesPerChunk = 1024 * 1024; // 1MB chunk sizes. + } else { + bytesPerChunk = file.size; + } + var start = 0; + var end = bytesPerChunk; + while (start < file.size) { + var chunk = file.slice(start, end, mimeType); + uploadFile(chunk); + start = end; + end = start + bytesPerChunk; + } + }, function(error) { + fail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR)); + }); + }, function(error) { + fail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR)); + }); + + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + }, + + download: function (args, win, fail) { + var source = args[0], + target = cleanUpPath(args[1]), + fileWriter; + + if (!checkURL(source)) { + fail(new FileTransferError(FileTransferError.INVALID_URL_ERR)); + } + + xhr = new XMLHttpRequest(); + + function writeFile(entry) { + entry.createWriter(function (writer) { + fileWriter = writer; + fileWriter.onwriteend = function (evt) { + if (!evt.target.error) { + win(new FileEntry(entry.name, entry.toURL())); + } else { + fail(evt.target.error); + } + }; + fileWriter.onerror = function (evt) { + fail(evt.target.error); + }; + fileWriter.write(new Blob([xhr.response])); + }, function (error) { + fail(error); + }); + } + + xhr.onerror = function (e) { + fail(new FileTransferError(FileTransferError.CONNECTION_ERR, source, target, xhr.status)); + }; + + xhr.onload = function () { + if (xhr.readyState === xhr.DONE) { + if (xhr.status === 200 && xhr.response) { + nativeResolveLocalFileSystemURI(getParentPath(target), function (dir) { + dir.getFile(getFileName(target), {create: true}, writeFile, function (error) { + fail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR)); + }); + }, function (error) { + fail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR)); + }); + } else if (xhr.status === 404) { + fail(new FileTransferError(FileTransferError.INVALID_URL_ERR, source, target, xhr.status)); + } else { + fail(new FileTransferError(FileTransferError.CONNECTION_ERR, source, target, xhr.status)); + } + } + }; + xhr.onprogress = function (evt) { + win(evt); + }; + + xhr.responseType = "blob"; + xhr.open("GET", source, true); + xhr.send(); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "async"}; + } +}; + +}); + +// file: lib/blackberry/plugin/qnx/inappbrowser/bbsymbols.js +define("cordova/plugin/qnx/inappbrowser/bbsymbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/InAppBrowser', 'open'); + +}); + +// file: lib/blackberry/plugin/qnx/magnetometer.js +define("cordova/plugin/qnx/magnetometer", function(require, exports, module) { + +var cordova = require('cordova'), + callback; + +module.exports = { + start: function (args, win, fail) { + window.removeEventListener("deviceorientation", callback); + callback = function (orientation) { + var heading = 360 - orientation.alpha; + win({ + magneticHeading: heading, + trueHeading: heading, + headingAccuracy: 0, + timestamp: orientation.timeStamp + }); + }; + + window.addEventListener("deviceorientation", callback); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "WebWorks Is On It" }; + }, + stop: function (args, win, fail) { + window.removeEventListener("deviceorientation", callback); + return { "status" : cordova.callbackStatus.OK, "message" : "removed" }; + } +}; + +}); + +// file: lib/blackberry/plugin/qnx/manager.js +define("cordova/plugin/qnx/manager", function(require, exports, module) { + +var cordova = require('cordova'), + plugins = { + 'NetworkStatus' : require('cordova/plugin/qnx/network'), + 'Accelerometer' : require('cordova/plugin/webworks/accelerometer'), + 'Device' : require('cordova/plugin/qnx/device'), + 'Battery' : require('cordova/plugin/qnx/battery'), + 'Compass' : require('cordova/plugin/qnx/magnetometer'), + 'Camera' : require('cordova/plugin/qnx/camera'), + 'Capture' : require('cordova/plugin/qnx/capture'), + 'Logger' : require('cordova/plugin/webworks/logger'), + 'Notification' : require('cordova/plugin/webworks/notification'), + 'Media': require('cordova/plugin/webworks/media'), + 'File' : require('cordova/plugin/qnx/file'), + 'InAppBrowser' : require('cordova/plugin/qnx/InAppBrowser'), + 'FileTransfer': require('cordova/plugin/qnx/fileTransfer') + }; + +module.exports = { + addPlugin: function (key, module) { + plugins[key] = require(module); + }, + exec: function (win, fail, clazz, action, args) { + var result = {"status" : cordova.callbackStatus.CLASS_NOT_FOUND_EXCEPTION, "message" : "Class " + clazz + " cannot be found"}; + + if (plugins[clazz]) { + if (plugins[clazz][action]) { + result = plugins[clazz][action](args, win, fail); + } + else { + result = { "status" : cordova.callbackStatus.INVALID_ACTION, "message" : "Action not found: " + action }; + } + } + + return result; + }, + resume: function () {}, + pause: function () {}, + destroy: function () {} +}; + +}); + +// file: lib/blackberry/plugin/qnx/network.js +define("cordova/plugin/qnx/network", function(require, exports, module) { + +var cordova = require('cordova'); + +module.exports = { + getConnectionInfo: function (args, win, fail) { + return { "status": cordova.callbackStatus.OK, "message": blackberry.connection.type}; + } +}; + +}); + +// file: lib/blackberry/plugin/qnx/platform.js +define("cordova/plugin/qnx/platform", function(require, exports, module) { + +var cordova = require('cordova'); + +module.exports = { + id: "qnx", + initialize: function () { + document.addEventListener("deviceready", function () { + blackberry.event.addEventListener("pause", function () { + cordova.fireDocumentEvent("pause"); + }); + blackberry.event.addEventListener("resume", function () { + cordova.fireDocumentEvent("resume"); + }); + + window.addEventListener("online", function () { + cordova.fireDocumentEvent("online"); + }); + + window.addEventListener("offline", function () { + cordova.fireDocumentEvent("offline"); + }); + }); + } +}; + +}); + +// file: lib/common/plugin/requestFileSystem.js +define("cordova/plugin/requestFileSystem", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + FileError = require('cordova/plugin/FileError'), + FileSystem = require('cordova/plugin/FileSystem'), + exec = require('cordova/exec'); + +/** + * Request a file system in which to store application data. + * @param type local file system type + * @param size indicates how much storage space, in bytes, the application expects to need + * @param successCallback invoked with a FileSystem object + * @param errorCallback invoked if error occurs retrieving file system + */ +var requestFileSystem = function(type, size, successCallback, errorCallback) { + argscheck.checkArgs('nnFF', 'requestFileSystem', arguments); + var fail = function(code) { + errorCallback && errorCallback(new FileError(code)); + }; + + if (type < 0 || type > 3) { + fail(FileError.SYNTAX_ERR); + } else { + // if successful, return a FileSystem object + var success = function(file_system) { + if (file_system) { + if (successCallback) { + // grab the name and root from the file system object + var result = new FileSystem(file_system.name, file_system.root); + successCallback(result); + } + } + else { + // no FileSystem object returned + fail(FileError.NOT_FOUND_ERR); + } + }; + exec(success, fail, "File", "requestFileSystem", [type, size]); + } +}; + +module.exports = requestFileSystem; + +}); + +// file: lib/common/plugin/resolveLocalFileSystemURI.js +define("cordova/plugin/resolveLocalFileSystemURI", function(require, exports, module) { + +var argscheck = require('cordova/argscheck'), + DirectoryEntry = require('cordova/plugin/DirectoryEntry'), + FileEntry = require('cordova/plugin/FileEntry'), + FileError = require('cordova/plugin/FileError'), + exec = require('cordova/exec'); + +/** + * Look up file system Entry referred to by local URI. + * @param {DOMString} uri URI referring to a local file or directory + * @param successCallback invoked with Entry object corresponding to URI + * @param errorCallback invoked if error occurs retrieving file system entry + */ +module.exports = function(uri, successCallback, errorCallback) { + argscheck.checkArgs('sFF', 'resolveLocalFileSystemURI', arguments); + // error callback + var fail = function(error) { + errorCallback && errorCallback(new FileError(error)); + }; + // sanity check for 'not:valid:filename' + if(!uri || uri.split(":").length > 2) { + setTimeout( function() { + fail(FileError.ENCODING_ERR); + },0); + return; + } + // if successful, return either a file or directory entry + var success = function(entry) { + var result; + if (entry) { + if (successCallback) { + // create appropriate Entry object + result = (entry.isDirectory) ? new DirectoryEntry(entry.name, entry.fullPath) : new FileEntry(entry.name, entry.fullPath); + successCallback(result); + } + } + else { + // no Entry object returned + fail(FileError.NOT_FOUND_ERR); + } + }; + + exec(success, fail, "File", "resolveLocalFileSystemURI", [uri]); +}; + +}); + +// file: lib/common/plugin/splashscreen.js +define("cordova/plugin/splashscreen", function(require, exports, module) { + +var exec = require('cordova/exec'); + +var splashscreen = { + show:function() { + exec(null, null, "SplashScreen", "show", []); + }, + hide:function() { + exec(null, null, "SplashScreen", "hide", []); + } +}; + +module.exports = splashscreen; + +}); + +// file: lib/common/plugin/splashscreen/symbols.js +define("cordova/plugin/splashscreen/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'); + +modulemapper.clobbers('cordova/plugin/splashscreen', 'navigator.splashscreen'); + +}); + +// file: lib/blackberry/plugin/webworks/accelerometer.js +define("cordova/plugin/webworks/accelerometer", function(require, exports, module) { + +var cordova = require('cordova'), + callback; + +module.exports = { + start: function (args, win, fail) { + window.removeEventListener("devicemotion", callback); + callback = function (motion) { + win({ + x: motion.accelerationIncludingGravity.x, + y: motion.accelerationIncludingGravity.y, + z: motion.accelerationIncludingGravity.z, + timestamp: motion.timestamp + }); + }; + window.addEventListener("devicemotion", callback); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "WebWorks Is On It" }; + }, + stop: function (args, win, fail) { + window.removeEventListener("devicemotion", callback); + return { "status" : cordova.callbackStatus.OK, "message" : "removed" }; + } +}; + +}); + +// file: lib/blackberry/plugin/webworks/logger.js +define("cordova/plugin/webworks/logger", function(require, exports, module) { + +var cordova = require('cordova'); + +module.exports = { + log: function (args, win, fail) { + console.log(args); + return {"status" : cordova.callbackStatus.OK, + "message" : 'Message logged to console: ' + args}; + } +}; + +}); + +// file: lib/blackberry/plugin/webworks/media.js +define("cordova/plugin/webworks/media", function(require, exports, module) { + +var cordova = require('cordova'), + audioObjects = {}; + +module.exports = { + create: function (args, win, fail) { + if (!args.length) { + return {"status" : 9, "message" : "Media Object id was not sent in arguments"}; + } + + var id = args[0], + src = args[1]; + + if (typeof src == "undefined"){ + audioObjects[id] = new Audio(); + } else { + audioObjects[id] = new Audio(src); + } + + return {"status" : 1, "message" : "Audio object created" }; + }, + startPlayingAudio: function (args, win, fail) { + if (!args.length) { + return {"status" : 9, "message" : "Media Object id was not sent in arguments"}; + } + + var id = args[0], + audio = audioObjects[id], + result; + + if (args.length === 1 || typeof args[1] == "undefined" ) { + return {"status" : 9, "message" : "Media source argument not found"}; + } + + if (audio) { + audio.pause(); + audioObjects[id] = undefined; + } + + audio = audioObjects[id] = new Audio(args[1]); + audio.play(); + return {"status" : 1, "message" : "Audio play started" }; + }, + stopPlayingAudio: function (args, win, fail) { + if (!args.length) { + return {"status" : 9, "message" : "Media Object id was not sent in arguments"}; + } + + var id = args[0], + audio = audioObjects[id], + result; + + if (!audio) { + return {"status" : 2, "message" : "Audio Object has not been initialized"}; + } + + audio.pause(); + audioObjects[id] = undefined; + + return {"status" : 1, "message" : "Audio play stopped" }; + }, + seekToAudio: function (args, win, fail) { + if (!args.length) { + return {"status" : 9, "message" : "Media Object id was not sent in arguments"}; + } + + var id = args[0], + audio = audioObjects[id], + result; + + if (!audio) { + result = {"status" : 2, "message" : "Audio Object has not been initialized"}; + } else if (args.length === 1) { + result = {"status" : 9, "message" : "Media seek time argument not found"}; + } else { + try { + audio.currentTime = args[1]; + } catch (e) { + console.log('Error seeking audio: ' + e); + return {"status" : 3, "message" : "Error seeking audio: " + e}; + } + + result = {"status" : 1, "message" : "Seek to audio succeeded" }; + } + return result; + }, + pausePlayingAudio: function (args, win, fail) { + if (!args.length) { + return {"status" : 9, "message" : "Media Object id was not sent in arguments"}; + } + + var id = args[0], + audio = audioObjects[id], + result; + + if (!audio) { + return {"status" : 2, "message" : "Audio Object has not been initialized"}; + } + + audio.pause(); + + return {"status" : 1, "message" : "Audio paused" }; + }, + getCurrentPositionAudio: function (args, win, fail) { + if (!args.length) { + return {"status" : 9, "message" : "Media Object id was not sent in arguments"}; + } + + var id = args[0], + audio = audioObjects[id], + result; + + if (!audio) { + return {"status" : 2, "message" : "Audio Object has not been initialized"}; + } + + return {"status" : 1, "message" : audio.currentTime }; + }, + getDuration: function (args, win, fail) { + if (!args.length) { + return {"status" : 9, "message" : "Media Object id was not sent in arguments"}; + } + + var id = args[0], + audio = audioObjects[id], + result; + + if (!audio) { + return {"status" : 2, "message" : "Audio Object has not been initialized"}; + } + + return {"status" : 1, "message" : audio.duration }; + }, + startRecordingAudio: function (args, win, fail) { + if (!args.length) { + return {"status" : 9, "message" : "Media Object id was not sent in arguments"}; + } + + if (args.length <= 1) { + return {"status" : 9, "message" : "Media start recording, insufficient arguments"}; + } + + blackberry.media.microphone.record(args[1], win, fail); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "WebWorks Is On It" }; + }, + stopRecordingAudio: function (args, win, fail) { + }, + release: function (args, win, fail) { + if (!args.length) { + return {"status" : 9, "message" : "Media Object id was not sent in arguments"}; + } + + var id = args[0], + audio = audioObjects[id], + result; + + if (audio) { + if(audio.src !== ""){ + audio.src = undefined; + } + audioObjects[id] = undefined; + //delete audio; + } + + result = {"status" : 1, "message" : "Media resources released"}; + + return result; + } +}; + +}); + +// file: lib/blackberry/plugin/webworks/notification.js +define("cordova/plugin/webworks/notification", function(require, exports, module) { + +var cordova = require('cordova'); + +module.exports = { + alert: function (args, win, fail) { + if (args.length !== 3) { + return {"status" : 9, "message" : "Notification action - alert arguments not found"}; + } + + //Unpack and map the args + var msg = args[0], + title = args[1], + btnLabel = args[2]; + + blackberry.ui.dialog.customAskAsync.apply(this, [ msg, [ btnLabel ], win, { "title" : title } ]); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "WebWorks Is On It" }; + }, + confirm: function (args, win, fail) { + if (args.length !== 3) { + return {"status" : 9, "message" : "Notification action - confirm arguments not found"}; + } + + //Unpack and map the args + var msg = args[0], + title = args[1], + btnLabel = args[2], + btnLabels = btnLabel.split(","); + + blackberry.ui.dialog.customAskAsync.apply(this, [msg, btnLabels, win, {"title" : title} ]); + return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "WebWorks Is On It" }; + } +}; + +}); + +// file: lib/common/symbols.js +define("cordova/symbols", function(require, exports, module) { + +var modulemapper = require('cordova/modulemapper'); + +// Use merges here in case others symbols files depend on this running first, +// but fail to declare the dependency with a require(). +modulemapper.merges('cordova', 'cordova'); +modulemapper.clobbers('cordova/exec', 'cordova.exec'); +modulemapper.clobbers('cordova/exec', 'Cordova.exec'); + +}); + +// file: lib/common/utils.js +define("cordova/utils", function(require, exports, module) { + +var utils = exports; + +/** + * Defines a property getter / setter for obj[key]. + */ +utils.defineGetterSetter = function(obj, key, getFunc, opt_setFunc) { + if (Object.defineProperty) { + var desc = { + get: getFunc, + configurable: true + }; + if (opt_setFunc) { + desc.set = opt_setFunc; + } + Object.defineProperty(obj, key, desc); + } else { + obj.__defineGetter__(key, getFunc); + if (opt_setFunc) { + obj.__defineSetter__(key, opt_setFunc); + } + } +}; + +/** + * Defines a property getter for obj[key]. + */ +utils.defineGetter = utils.defineGetterSetter; + +utils.arrayIndexOf = function(a, item) { + if (a.indexOf) { + return a.indexOf(item); + } + var len = a.length; + for (var i = 0; i < len; ++i) { + if (a[i] == item) { + return i; + } + } + return -1; +}; + +/** + * Returns whether the item was found in the array. + */ +utils.arrayRemove = function(a, item) { + var index = utils.arrayIndexOf(a, item); + if (index != -1) { + a.splice(index, 1); + } + return index != -1; +}; + +utils.typeName = function(val) { + return Object.prototype.toString.call(val).slice(8, -1); +}; + +/** + * Returns an indication of whether the argument is an array or not + */ +utils.isArray = function(a) { + return utils.typeName(a) == 'Array'; +}; + +/** + * Returns an indication of whether the argument is a Date or not + */ +utils.isDate = function(d) { + return utils.typeName(d) == 'Date'; +}; + +/** + * Does a deep clone of the object. + */ +utils.clone = function(obj) { + if(!obj || typeof obj == 'function' || utils.isDate(obj) || typeof obj != 'object') { + return obj; + } + + var retVal, i; + + if(utils.isArray(obj)){ + retVal = []; + for(i = 0; i < obj.length; ++i){ + retVal.push(utils.clone(obj[i])); + } + return retVal; + } + + retVal = {}; + for(i in obj){ + if(!(i in retVal) || retVal[i] != obj[i]) { + retVal[i] = utils.clone(obj[i]); + } + } + return retVal; +}; + +/** + * Returns a wrapped version of the function + */ +utils.close = function(context, func, params) { + if (typeof params == 'undefined') { + return function() { + return func.apply(context, arguments); + }; + } else { + return function() { + return func.apply(context, params); + }; + } +}; + +/** + * Create a UUID + */ +utils.createUUID = function() { + return UUIDcreatePart(4) + '-' + + UUIDcreatePart(2) + '-' + + UUIDcreatePart(2) + '-' + + UUIDcreatePart(2) + '-' + + UUIDcreatePart(6); +}; + +/** + * Extends a child object from a parent object using classical inheritance + * pattern. + */ +utils.extend = (function() { + // proxy used to establish prototype chain + var F = function() {}; + // extend Child from Parent + return function(Child, Parent) { + F.prototype = Parent.prototype; + Child.prototype = new F(); + Child.__super__ = Parent.prototype; + Child.prototype.constructor = Child; + }; +}()); + +/** + * Alerts a message in any available way: alert or console.log. + */ +utils.alert = function(msg) { + if (window.alert) { + window.alert(msg); + } else if (console && console.log) { + console.log(msg); + } +}; + +/** + * Formats a string and arguments following it ala sprintf() + * + * see utils.vformat() for more information + */ +utils.format = function(formatString /* ,... */) { + var args = [].slice.call(arguments, 1); + return utils.vformat(formatString, args); +}; + +/** + * Formats a string and arguments following it ala vsprintf() + * + * format chars: + * %j - format arg as JSON + * %o - format arg as JSON + * %c - format arg as '' + * %% - replace with '%' + * any other char following % will format it's + * arg via toString(). + * + * for rationale, see FireBug's Console API: + * http://getfirebug.com/wiki/index.php/Console_API + */ +utils.vformat = function(formatString, args) { + if (formatString === null || formatString === undefined) return ""; + if (arguments.length == 1) return formatString.toString(); + if (typeof formatString != "string") return formatString.toString(); + + var pattern = /(.*?)%(.)(.*)/; + var rest = formatString; + var result = []; + + while (args.length) { + var arg = args.shift(); + var match = pattern.exec(rest); + + if (!match) break; + + rest = match[3]; + + result.push(match[1]); + + if (match[2] == '%') { + result.push('%'); + args.unshift(arg); + continue; + } + + result.push(formatted(arg, match[2])); + } + + result.push(rest); + + return result.join(''); +}; + +//------------------------------------------------------------------------------ +function UUIDcreatePart(length) { + var uuidpart = ""; + for (var i=0; i + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + If you fill in the playbook.device.pin value you can use debug tokens! + This means you won't have to worry about having a unique version in config.xml every time. + + + + + + + + + + + + + + + + + + + + + + + + + + This tool will not open the simulator for you + + + + + + + + + + + + + + + + This tool will not open the simulator for you + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +NAME + ${ant.project.name} + +SYNOPSIS + ant TARGET COMMAND [-D<argument>=<value>]... + +DESCRIPTION + You can build and deploy your project to a device or simulator. + +TARGETS + blackberry ........ Builds a cod file and deploys to a device or simulator + + playbook .......... Builds a bar file and deploys to a device or simulator + +COMMANDS + help .............. Show this help menu. + ant, ant help + + load-device ....... Builds and deploys project to a connected USB device. + ant load-device + + load-simulator .... Builds and deploys project to default simulator. + ant load-simulator + + build ............. Compiles and packages the project for deployment. + ant build + + clean ............. Remove all files from the build/ directory. + ant clean + + clean-device ...... Remove this project from the connected USB device. + ant clean-device + + clean-simulator ... Remove this project from the simulator (takes a while). + ant clean-simulator + +GETTING STARTED + 1. Edit project.properties + + 2. <ant <TARGET> load-simulator> to run the project on the simulator + + 3. Customize your project by editing res/config.xml + + 4. To run the project on a BlackBerry device, you will need to obtain + code signing keys from RIM. Once you have the key, a project is + installed by connecting a BlackBerry via USB and running + <ant <TARGET> load-device>. + + + diff --git a/blackberry/project.properties b/blackberry/project.properties new file mode 100644 index 0000000..7867c5d --- /dev/null +++ b/blackberry/project.properties @@ -0,0 +1,137 @@ +# BlackBerry WebWorks Packager Directory +# +# The BlackBerry WebWorks Packager (bbwp) is required for compiling and packaging +# BlackBerry WebWorks applications for deployment to a BlackBerry device +# or simulator. The bbwp utility is installed with the standalone BlackBerry +# WebWorks SDK, and as part of the BlackBerry Web Plugin for Eclipse. +# +# Please specify the location of the BlackBerry WebWorks Packager in your +# environment. +# +# Typical location of bbwp for standalone BlackBerry WebWorks SDK installation: +# C:\Program Files (x86)\Research In Motion\BlackBerry Widget Packager +# +# Typical location of bbwp for BlackBerry Web Plugin for Eclipse installation: +# C:\Eclipse-3.5.2\plugins\net.rim.browser.tools.wcpc_1.0.0.201003191451-126\wcpc +# +# The ANT script is brittle and requires you to escape the backslashes. +# e.g. C:\some\path must be C:\\some\\path +# +# Please remember to: +# - Double escape your backslahses (i.e. \ must be \\) +# - Do not add a trailing slash (e.g. C:\some\path) +# +blackberry.bbwp.dir=/home/mopar/devel/priv/BB10-WebWorks-SDK-Linux +playbook.bbwp.dir=C:\\Program Files\\Research In Motion\\BlackBerry WebWorks SDK for TabletOS 2.1.0.6\\bbwp +qnx.bbwp.dir=/Developer/SDKs/Research In Motion/BlackBerry 10 WebWorks SDK 1.0.4.7 + +# (Optional) Simulator Directory +# +# If sim.dir is not specified, the build script will use the simulator directory +# within the BlackBerry WebWorks Packager. +# +blackberry.sim.dir=C:\\Program Files\\Research In Motion\BlackBerry WebWorks Packager\\simpack\\6.0.0.227 + +# (Optional) Simulator Binary +# +# If sim.bin is not specified, the build script will attempt to use the default +# simulator in the simulator directory. +# +#blackberry.sim.bin=9700.bat + +# (Optional) MDS Directory +# +# If mds.dir is not specified, the build script will attempt to use the MDS that +# is installed with the BlackBerry WebWorks Packager. +# +blackberry.mds.dir=C:\\Program Files\\Research In Motion\\BlackBerry WebWorks Packager\\mds + +# BlackBerry Code Signing Password +# +# If you leave this field blank, then +# the signing tool will prompt you each time +# +blackberry.sigtool.password= + +# Playbook Code Signing Password +# +# If you leave these fields blank, then +# signing will fail +# +playbook.sigtool.csk.password= +playbook.sigtool.p12.password= + +# BB10 Code Signing Password +qnx.sigtool.password= + +# BlackBerry Simulator Password +# +# If you leave this field blank, then +# you cannot deploy to simulator +# +blackberry.sim.password= + +# Playbook Simulator IP +# +# If you leave this field blank, then +# you cannot deploy to simulator +# +playbook.sim.ip= + +# Playbook Simulator Password +# +# If you leave this field blank, then +# you cannot deploy to simulator +# +playbook.sim.password= + +# Playbook Device IP +# +# If you leave this field blank, then +# you cannot deploy to device +# +playbook.device.ip= + +# Playbook Device Password +# +# If you leave this field blank, then +# you cannot deploy to device +# +playbook.device.password= +# PlayBook Device PIN +# +# Fill this value in to use debug tokens when debuging on the device +playbook.device.pin= + +# QNX Simulator IP +# +# If you leave this field blank, then +# you cannot deploy to simulator +# +qnx.sim.ip= + +# QNX Simulator Password +# +# If you leave this field blank, then +# you cannot deploy to simulator +# +qnx.sim.password= + +# QNX Device IP +# +# If you leave this field blank, then +# you cannot deploy to device +# +qnx.device.ip= + +# QNX Device Password +# +# If you leave this field blank, then +# you cannot deploy to device +# +qnx.device.password= + +# QNX Device PIN +# +# Fill this value in to use debug tokens when debuging on the device +qnx.device.pin= diff --git a/blackberry/qnx.xml b/blackberry/qnx.xml new file mode 100644 index 0000000..066af4b --- /dev/null +++ b/blackberry/qnx.xml @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + If you fill in the qnx.device.pin value you can use debug tokens! + This means you won't have to worry about having a unique version in config.xml every time. + + + + + + + + + + + + + + + + + + + + + + + + + + This tool will not open the simulator for you + + + + + + + + + + + + + + + + + This tool will not open the simulator for you + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +NAME + ${ant.project.name} + +SYNOPSIS + ant TARGET COMMAND [-D<argument>=<value>]... + +DESCRIPTION + You can build and deploy your project to a device or simulator. + +TARGETS + blackberry ........ Builds a cod file and deploys to a device or simulator + + playbook .......... Builds a bar file and deploys to a device or simulator + +COMMANDS + help .............. Show this help menu. + ant, ant help + + load-device ....... Builds and deploys project to a connected USB device. + ant load-device + + load-simulator .... Builds and deploys project to default simulator. + ant load-simulator + + build ............. Compiles and packages the project for deployment. + ant build + + clean ............. Remove all files from the build/ directory. + ant clean + + clean-device ...... Remove this project from the connected USB device. + ant clean-device + + clean-simulator ... Remove this project from the simulator (takes a while). + ant clean-simulator + +GETTING STARTED + 1. Edit project.properties + + 2. <ant <TARGET> load-simulator> to run the project on the simulator + + 3. Customize your project by editing res/config.xml + + 4. To run the project on a BlackBerry device, you will need to obtain + code signing keys from RIM. Once you have the key, a project is + installed by connecting a BlackBerry via USB and running + <ant <TARGET> load-device>. + + + diff --git a/blackberry/res/config.xml b/blackberry/res/config.xml new file mode 100644 index 0000000..d098dc8 --- /dev/null +++ b/blackberry/res/config.xml @@ -0,0 +1,112 @@ + + + + + + + Points Watcher + + + Points Watcher is the easiest way to keep track of your Weight Watcher's Points Plus system. + + + + Travis Burtrum (moparisthebest) + + + + Copyright (C) 2013 Travis Burtrum (moparisthebest) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + use_camera + read_device_identifying_information + access_shared + read_geolocation + record_audio + access_pimdomain_contacts + + + diff --git a/blackberry/www b/blackberry/www new file mode 120000 index 0000000..cec6c33 --- /dev/null +++ b/blackberry/www @@ -0,0 +1 @@ +../www \ No newline at end of file diff --git a/images/convert.sh b/images/convert.sh new file mode 100755 index 0000000..91d4dc4 --- /dev/null +++ b/images/convert.sh @@ -0,0 +1,71 @@ +#!/bin/bash +cd "$(dirname "$0")" + +# create directory for market images +mkdir -p ./markets +convert -background none -resize 512x512\! ./icon.svg ./markets/512x512.png + +# icons +# create required directories +mkdir -p ../www/res/icon/android ../www/res/icon/blackberry ../www/res/icon/ios ../www/res/icon/webos ../www/res/icon/windows-phone +# default +convert -background none -resize 96x96\! ./icon.svg ../www/icon.png +# android +convert -background none -resize 96x96\! ./icon.svg ../www/res/icon/android/icon-96-xhdpi.png +convert -background none -resize 72x72\! ./icon.svg ../www/res/icon/android/icon-72-hdpi.png +convert -background none -resize 48x48\! ./icon.svg ../www/res/icon/android/icon-48-mdpi.png +convert -background none -resize 36x36\! ./icon.svg ../www/res/icon/android/icon-36-ldpi.png +# blackberry +convert -background none -resize 80x80\! ./icon.svg ../www/res/icon/blackberry/icon-80.png +# ios +convert -background none -resize 57x57\! ./icon.svg ../www/res/icon/ios/icon-57.png +convert -background none -resize 72x72\! ./icon.svg ../www/res/icon/ios/icon-72.png +convert -background none -resize 114x114\! ./icon.svg ../www/res/icon/ios/icon-57-2x.png +convert -background none -resize 144x144\! ./icon.svg ../www/res/icon/ios/icon-72-2x.png +# webos +convert -background none -resize 64x64\! ./icon.svg ../www/res/icon/webos/icon-64.png +# windows phone +convert -background none -resize 48x48\! ./icon.svg ../www/res/icon/windows-phone/icon-48.png +convert -background none -resize 173x173\! ./icon.svg ../www/res/icon/windows-phone/icon-173.png + +function splash_screen(){ +x="$1" +y="$2" +in_file="$3" +out_file="$4" + +gradient="gradient:gray-white" +gradient="gradient:#A7A7A7-#E4E4E4" +#gradient="radial-gradient:#555555-#222222" + +convert -background none "$in_file" -resize 96x96\! \ +\( -size 1x10 xc:none \) \ +\( -size "${x}x" -background none -font Arial -pointsize 36 -fill "black" -gravity center caption:"Points Watcher" \) \ +-gravity center -append \ +\( -size "${x}x${y}" "$gradient" \) \ ++swap -gravity center -compose over -composite "$out_file" +} + +# splash screens +# create required directories +mkdir -p ../www/res/screen/android ../www/res/screen/blackberry ../www/res/screen/ios ../www/res/screen/windows-phone +# default +splash_screen 480 800 ./icon.svg ../www/screen.png +# android +splash_screen 200 320 ./icon.svg ../www/res/screen/android/screen-ldpi-portrait.png +splash_screen 320 480 ./icon.svg ../www/res/screen/android/screen-mdpi-portrait.png +splash_screen 480 800 ./icon.svg ../www/res/screen/android/screen-hdpi-portrait.png +splash_screen 720 1280 ./icon.svg ../www/res/screen/android/screen-xhdpi-portrait.png +splash_screen 200 320 ./icon.svg ../www/res/screen/android/screen-ldpi-portrait.png +# blackberry (appears to be just the icon) +#splash_screen 225 225 ./icon.svg ../www/res/screen/blackberry/screen-225.png +convert -background none -resize 225x225\! ./icon.svg ../www/res/screen/blackberry/screen-225.png +# ios +splash_screen 320 480 ./icon.svg ../www/res/screen/ios/screen-iphone-portrait.png +splash_screen 640 960 ./icon.svg ../www/res/screen/ios/screen-iphone-portrait-2x.png +splash_screen 768 1024 ./icon.svg ../www/res/screen/ios/screen-ipad-portrait.png +splash_screen 1024 768 ./icon.svg ../www/res/screen/ios/screen-ipad-landscape.png +# windows phone +splash_screen 480 800 ./icon.svg ../www/res/screen/windows-phone/screen-portrait.jpg +# screen shots +#convert -resize 480x854\! ./ss1.png ./markets/ss1.png diff --git a/images/icon.svg b/images/icon.svg new file mode 100644 index 0000000..c57b57e --- /dev/null +++ b/images/icon.svg @@ -0,0 +1,132 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/assets/fonts/sansation/SansationBoldItalicWebfont.eot b/www/assets/fonts/sansation/SansationBoldItalicWebfont.eot new file mode 100755 index 0000000..c36a547 Binary files /dev/null and b/www/assets/fonts/sansation/SansationBoldItalicWebfont.eot differ diff --git a/www/assets/fonts/sansation/SansationBoldItalicWebfont.svg b/www/assets/fonts/sansation/SansationBoldItalicWebfont.svg new file mode 100755 index 0000000..5237a4c --- /dev/null +++ b/www/assets/fonts/sansation/SansationBoldItalicWebfont.svg @@ -0,0 +1,145 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : 2011 Bernd Montag +Designer : Bernd Montag + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/assets/fonts/sansation/SansationBoldItalicWebfont.ttf b/www/assets/fonts/sansation/SansationBoldItalicWebfont.ttf new file mode 100755 index 0000000..b275b2b Binary files /dev/null and b/www/assets/fonts/sansation/SansationBoldItalicWebfont.ttf differ diff --git a/www/assets/fonts/sansation/SansationBoldItalicWebfont.woff b/www/assets/fonts/sansation/SansationBoldItalicWebfont.woff new file mode 100755 index 0000000..980def9 Binary files /dev/null and b/www/assets/fonts/sansation/SansationBoldItalicWebfont.woff differ diff --git a/www/assets/fonts/sansation/SansationBoldWebfont.eot b/www/assets/fonts/sansation/SansationBoldWebfont.eot new file mode 100755 index 0000000..79297d6 Binary files /dev/null and b/www/assets/fonts/sansation/SansationBoldWebfont.eot differ diff --git a/www/assets/fonts/sansation/SansationBoldWebfont.svg b/www/assets/fonts/sansation/SansationBoldWebfont.svg new file mode 100755 index 0000000..9f74046 --- /dev/null +++ b/www/assets/fonts/sansation/SansationBoldWebfont.svg @@ -0,0 +1,145 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : 2011 Bernd Montag +Designer : Bernd Montag + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/assets/fonts/sansation/SansationBoldWebfont.ttf b/www/assets/fonts/sansation/SansationBoldWebfont.ttf new file mode 100755 index 0000000..d8463bc Binary files /dev/null and b/www/assets/fonts/sansation/SansationBoldWebfont.ttf differ diff --git a/www/assets/fonts/sansation/SansationBoldWebfont.woff b/www/assets/fonts/sansation/SansationBoldWebfont.woff new file mode 100755 index 0000000..fbf7390 Binary files /dev/null and b/www/assets/fonts/sansation/SansationBoldWebfont.woff differ diff --git a/www/assets/fonts/sansation/SansationItalicWebfont.eot b/www/assets/fonts/sansation/SansationItalicWebfont.eot new file mode 100755 index 0000000..ae0f133 Binary files /dev/null and b/www/assets/fonts/sansation/SansationItalicWebfont.eot differ diff --git a/www/assets/fonts/sansation/SansationItalicWebfont.svg b/www/assets/fonts/sansation/SansationItalicWebfont.svg new file mode 100755 index 0000000..34583c9 --- /dev/null +++ b/www/assets/fonts/sansation/SansationItalicWebfont.svg @@ -0,0 +1,145 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : 2011 Bernd Montag +Designer : Bernd Montag + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/assets/fonts/sansation/SansationItalicWebfont.ttf b/www/assets/fonts/sansation/SansationItalicWebfont.ttf new file mode 100755 index 0000000..64a0577 Binary files /dev/null and b/www/assets/fonts/sansation/SansationItalicWebfont.ttf differ diff --git a/www/assets/fonts/sansation/SansationItalicWebfont.woff b/www/assets/fonts/sansation/SansationItalicWebfont.woff new file mode 100755 index 0000000..6e14ff3 Binary files /dev/null and b/www/assets/fonts/sansation/SansationItalicWebfont.woff differ diff --git a/www/assets/fonts/sansation/SansationLightItalicWebfont.eot b/www/assets/fonts/sansation/SansationLightItalicWebfont.eot new file mode 100755 index 0000000..3dfb0f6 Binary files /dev/null and b/www/assets/fonts/sansation/SansationLightItalicWebfont.eot differ diff --git a/www/assets/fonts/sansation/SansationLightItalicWebfont.svg b/www/assets/fonts/sansation/SansationLightItalicWebfont.svg new file mode 100755 index 0000000..71b9fc5 --- /dev/null +++ b/www/assets/fonts/sansation/SansationLightItalicWebfont.svg @@ -0,0 +1,145 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : 2011 Bernd Montag +Designer : Bernd Montag + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/assets/fonts/sansation/SansationLightItalicWebfont.ttf b/www/assets/fonts/sansation/SansationLightItalicWebfont.ttf new file mode 100755 index 0000000..23a6135 Binary files /dev/null and b/www/assets/fonts/sansation/SansationLightItalicWebfont.ttf differ diff --git a/www/assets/fonts/sansation/SansationLightItalicWebfont.woff b/www/assets/fonts/sansation/SansationLightItalicWebfont.woff new file mode 100755 index 0000000..5e32f49 Binary files /dev/null and b/www/assets/fonts/sansation/SansationLightItalicWebfont.woff differ diff --git a/www/assets/fonts/sansation/SansationLightWebfont.eot b/www/assets/fonts/sansation/SansationLightWebfont.eot new file mode 100755 index 0000000..63f8928 Binary files /dev/null and b/www/assets/fonts/sansation/SansationLightWebfont.eot differ diff --git a/www/assets/fonts/sansation/SansationLightWebfont.svg b/www/assets/fonts/sansation/SansationLightWebfont.svg new file mode 100755 index 0000000..a51e4da --- /dev/null +++ b/www/assets/fonts/sansation/SansationLightWebfont.svg @@ -0,0 +1,145 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : 2011 Bernd Montag +Designer : Bernd Montag + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/assets/fonts/sansation/SansationLightWebfont.ttf b/www/assets/fonts/sansation/SansationLightWebfont.ttf new file mode 100755 index 0000000..1524764 Binary files /dev/null and b/www/assets/fonts/sansation/SansationLightWebfont.ttf differ diff --git a/www/assets/fonts/sansation/SansationLightWebfont.woff b/www/assets/fonts/sansation/SansationLightWebfont.woff new file mode 100755 index 0000000..9182f42 Binary files /dev/null and b/www/assets/fonts/sansation/SansationLightWebfont.woff differ diff --git a/www/assets/fonts/sansation/SansationRegularWebfont.eot b/www/assets/fonts/sansation/SansationRegularWebfont.eot new file mode 100755 index 0000000..9fb0542 Binary files /dev/null and b/www/assets/fonts/sansation/SansationRegularWebfont.eot differ diff --git a/www/assets/fonts/sansation/SansationRegularWebfont.svg b/www/assets/fonts/sansation/SansationRegularWebfont.svg new file mode 100755 index 0000000..953c1d6 --- /dev/null +++ b/www/assets/fonts/sansation/SansationRegularWebfont.svg @@ -0,0 +1,145 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : 2011 Bernd Montag +Designer : Bernd Montag + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/assets/fonts/sansation/SansationRegularWebfont.ttf b/www/assets/fonts/sansation/SansationRegularWebfont.ttf new file mode 100755 index 0000000..341fadc Binary files /dev/null and b/www/assets/fonts/sansation/SansationRegularWebfont.ttf differ diff --git a/www/assets/fonts/sansation/SansationRegularWebfont.woff b/www/assets/fonts/sansation/SansationRegularWebfont.woff new file mode 100755 index 0000000..ebbd682 Binary files /dev/null and b/www/assets/fonts/sansation/SansationRegularWebfont.woff differ diff --git a/www/assets/fonts/sansation/demo.html b/www/assets/fonts/sansation/demo.html new file mode 100755 index 0000000..04fc689 --- /dev/null +++ b/www/assets/fonts/sansation/demo.html @@ -0,0 +1,58 @@ + + + + + + + Font Face Demo + + + + + +
+

Font-face Demo for the Sansation Font

+ + + +

Sansation Regular - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+ + + +

Sansation Light - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+ + + +

Sansation Bold - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+ + + +

Sansation Light Light Italic - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+ + + +

Sansation Italic - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+ + + +

Sansation Bold Italic - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+ +
+ + diff --git a/www/assets/fonts/sansation/license.txt b/www/assets/fonts/sansation/license.txt new file mode 100755 index 0000000..a0399e1 --- /dev/null +++ b/www/assets/fonts/sansation/license.txt @@ -0,0 +1,18 @@ +Sansation - freeware font family +Version 1.3 +Bernd Montag © 2011 - All Rights Reserved + +This font family is freeware and can be used for personal and commercial purposes. +Although a PayPal donation is much appreciated. + +You may but this font on CDs, websites,... with the following restrictions: + + -Editing is only allowed for personal use, don´t distribute an modiefied version of the font files! + -Do not rename the font files! + -Do not sell the font files! + -Do not pass the font files without this textfile! + -Make sure you have downloaded the latest update from www.dafont.com for best optical results. + +If you have further questions - please contact me. + +berndmontag@gmx.de \ No newline at end of file diff --git a/www/assets/fonts/sansation/stylesheet.css b/www/assets/fonts/sansation/stylesheet.css new file mode 100755 index 0000000..50085a7 --- /dev/null +++ b/www/assets/fonts/sansation/stylesheet.css @@ -0,0 +1,76 @@ +/* Generated by Font Squirrel (http://www.fontsquirrel.com) on May 11, 2012 12:44:10 PM America/New_York */ + + + +@font-face { + font-family: 'SansationRegular'; + src: url('SansationRegularWebfont.eot'); + src: url('SansationRegularWebfont.eot?#iefix') format('embedded-opentype'), + url('SansationRegularWebfont.woff') format('woff'), + url('SansationRegularWebfont.ttf') format('truetype'), + url('SansationRegularWebfont.svg#SansationRegular') format('svg'); + font-weight: normal; + font-style: normal; + +} + +@font-face { + font-family: 'SansationLight'; + src: url('SansationLightWebfont.eot'); + src: url('SansationLightWebfont.eot?#iefix') format('embedded-opentype'), + url('SansationLightWebfont.woff') format('woff'), + url('SansationLightWebfont.ttf') format('truetype'), + url('SansationLightWebfont.svg#SansationLight') format('svg'); + font-weight: normal; + font-style: normal; + +} + +@font-face { + font-family: 'SansationBold'; + src: url('SansationBoldWebfont.eot'); + src: url('SansationBoldWebfont.eot?#iefix') format('embedded-opentype'), + url('SansationBoldWebfont.woff') format('woff'), + url('SansationBoldWebfont.ttf') format('truetype'), + url('SansationBoldWebfont.svg#SansationBold') format('svg'); + font-weight: normal; + font-style: normal; + +} + +@font-face { + font-family: 'SansationLightLightItalic'; + src: url('SansationLightItalicWebfont.eot'); + src: url('SansationLightItalicWebfont.eot?#iefix') format('embedded-opentype'), + url('SansationLightItalicWebfont.woff') format('woff'), + url('SansationLightItalicWebfont.ttf') format('truetype'), + url('SansationLightItalicWebfont.svg#SansationLightLightItalic') format('svg'); + font-weight: normal; + font-style: normal; + +} + +@font-face { + font-family: 'SansationItalic'; + src: url('SansationItalicWebfont.eot'); + src: url('SansationItalicWebfont.eot?#iefix') format('embedded-opentype'), + url('SansationItalicWebfont.woff') format('woff'), + url('SansationItalicWebfont.ttf') format('truetype'), + url('SansationItalicWebfont.svg#SansationItalic') format('svg'); + font-weight: normal; + font-style: normal; + +} + +@font-face { + font-family: 'SansationBoldItalic'; + src: url('SansationBoldItalicWebfont.eot'); + src: url('SansationBoldItalicWebfont.eot?#iefix') format('embedded-opentype'), + url('SansationBoldItalicWebfont.woff') format('woff'), + url('SansationBoldItalicWebfont.ttf') format('truetype'), + url('SansationBoldItalicWebfont.svg#SansationBoldItalic') format('svg'); + font-weight: normal; + font-style: normal; + +} + diff --git a/www/assets/graphics/backArrow.png b/www/assets/graphics/backArrow.png new file mode 100644 index 0000000..78f625e Binary files /dev/null and b/www/assets/graphics/backArrow.png differ diff --git a/www/assets/graphics/bread.png b/www/assets/graphics/bread.png new file mode 100644 index 0000000..5738092 Binary files /dev/null and b/www/assets/graphics/bread.png differ diff --git a/www/assets/graphics/calculator.svg b/www/assets/graphics/calculator.svg new file mode 100755 index 0000000..05d9df4 --- /dev/null +++ b/www/assets/graphics/calculator.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/www/assets/graphics/info.png b/www/assets/graphics/info.png new file mode 100644 index 0000000..2c62631 Binary files /dev/null and b/www/assets/graphics/info.png differ diff --git a/www/assets/graphics/moreDisclosure.png b/www/assets/graphics/moreDisclosure.png new file mode 100644 index 0000000..d9d91b2 Binary files /dev/null and b/www/assets/graphics/moreDisclosure.png differ diff --git a/www/assets/graphics/notebook.svg b/www/assets/graphics/notebook.svg new file mode 100755 index 0000000..c4d784a --- /dev/null +++ b/www/assets/graphics/notebook.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/www/assets/graphics/search.png b/www/assets/graphics/search.png new file mode 100644 index 0000000..5c83ac8 Binary files /dev/null and b/www/assets/graphics/search.png differ diff --git a/www/assets/graphics/settings.svg b/www/assets/graphics/settings.svg new file mode 100755 index 0000000..248d1b8 --- /dev/null +++ b/www/assets/graphics/settings.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/www/assets/graphics/wheatBg.png b/www/assets/graphics/wheatBg.png new file mode 100644 index 0000000..ad2aab2 Binary files /dev/null and b/www/assets/graphics/wheatBg.png differ diff --git a/www/assets/graphics/wheatBgNoColor.png b/www/assets/graphics/wheatBgNoColor.png new file mode 100644 index 0000000..88524b7 Binary files /dev/null and b/www/assets/graphics/wheatBgNoColor.png differ diff --git a/www/assets/styles.css b/www/assets/styles.css new file mode 100755 index 0000000..a3455c5 --- /dev/null +++ b/www/assets/styles.css @@ -0,0 +1,402 @@ + + + +* { +-webkit-touch-callout: none; +-webkit-user-select: none; +} + +input, +textarea { + -webkit-touch-callout: auto; + -webkit-user-select: auto; +} + +body { + position:absolute; + top:0px; + bottom:0px; + left:0px; + right:0px; + overflow: hidden; + padding: 0px; + margin: 0px; + background-color:#555; +} +* { + font-family:'SansationRegular', Arial, sans-serif; + letter-spacing: 0; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + + + +.subtext { + font-size:0.85em; + font-color: #888; +} + +.data-list { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + overflow: hidden; + position:relative; + background-color: #EDEDED; + min-height:100%; + + + backface-visibility: hidden; + -webkit-backface-visibility: hidden; +} + +.data-list ul, +.data-list li { + padding:0; + margin:0; + border:none; +} + + +.data-list ul { + display:block; + width:100%; + width:100%; + max-width:100%; +} + +.data-list li { + cursor:pointer; + font-size:1em; + padding:1em; + padding-left:1em; + padding-right:1px; + display:block; + border-top:1px solid #fff; + border-bottom:1px solid #CCC; + + background-image:url('graphics/moreDisclosure.png'); + background-position:right center; + background-repeat:no-repeat; +} + +.listSelected { + color:#333; + border-top:1px solid #094C99; + background-color: #D9D900; +} + + +/*ViewNavigator Styles*/ + +.viewNavigator_header { + background:#444; + color:#444; +} + +.viewNavigator_header_title { + color: white; + font-size:1.5em; + max-width:65%; +} + +.viewNavigator_backButton { + position:absolute; + top:5px; + left:5px; + width:40px; + color: rgba(0,0,0,0); + height:35px; + box-shadow: 0 0 0 0; + background: #DEDEDE; + border:1px solid #999; + padding:0px; + border-radius:0px; + background-image:url('graphics/backArrow.png'); + background-position: 3px center; + background-repeat:no-repeat; +} + +@media only screen and (min-width:760px) { + .viewNavigator_backButton { + text-align:right; + vertical-align:middle; + padding-right:10px; + padding-left:50px; + padding-top:9px; + height:26px; + color: #444; + } +} + +.viewNavigator_backButton:active { + background-color: #D9D900; +} + +.viewNavigator_content { + border-top:1px solid #999; + background:#999; + color:#444; +} + +.viewNavigator_contentHolder { + color:#444; + background:#999; + border-left:1px solid #999; + border-right:1px solid #999; +} + +.viewNavigator_contentHolder > div:first-child { + min-height:100%; + background:#EDEDED; + /*background-image:url('graphics/wheatBg.png'); + background-position: top left; + background-repeat:repeat;*/ + border-bottom:1px solid #444; + border-top:1px solid #444; +} + + +/*APPLICATION VIEWS*/ + +.right { + position:absolute; + right:0.75em; + top:0.5em; +} + +.padded { + padding:1em; +} + +.button { + padding:.5em; + cursor:pointer; + border:1px solid #999; + background-color: #AAA; + color: white; + text-decoration:none; +} + +.button:active { + background-color: #D9D900; +} + +.heading { + background-color: #fff; + color:#444; + border-bottom:1px solid #999; + backface-visibility: hidden; + -webkit-backface-visibility: hidden; + -webkit-transform:translate3d(0,0,0); +} + +.warning { + background-color: #F2DEDE; + color:#B94A48; + border:1px solid #EED3D7; +} + +#defaultView { + background-image:url('graphics/wheatBgNoColor.png'); + background-position: bottom center; + background-repeat:no-repeat; +} + + + +@media only screen and (min-width:760px) { + #defaultView { + background-image:url('graphics/wheatBg.png'); + } +} + +#aboutView h2, +#defaultView h2 { + display:block; + padding:0em; + text-align:center; +} +#aboutView div, +#defaultView div { + display:block; + padding:1em; + padding-top:0em; +} + +#defaultView a { + height:100%; + display:block; + border:1px solid #999; + padding:1.25em; + text-decoration: none; + color:#444; + font-size:1em; + background:rgba(230,230,230,0.85); +} + +#defaultView a:active { + background-color:#D9D900; +} + +#defaultView #points { + padding-left:75px; + background-image:url('graphics/notebook.svg'); + background-size:45px 45px; + background-position: 15px center; + background-repeat:no-repeat; +} + +#defaultView #search { + padding-left:75px; + background-image:url('graphics/search.png'); + background-position: 5px center; + background-repeat:no-repeat; +} + +#defaultView #calculate { + padding-left:75px; + background-image:url('graphics/bread.png'); + background-size:45px 45px; + background-position: 5px center; + background-repeat:no-repeat; +} + +#defaultView #calculateAllowance { + padding-left:75px; + background-image:url('graphics/calculator.svg'); + background-size:45px 45px; + background-position: 5px center; + background-repeat:no-repeat; +} + +#defaultView #settings { + padding-left:75px; + background-image:url('graphics/settings.svg'); + background-size:45px 45px; + background-position: 5px center; + background-repeat:no-repeat; +} + +#defaultView #about { + padding-left:75px; + background-image:url('graphics/info.png'); + background-position: 10px center; + background-repeat:no-repeat; +} + +#aboutView { + padding:1em; + padding-top:0em; + + backface-visibility: hidden; + -webkit-backface-visibility: hidden; + + transform: translate3d(0,0,0); + -webkit-transform: translate3d(0,0,0); +} + +#searchView { + padding:1.25em; +} + +#foodDetailsView { + padding:1.0em; +} + + +#foodDetailsView h2 { + padding:0em; + margin:0em; +} + +.paragraph { + margin:0px; + margin-bottom:1em; + border-top:1px solid #CCC; + padding-top:1em; +} + +.paragraph_noborder { + margin:0px; + margin-bottom:1em; + border: none; + padding-top:1em; +} + +.amenities { + min-height:30px; + font-size: 1.25em; + padding-top:0.25em; + padding-left:62px; + background-repeat:no-repeat; +} + +#foodMapView { + width:100%; + height:100%; + position:absolute; +} + +#foodMapView #foodMapContainer{ + top:0px; + bottom:0px; + left:0px; + right:0px; + position:absolute; +} + +#foodMapView #footer{ + top:0px; + height:18px; + right:0px; + position:absolute; + padding:1em; + padding-right:0.5em; + z-index:99; +} + +#search_state { + font-size:1.25em; + width:100%; +} + + +#search_searchPhrase { + width:96%; + font-size:1.25em; +} + +#searchButton { + padding-left:2em; + padding-right:2em; +} + +input[type='checkbox'] { + width:2em; + height:2em; +} + +label { + font-size: .8em; + padding:.25em; +} + +.searchfilter{ + padding:.25em; +} + +.searchfilter .amenities { + font-size: 1em; +} + +#geoError{ + padding:1.25em; +} +#geoError div { + padding:1.25em; + padding-top:0px; +} \ No newline at end of file diff --git a/www/config.xml b/www/config.xml new file mode 100644 index 0000000..2eeb8df --- /dev/null +++ b/www/config.xml @@ -0,0 +1,119 @@ + + + + + + Points Watcher + + + Points Watcher is the easiest way to keep track of your Weight Watcher's Points Plus system. + + + + Travis Burtrum (moparisthebest) + + + + Copyright (C) 2013 Travis Burtrum (moparisthebest) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/www/icon.png b/www/icon.png new file mode 100644 index 0000000..cdd7c37 Binary files /dev/null and b/www/icon.png differ diff --git a/www/index.html b/www/index.html new file mode 100644 index 0000000..1cc3b4e --- /dev/null +++ b/www/index.html @@ -0,0 +1,30 @@ + + + + + Points Watcher + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/www/js/application.js b/www/js/application.js new file mode 100644 index 0000000..02de45b --- /dev/null +++ b/www/js/application.js @@ -0,0 +1,298 @@ +/*HTMLElement.prototype.originalRemoveEventListener + = HTMLElement.prototype.removeEventListener; + + HTMLElement.prototype.removeEventListener = function(type, listener, useCapture) + { + console.log('remove: ' + type); + this.originalRemoveEventListener(type, listener, useCapture); + }; + */ + +var maxSearchLength = 50; + +var weeklyPointsAllowed = 49; + +var values = []; +var database; +var viewAssembler = new ViewAssembler(); +var backButtonLabel = " "; + +$(document).ready(function () { + loadTemplates(setupDefaultView); +}); + +function setupDefaultView() { + var bodyView = viewAssembler.defaultView(); + + //Setup the default view + var defaultView = { title: "Welcome!", + view: bodyView + }; + + //Setup the ViewNavigator + window.viewNavigator = new ViewNavigator('body'); + window.viewNavigator.pushView(defaultView); + + backButtonLabel = (isTablet() ? "Back" : " "); + database = window.localStorage; + + $.ajaxSetup({ + cache: true + }); + + $.getScript("values.js", scriptSuccess); +} + +function onNearbyListItemClick(event) { + + $("li").removeClass("listSelected"); + var target = $(event.target) + if (target.get(0).nodeName.toUpperCase() != "LI") { + target = target.parent(); + } + + target.addClass("listSelected"); + var index = target.attr("index"); + index = parseInt(index); + + database.setItem("amount", values[index][3]); + + showPointsPage(true); +} + +function scriptSuccess(data, textStatus, jqXHR) { + + //for (var i = 0; i < values.length; i++) { + // values[i].push(i.toString()); + //} + //console.log( "scriptSuccess: " + values.length ); +} + +function pushPointsPage() { + showPointsPage(true); +} + +function showPointsPage(push) { + var view = { title: "My Points", + backLabel: backButtonLabel, + view: viewAssembler.pointsView() + }; + if(push == undefined || !push) + window.viewNavigator.replaceView(view); + else + window.viewNavigator.pushView(view); +} + +function onSearchButtonClick(event) { + var $input = $("#search_searchPhrase"); + var searchPhrase = $input.val(); + + if (searchPhrase != undefined && searchPhrase.length > 0) { + var values = filterValuesBySearchCriteria(searchPhrase); + var view = { title: "Search Results", + backLabel: backButtonLabel, + view: viewAssembler.searchResultsView(values, searchPhrase) + }; + window.viewNavigator.pushView(view); + } +} + +function filterValuesBySearchCriteria(searchPhrase) { + var result = []; + //var startTime = new Date().getTime(); + var tokens = searchPhrase.toLowerCase().split(" "); + var regexps = new Array(tokens.length); + for (var x = 0; x < regexps.length; ++x) + regexps[x] = new RegExp(tokens[x]); + var numFound = 0; + for (var y = 0; y < values.length; ++y) { + var found = true; + for (var z = 0; z < regexps.length; ++z) { + if (!regexps[z].test(values[y][0])) { + found = false; + break; + } + } + if (found) { + result.push(y); + if (++numFound == maxSearchLength) + break; + } + } + //console.log( new Date().getTime() - startTime ); + return result; +} + +function isNumber(n) { + return !isNaN(parseFloat(n)) && isFinite(n); +} + +function isPositiveNumber(n) { + return isNumber(n) && n > 0; +} + +function roundPoints(points){ + return Math.round(points * 10) / 10; +} + +function onCalcPointsButtonClick(event) { + var protein = $("#calcProtein").val(); + var carbs = $("#calcCarbs").val(); + var fat = $("#calcFat").val(); + var fiber = $("#calcFiber").val(); + + if (isPositiveNumber(protein) && isPositiveNumber(carbs) && isPositiveNumber(fat) && isPositiveNumber(fiber)) { + var amount = calcPointsPlusFood(protein, carbs, fat, fiber); + database.setItem("amount", amount); + database.setItem("calcPointsAmount", amount); + database.setItem("protein", protein); + database.setItem("carbs", carbs); + database.setItem("fat", fat); + database.setItem("fiber", fiber); + var view = { title: "Calculate Points", + backLabel: backButtonLabel, + view: viewAssembler.calcPointsView() + }; + window.viewNavigator.replaceView(view); + } +} + +function calcPointsPlusFood(protein, carbs, fat, fiber) { + var points = (protein / 10.9375) + (carbs / 9.2105) + (fat / 3.8889) - (fiber / 12.5); + return roundPoints(points); +} + +function onCalcAllowanceButtonClick(event) { + var weight = $("#calcWeight").val(); + var height = $("#calcHeight").val(); + var age = $("#calcAge").val(); + var maleNotFemale = "male" == $("#calcGender").val(); + var poundsNotKg = "pounds" == $("#calcWeightType").val(); + var inchNotMeters = "inches" == $("#calcHeightType").val(); + + if (isPositiveNumber(weight) && isPositiveNumber(height) && isPositiveNumber(age)) { + var allowance = calcPointsPlusAllowance(weight, height, age, maleNotFemale, poundsNotKg, inchNotMeters); + database.setItem("allowance", allowance); + database.setItem("weight", weight); + database.setItem("height", height); + database.setItem("age", age); + database.setItem("maleNotFemale", maleNotFemale); + + var view = { title: "Calculate Allowance", + backLabel: backButtonLabel, + view: viewAssembler.calcAllowanceView(allowance, weight, height, age, maleNotFemale, poundsNotKg, inchNotMeters) + }; + window.viewNavigator.replaceView(view); + } +} + +function calcPointsPlusAllowance(weight, height, age, maleNotFemale, poundsNotKg, inchNotMeters) { + var wmult = poundsNotKg ? .454 : 1; + var hmult = inchNotMeters ? .0254 : 1; + + var base1, age1, activity, wgt1, ht1; + if (maleNotFemale) { + base1 = 864; + age1 = 9.72; + activity = 1.12; + wgt1 = 14.2; + ht1 = 503; + } else { + base1 = 387; + age1 = 7.31; + activity = 1.14; + wgt1 = 10.9; + ht1 = 660.7; + } + + var totage = Math.round((age1 * age) * 100) / 100; + var totwgt = Math.round(((wmult * weight) * wgt1) * 100) / 100; + var totht = Math.round(((hmult * height) * ht1) * 100) / 100; + var tee1 = Math.round((activity * (totwgt + totht)) * 100) / 100; + var tee2 = Math.round((base1 - totage + tee1) * 100) / 100; + var atee1 = tee2 - (tee2 * .10) + 200; + var target1 = (atee1 - 1000) / 35; + var modtar = Math.round(target1 - 11); + + if (modtar <= 26) + modtar = 26; + else if (modtar >= 71) + modtar = 71; + + return modtar; +} + +function onSubtractPointsButtonClick(event) { + var amount = $("#pointSubtract").val(); + var dailyNotWeekly = "daily" == $("#pointType").val(); + + if (isNumber(amount)) { + var keyName = dailyNotWeekly ? "dailyPoints" : "weeklyPointsAllowed"; + var points = database.getItem(keyName); + points -= amount; + database.setItem(keyName, roundPoints(points)); + showPointsPage(); + } +} + +function onResetPointsButtonClick(dailyNotWeekly) { + var keyName = dailyNotWeekly ? "dailyPoints" : "weeklyPointsAllowed"; + var points = dailyNotWeekly ? dbGet("allowance", 0) : weeklyPointsAllowed; + database.setItem(keyName, points); + showPointsPage(); +} + +function arrayToFoodObject(index) { + var result = {}; + + var row = values[index]; + + result.name = row[1]; + result.amount = row[2]; + result.points = row[3]; + + result.index = index; + + return result; +} + +function openExternalURL(url) { + var result = confirm("You will leave the Points Watcher App. Continue?"); + if (result == true) { + window.open(url, '_blank'); + } +} + + +function dbGetNum(key) { + var ret = dbGet(key, 0); + return ret < 1 ? undefined : ret; +} + +function dbGet(key, defaultVal) { + var ret = database.getItem(key); + if (ret == undefined) { + ret = defaultVal; + database.setItem(key, ret); + } + return ret; +} + +document.addEventListener("deviceready", onDeviceReady, false); + +function onDeviceReady() { + document.addEventListener("backbutton", onBackKey, false); +} + +function onBackKey(event) { + if (window.viewNavigator.history.length > 1) { + event.preventDefault(); + window.viewNavigator.popView(); + return false; + } + navigator.app.exitApp(); +} + +document.addEventListener('touchmove', function (e) { + e.preventDefault(); +}, false); \ No newline at end of file diff --git a/www/js/libs/css/activityIndicator.css b/www/js/libs/css/activityIndicator.css new file mode 100644 index 0000000..ae17c11 --- /dev/null +++ b/www/js/libs/css/activityIndicator.css @@ -0,0 +1,15 @@ +.activityIndicator { + height: 40px; + width: 40px; + -webkit-background-size: 40px 40px; + margin: 0px auto; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAATEAAAEwCAYAAADfOUbNAAAgAElEQVR4nO3de3SU1bkw8Od999ySkISbBKGC/fpZdNV6rIbqkUO+5YFKQsByXGdCKwFCAwERUuBUJdVlF6v4AUuLJVxqAjECQcvg8tBTgaDYrtJDP672stpa6vIoFBCR2yTkMjPv5ftjMiCQmcxlX995fmu5RMnsvWfmzTPv3vM8ewMghJDCNNEDQM7i9/vJV77yldvy8/Onm6Y5HwCAELKhvb1960cfffSPHTt2mKLHiJwFgxiiYtGiRbcWFRWdSeZnP/vss2E//elPP2U9JpQdMIihjCxcuLBg2LBhwXQee+bMmcK1a9e20R4Tyi666AEgdT3//PMT0g1gAADDhg0LPv/88xNojgllHwxiKC0vvPDCUzk5Oa2ZtpOTk9P6wgsvPEVjTCg7EdEDQOp5/vnnJ3g8ns202tM07Vtjxow5+Jvf/OYjWm2i7IFrYiglmayB9QXXyFA6cDqJUsIqgLFuGzkXBjGUtEWLFt3qhD6Qs2AQQ0lLNg9M9j6Qs2AQQ0nx+/3cvgTi2RdSHwYxlJRRo0aNcGJfSH0YxFBSfD5fjRP7QurDIIaSQghZ6sS+kPowiCGElIZBDCGkNAxiCCGlYRBDCCkNgxhCSGku0QNQVX19fYFlWVPdbndjvJ8xDKO2s7Ozpa6u7hLPsSE5LF26dIBpmpW6rtcn+LGaU6dObd+2bRsWvqcJd7FIUUNDQ6FhGJdTfVwoFLp7yZIlf2ExJh5WrFhh8+yvrq5O2Wtz8eLFX/N4PH9O46H9V61ahUXwKcLpZArWrFmzMJ0ABgDg9Xr/vH79eru+vt5Le1xIDmVlZd5nnnnGTjOAAQBcfuqppxZSHVQWwCCWBNu2tfXr19sulyvRtCAphJDuDRs2DKAxLiSPFStWDLjnnnu6M21H1/X6Z555xrZtW9k7Ud4wiCVhw4YNFs32bNu+iHdkzlFWVua9fPnyRZptLl26lOo152QYxPqwZs0aJrf3hJCMP7WRHGjcgfUGp5bJwSCWQENDQyGNKWQ8L7744j+zahvxsWjRImbvYc/UspBV+06BQSyBdBfxk5Wbm/s73DtLXX6/n3i93t8x7obpNegEGMTiqK+vL+DRT0lJSROPfhB9I0aM4PLeLVy4kMu1qCoMYnFYljWVRz+6rs9ct27dIB59IXrq6uoGuVyumTz6ys3N5XItqgqDWByJMvFp0zTtPK++EB2WZfF8z7hdiyrCICaJ1atXjxU9BpScuro6fK8kgkFMEl6vd38gEMBFfsn5/X5iWdZ+0eNA12AQk8jZs2c3iB4DSmzkyJH4HkkGg5hECCE1uMgvr7q6ukGEEDzERDIYxCSDi/zy4ryYj5KEQUxCTU1NxaLHgK73ox/9CN8TSWEQi8MwjFpRfXd3dx8B3OtNJlrPeyKEZVnCrkUVYBCLwzTNbSL7X7NmTZnI/tE1dXV1Qt8LwzCEXouywyAWx5IlS6hurZIql8u1C1MuxOtJqdglcgwvv/yy0GtRdhjEEiCE3Cuy/88++wzrKgXjVR8Zj8fjEXoNqgCDWALz5s37o8j+sa5SLJ71kfH8+Mc/FnoNqgCDWB9s2x4ssn9MuRBHdEqFrutCrz1VYBDrw4IFCy5YlrVZ5Bgw5YK/Z599VuhrbhjG5hUrVlwQOQZVYBBLQlFRUbXI/jHlgjvNMAxhKRUAACdPnhR6zakEg1gSKioqTMMwykWOAVMu+FmyZInQ11rX9fIdO3aYIsegEgxiSfr+97+/R2T/mHLBh9/vJ263W2hKxYoVK4Rea6rBIJY82+fzjRY5AEy5YE90SoXL5RoNAFxPW1cdBrEUVFdXHxXZP6ZcsCVDSsULL7wg9BpTEQaxFGHKhXNhSoWaMIilaMGCBRdM0xS65/natWsx5YIy0SkVpmk2YkpFejCIpWHo0KHzRfav6zqmXNAlPKXixIkTQq8plWEQS0NFRYUZCoVKRI4BUy7okSClogRTKtKHQSxNS5Ys+a3I/jHlgg5JUiqEXkuqwyCWAdGL/JhykTnRKRW4mJ85DGIZEF1XiSkXmRGdUoH1kXRgEMuQ6LpKTLlIn+iUCqyPpAODWIZkqKvE08NTJ/oU70gkgvWRlGAQo0B0XSWeHp4aGU7xXr16NdZHUoJBjA7bsiyhdZV4enjyRJ/ijfWRdGEQo2ThwoVCa97w9PDkyHCKN9ZH0oVBjCLRKRe4yN830Yv5mFJBHwYxikSnXADgVtaJiK6PxJQKNjCIUSY65QK3so5LeH0kplSwgUGMMhlSLrCu8maiT/HGlAp2MIgxIDrlAusqryfDKd6YUsEOBjE2cCtriYiuj8SUCrYwiDGCW1nLQXR9JACmVLCGQYwhTLkQD1MqnA+DGEMypFw0NDTcJ7J/kX74wx8Kfe6YUsGHi3eHLS0tBd3d3VMJIXH3qbcsq9bn87VMmzbtEs+xsVBUVFT9+eefi9zu5RhEP6yybU1GM03zmMgBOCWl4oknnhjQ1dVVSQipj/czpmnWRCKR7du2bWvjOTYAjvlEDQ0NhR6P53Kqj3O5XPdOnz79jyzGxMuaNWsmulwuYd+OhUKhkkx3ol2+fPkKQshSWmNKxDTNlc8991xdJm0sXrx4rMfjEVbkret6+YoVK3aL6p+G733ve/+kadofUn0cIaR/Y2NjkMWYesNlOtnU1LQwnQAGAGAYxh+am5ttlRepRadceL3e/ZDhB1Z3dze3E54o9KWJDGAAap/iPWPGjEHV1dV2OgEMAMA0zctVVVULaY8rHqZBzLZtrbm52dZ1Pe5taLLy8vLOv/rqq68pmv8kPOXixRdffDCTxx8/fvwkrbGw7mvRokUZPddM9bzXyk3f/X4/qaqqes3tdmf8ZQghpL66utoGDrM9pkHstddes2i2p2nazI6ODmPjxo0TQbHSGtEpF7m5ub/L5PE8s80z7cvr9Wb0XDO1bNky1VIqtOnTp08sKCgwCCFU12+rq6upxoDeMAtiTU1NzG4nXS7XrubmZmvLli1KFTuLTrlYvXr1wEweb1nWUFpjYdWH3+/P6DlmSrWUisWLFxdXV1dbHo+H2Zot66klkyDW0NBQSGMK2RfTNI+otF4m+vRwQsi0TB7/7LPPfkZrLKz6uP322zN6jplQ6RTvurq6QdXV1XZbWxvzonhCSH1NTU0hq/aZBLF0F/HTlZeXd37Tpk0NKqyXiTw93OVy0Vib9NEYC6u2eXx4xqPCKd5+v5/MmjWr4dy5c1yTgE3TZBYTqAexlpaWAtptJoMQUtPR0WE0NzdLfWiGDKeHZ6K2tjbk8/mG0W7X5/MNq62tDdFulxcVTvGePXv22IKCAkPXdSE7206bNo1JbKAexLq7u6fSbjNF+2WfYoo+PTxTixcv/pRmIPP5fMMWL178Ka32RJD5FO9YyoRt20LTTtxuN5PYQD2IJcrE50n2lAzRi/yZWrx48ac0pn95eXk+1QOYrIv5NFMmaGAVGxxdOxlLyXjllVekS8mQoa4yU7W1taG6ujotnW8ULcsaWldXp6k8hQSQtj5Se/zxx5mkTMiIe+2kCF6vd1dzczMQQkbPmDFDmhwe0XWVtPR8o6j5/X4yatSoET6fr+bGEiXTNFd2d3c3Hj9+/KTsa0epkK0+csGCBcVdXV1Ct+HmLSuCWExPSgZ0dHQMXrBggfBPz4qKCnPNmjXlIusqaeoJTh8DQF3PP44m05bTM2bMGOR2u893dXWJHgp3jp5OxiPTehnPuspIJCL0vEVOuD1HGbaclm3dS4SsDGIAUpUw2QDwDR4d6bq+nUc/Ip06dYrLcySEfAPE1kcyKxVSDfVf3ubmZuUKXwFA+HrZ+vXrmb9uTz75pFRfbrDyzDPPMH8tV61aJey1VHndq6mpifrrRn1NzLKsWpFZ0+kSvV527ty5nCFDhjBb0Ghvb+/Pqm0J9QcAZhniPp8vh1Xbiai+7mWaZi2LdqlPJ23b3ka7TZ5ErZctW7asOxQKfYlF24Zh1C5dupTbJnWirVq1KmhZFpNfmGAw+KVly5Z1s2g7Hqese3V0dDCJDUxuiVWdUt7IMIzyOXPm7AGOax9r1669U9f1D2i2mS3TyBvRnlYahnHXT37yk7/RbLMP2vTp08tY7jDBE4upJACjhf2Ojo67WbTLW2zLnzfeeIPblj8LFy78m23bo2i1N3/+/Kz98mbVqlXUnvuVK1dG8QxgPLbI4ckwDGYxgdkntFPuxr6I53rZz372syGWZaW9LY1pmpW1tbVKT+1pefrpp6dpmtaS7uNN0yx66aWXztEcUzx1dXWDeO8wwQOruzAAhkGsvr7em5+fz3XtgAfTNBsLCgrmV1RUME9yDAQC5NNPP13ucrmSPqAjEom8uXfv3so9e/YoXc5DW1lZmffrX/96i6Zp/57sYwzDWHny5MnneCS0+v1+0q9fvw2idphg6cyZMz6W1yPTtZJt27YNCIfDF1n2IVDJrFmzeO1coL/00ku3eTye2YSQ5278S9M0l4fD4U0/+MEP/gEAzLcDVpz+5JNP3pabmztb1/WbXkvLspZ3dnZuWr9+PbfXcvbs2WNF7zDByi233DJw5cqVTI9eZL7g69Q7shhZSpiQemIpE6LHwQrrO7AYbt9aNTY2PuR2uw/w6o8n27Y39+vXr5rHFBOpz+/3k7y8vCanZtp3dHSM+fnPf87tsBauX70HAgHS1ta2gRDiuHk/AEAoFCqfN28e15QMpBTt8ccfL8vJyXHEN443siyr8cqVK/N5F8ULyR9at27doLy8PMfeRkcikW/U1NSkdfAocqY5c+bca1nW70WPg5VIJDJ4y5YtQpZVhCZB9uyH78gFTQCATz75JId3djeSS1VVlY8QomadUBI0TSvZtGmT0K25hWdyO32Kqev6l2bOnHla9DgQf36/f3hBQcEp0eNgQdTUsTfCg1iMk6eY4XD4rrlz5/IsV0GCVVVV3UkIoVo+JoshQ4YMlmlLbmmCWMwbb7xR3N3dreQ2I4l0dHSMWrBgwd9FjwOxN2PGjK+63e7josdBW0FBweiXX35Zmu3dY6QLYj20jRs3ljll2+aY7u7uoieeeIJL+QoSY/r06UM8Hg/zk9J5CofD5Vu3bpX2W3dZgxgARNfLrly50qRpmmPyafLy8lyYT+ZMfr+fFBQUGKLHQYtpmps7OjqqZVj3SkTqg0J6ftmr1q1b9x9OWS9rb29fDllwiEY2ysnJWS56DLSITJlIldR3YjfasmVLsWmayq+XzZo1iwDWODqNXl1dLfUdSzJycnJGr1u3Trp1r0SUCmI9lF8v6+jouH3BggUnRI8D0fPYY4+NHDBgwCeix5Eu2de9ElFxwzx7zpw5u/Py8ly2bSt5gnZOTs480WNAdPXr10/J99Q0zc1tbW2urVu37gYFAxiAmndi11E1v2zWrFnKv/bomurqauUCgErrXolIvbCfjJ5tcDSnrJchxJqK616JKB/EYnrOjNRfeeWVMq/Xq+x6GUKsdHV1lb/++utKrnslouKaWCL2vHnzlF4vQ4i22LrX66+/ruy6VyKOuRP7IifmlyGUDqeseyXiyCAWE1svk23LH8uyVooeA6IrEomsdLvdSR/owpoMW+Tw4rTpZK9mzZr127y8PJdpmo2ixwIA0NXV9YroMSC6rly5IsV7allWY1tbmytbAhiAA1IsUiVDSgZm7DuS8Ix92bbI4cXR08nexKaYorb8MU3zTcAA5kRWJBJ50+12J32uJS2ybpHDS9bdid2AewlTe3u7r7a2Fg+2daCysjLvsGHDuG1HrnKpEE1ZsSaWANcSJk3TKjGAOdeePXtCoVCoknU/TigVoinb78Suw3q9DEuNsgPLEqRsSJlIFf5S9eLVV1+9T9O0YzTbrKqq0jVNy/pPzSyhVVdXU133JITc39jY+D7NNp0Cg1h82saNG//F5XJllF9mWVZtdXX1WlqDQuqoqqpaSAipz6SNUChU0tLS8t+A08a4MIj1TWtqanpQ1/WUj2UPh8P9586dG2QxKKSGmpqaQtM0L6f6uEgk8tCWLVsOAgavPmEQS8Hq1asHFhYWTtN1Pe6nq2maNZ2dndtra2vbeI4Nya2srKygqKhoKiEkbsK1aZq1HR0d23bs2HGR59gQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIpbcXj9/uJ3+8fYRhGjcvlkuagUFYMw1jpcrkaAeBkz6niCHHh9/tJMBgcEQ6Ha7xer+N/10Kh0ErLshr3799/EgBS+l1LKog1NDTcOmDAgDNpjc5BgsHg0Dlz5nwmehzIub773e8WXbx48azocYh2/vz5YceOHfs0mZ9NGMRaWloKPB4P7kx6g7Nnz+Kxa4iqsrIyr2VZ3I57U8Xly5cLDx06lHCD0bhHtm3fvn0CBrDeDR06tHvr1q23ih4HcobKyspbMYD1rn///sGHH354QqKf6TWIBQKBpzRNa2UzLGfwer1nMJChTFVWVt76+eefZ/1STSIej6f14Ycffire3980ndy+ffsEDGDJw6klShdOIVMTDodLf/3rX++98f9fdyfW0tJSgAEsNUOHDsWLEKUFA1hqPB5Pa1lZWcGN/1+/4YdwDSwNGzduLBI9BqSWcePG4TWTBsuybopRV4NYQ0MDru+kqbCwMOu/EkepcblceM2k6f77778uVl0NYpgHlhm/309EjwEpA6+VDAwePPi6WKUDAAQCAXxRM+T3+0eIHgNSQ0lJCV4rGfriTYMOANDR0XGbuOE4g2EYNaLHgNSg6zpeKxlqb2+/GrN0AACfzzdd3HCcIRtqSREd2VALyVooFLoas3QAAELIfHHDQQih1Oi6fjVmxS07QgghFegAAKZpbhA9EIQQSpZlWVdjlg4A0N3dvVXccJzBMIyVoseA1BAKhfBayZDX670as3QAgLy8vH+IG44z9GyeiFCfLMvCayVD+fn5V2OWDgCAu5ZmbseOHSdFjwGpoWf3UpSBHTt2XI1ZVxf2L126NEzMcJzhiy8qQn3AayUD58+fvy5WXQ1ic+fOTWorWHSzYDA4VPQYkFoMw8BrJk03blt9XYpFOBwu5DscZ8B991Gq3nvvPbxm0qDr+k0x6rogVllZ2Wbbdim/Ianv7NmzPtFjQGrSdR2vnRSEw+HSPXv23LTf/k3JrlOnTt0LAE9zGZXiQqHQMNzVFaVrz549oVtuuQXXopMQDoef7m1XV4AEpx3hNtWJhUKhYdOnT8d1RJQx3Gc/sXjbUsfgkW1pwH31EW24337vkjmyDQ/PTQEenotYw8Nzo6gdnnsjv99P/H7/CMMwarJh6xnDMFb2ZOKfxIRgxJPf7yfBYHBEOByuyYate0Kh0ErLshp7EoHxdw0hhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIcZbSVjzZLhAIDPT5fNM0XauP9zOWadW0t7dvr6ysTLiRG8o6BQAwFQASHZxbCwDbAOAilxE5BAaxvmmBQODBnNyc36X6wK7Orv4VFRW4M252KwSAy2k87iEAOAgANt3hOA8Gsfi0t99++19ssPdn0oht2bWPPvroWlqDQkpZCABx79qTVAIA/w0YzOLCINaL1tbW+yJG5BjNNieVT9I1TcMLMTtoAGBRbvN+AHifcpuOgEHsCzZv3jxo4KCB51m1P3nSZHy9swOzD6vhw4cPPn369AVW7avopnMns1EgECC/+MUvXmMZwAAA3nrrrWks20dSYPoenz59+jwAvAYAhGU/Ksn2OwNt586dZcRFdvHq8OP/+RiPe3MuLwDwPHatHAD2QJavl7lED0CUXbt2FVu2dYR3vyNGjGgBAD/vfhEXLZz72wUAkJubO7qzs/Mo576lkXV3Yvv27RvU1d3FdNrYl8mTJhOgv/CLxNJB8FFj2bpeljVBLBAIEHeuZ4MLSI3oseiafnt5efkJ0eNAVI0EgE9EDwKiybTzIYvObsyKhf3W1taxObk5hgwBDAAgHA7PEz0GRJ0s72kNABgAMFb0QHhx9J0Y65SJTGC6hePIurg+GAAcPcV05MJ+IBAgXq+3SSf6TNFjQUiw8wCwGQCqwaFTTKdNJ7WdO3dOzMnNMTCAIXTVTIhOMSeCA2dfjrkT27lzZzFxEe4pEwgpJJYPORoAHJOSoXwQk3ndCyFJxT7sHbFepux0klepEAtGxFgpegyIOhXfU0eUMKkYxJRf9/J4PK+IHgOiTtX3VPn1MqUGvXPXzmJiq7/uhRn7jiQ8Y58S5dbLlLgT27x586Bfvv1L2wkBrGcqiQHMeSxQc0p5oyMAYA8fPnyQ6IEkS+o7MSfme3V1drkqKiqc8ImNbkYgOjVzCiXyy2QNYty3yOEhEo4UPfbYY+dEjwMxNQQAPhM9CMqk3vJHuiAmaosc1jqudIz6zne+83fR40BcfBUAjoseBG1f2PJHBwAP8N07LS5pgpgMW+Sw0t7Wftfjjz/+N9HjQFzdCQAfiB4EC9/85jcHHz58OJZf5gPBwUx4EJNpixwWujq7vlRRUXFa9DiQEMMB4JToQTDyn/n5+TXt7e3nIXpXBgAQhmhM4TrtFBrEWltbx0aMSEZHosns6JGjOcuWLZPilhsJ4wOALtGDYGgVACzt+bMLol9suCD6ZQCXYCYkiDm9VEjX9G+Ul5f/QfQ4kFTuBYDfix4EQ68BwA/gWhmTu+ffEdYdcw1iTp86moZZPmXKFGm/xUHCaQBQBtcKsZ3oNxCtAjgN0YNTIhCdZjLDLYjt3LnzIeIiB3j1x5NlWptDoVA15n+hJBEAaILoL7sT2QDwbwDwXxCdWuoAwOyEL+ZBrL6+3vvl//Vlx64LXbxwcfDMmTOV3wkACTEIokXYTmS7XK7/axjGMoiuk+UBwBUWHTENYm+//fYAG+yLLPsQxe1yl5SWlv6WU3f6rl27bnN5XLOJTp678S9Ny1xuhI1N5eXl/wAsaeqL/t57792Wl5c3m5BeXkvTXN7R0bFp3LhxPF/LsQDgyC+4dF1/7c4775y7ZcsWu7i42AUMvuRgFsScegdmgNkY6QzP5zF1DAQCJD8/f7nb417a909HmYb55vHjxyvxgN7r1dfXe0ePHt3icrn+PdnHRCKRladOnXqO0zIBAYANED3ow1E0TXvHtu1qiKabeKCPNTLbtnVN05L+AGEWxH759i8dt7id48sZPH78eC5Tx7feemtIQWFB+uUrNlSOHz9+G8UhKevw4cPTNE1L+2DbixcvFk2YMIFLudjw4cMHnT592nFTTF3X11mW9QwAdEI0YFP7YGASxFpbW78WMSJ/ZtG2CLqmjy4vL+e2Pcm+ffu+ChqdspVx/zpO1zTNcR8oybBtWzt69CiVKaFlWaMeeOABbmVjubm5xZ2dnU4qv7MIIXNM03wVAPpBdH2MSmIskyDmlLswESkTr+99884hrv5Uy1XGjxsvvDJDhCNHjlB93zRNu6u4uJhn+ZijUjJcLtenhmEMg2jqRRgo/V5R308sEAgMpN0mb5Zpbe7q7HJNmTJlN3AMYIFAYDjtAAYAsHfv3oW025TdoUOHqD9n27Y/eO+994bTbjdRlwCwG6JpCps59suEYRhFXq93AkTTLaid70E9iPl8vmm02+Tp4oWLg7/97W9X8c75am5u9g0cNJBJnR1xkfp33323kEXbMjp69Gihruv1LNouKCg41dzc7GPRdgImAFQNHz58MOd+adMjkcimsrIyL0Tvxq5j23ZaMwbqpx1pusbk4mHN1MzRU8qnCNuW97YRtzGtr9N07TJIUPDPg23bl1m2f/fdd3eBgNfy9OnTF3r6LYZrJxYpxbKsoUeOHInlx+lAIY1Fie2pWTINs3zypMm6yAD2zjvv3Mujn927dxfw6EckXs/x8OHDXN6zOGJ7epULHEO6XBcuXGiEaALsdR8E6X4BlbVBTNS6Vy80nehcCoPdbvdUHv2INHjwYC7PUdO036c7/aFE5fUyC6IBjMpRccofnpsOmUqF9uzZU8arL03XGgFgI6/+RNA0rZFXX4cOHSqDaCARyQSAKgD4D1CnhOnLEN3lgsqHQFYFMdMwR0+ZIm7aeKNAIEDcHrcjvj4HiD6fkSNHjghFQjVEI9dVGZi2udLr9jaeOHHipFMK5QkhuwKBgCwHv6i0XmZA9E6SyuuWFUFM1i1yCgsLm0SPgYaDBw8WmaZ5FgDAMAwg2s2zBKKRpYZhLB0+fDgcOHAACCFDH3zwQeUP1Bg5cmQTRO+EZBFbL5M2v4wQ8l+GYYTh2o6w8SSVDOvoNTGJ1r1usm/fvkHERZTeiuXDDz/0HjhwwI4FsFSYpnn2wIED9ocffnjTV+0q0XV95r59+2Q7o1Hm9TJL07T/hOh6WF9rYjYAgG3bbtu2c+P9EPUgZpmWFAWsovK9kqYps37Rq/3799967ty5jAv8z507171///5baYxJlMLCQlnfy9h6mUz5ZWYkErnU8+ek0is0TYtomtYZ7++pB7H29vbttNtMhQZayeRJkzVZFu5709raOlb0GDJx9OjRWwkhZ2i1Rwg5c/ToUaUD2bFjx2R+T2PrZSWCx2H2jOEEAOQCpR1fqQexysrKNtptJsMAs7Grs8s1adIkXnt8pSUQCBCX26Xs3lEffvihNxQKUQtgMaFQ6IzKU0vLsvYHAgEqKQMM/RaiU0xu3+DeIAgAsf0FLZC1dhIAoKuzqz+LduPJ8eUM/rdJU+ZKO3X8gsLCwg2i+jYNszbTNmhMIVm2bVlWxs8xXSNHjhT23qbABIC5gkqY1gPA3yG6i0UHyBzEKioqgrZlM7+YdE0fPXnSZI3XHl+Z6lnMF7ZmGAwGM9pf7ODBg0W0xsKqj0uXLgnbQ03X9ZoPPvhAtkX+XvWUMBEAGM2py7MAsK7nz7EdLKjkiTH7dvLRRx9dy6rtWKkQzz2+qBC8mF9RUZHRVuHpfAvJu9sQ6rQAAAfkSURBVI/S0lKh26FfuXJF1kX+3lgA8EeIxoEFjPt6HgDOAUAOXDvGTd47sZhJ5ZOoti9zykRf3vn1O8Ui++/q7Hook8fzXO/JtK9wOJzRc83U+++/L/S9TlEEor9LLQDwvzVNO8SgjyqIVoq4IboND9XfXaZBTNM0e/KkyRqNqaX0KROJabqlC82injx58sFMHj9y5MgRtMbCuq8xY8Zk9FwzZZrmEcF1leloA4CPbNv+P4SQxym1eRIAvgLRXDUC0Ux96oevcEl2ffTRR9d2edNc7LfhXtlTJvrCsz6yN0bEKIEMP/1CkRC3tTwKfdm6rgtNJ+ipq1RJbI0qZJrmGxD9FjOTvQGXQfTU848hGmdMYDR74v5p0dLSUpCfnz9VJ3rcr3lty67Vdb1l0qRJl+L9jCoCgQAZOGigIXIM48eN1yHDC+jAgQNcp+9jxozJ9NrUjhw5IvT4uo8//liWuspUeSB6vcSu2wcAoBoAZvfxOAMAfgUAqyCazhEBSnuGJcK9drInj2wjOHw3hRjR9ZGaW7sfFFs/pMTWNO1+27aPiRqAhHWVyYolobohGoQOAcBBAJgLAHcAwIief48CAB9Ej2I7DwB/g+gXBZchGriYBzCALNnpU5R9+/YNEv2NJK1DQhS8EwMA+oeFpCoYDHI75o+hWDAz4NrOEwSiN0Gx/w9wLYFVA4pHsvXF0QXgwomuj7SlqpkTIhgMCn0NJK6rTEUEot8qWhANaLGgZsK1dIkYalvsJAuDGCPvvCM2pcI0zM0OuAPI2Pjx4y9YliV0JwfFUi4SsSEatGL/GD3/xP6b2eJ9IhjE2NB0IjalIhgMVovsXyYnTpwQ+loomnKhDAxiDIhOqYiEI+WKfivGREVFhWmaptBDNRRMuVAGBjHKZNhyuqysbI/I/mX0wAMPCH1Nerayln2XCyVhEKNMdEqFpVujITtTKhLSNM0mhPAqdu5VT8oFogyDGEUybDn9yMOPqFUUz9F9990n9LWRdCtr5WEQowlTKqTXr18/TLlwGAxilEiQUtGIKRV9u+uuuy5YliVqZ1MAcFTKhRQwiNEhQ0rFfJH9q+TEiRNCXytMuaALgxgFolMqjIhRgikVyauoqDBxlwvnwCCWIRlSKkpLS6U+HEVG999/v9DXDFMu6MEgliHRKRW4mJ8+0XWVmHJBBwaxDIhOqcD6yMyIrqvElAs6MIhlQnBKBdZHZk50XSWmXGQOg1iaRJ/ijfWRdMhQVyn56eHSwyCWBhlO8cb6SHpE11Uqcnq4tDCIpUHkKd4AAJaJ9ZE0SVJXqcLp4VLCIJYi0ad4AwA88gjWR9ImQV2lMqeHywaDWKqwPtKxRKdcKHZ6uDQwiKVAgvpITKlgSHTKBQDWVaYDg1jyZKiPxJQKxkSnXGBdZeowiCVJdH0kplTwIUPKBdZVpgaDWBJkqI/ElAp+RKdcYF1lajCIJUF0fSSmVPAlScoF1lUmCYNYH0TXRwJgSoUIEqRcYF1lkjCI9QVTKrKW6JQLrKtMDgaxBH71q1/9k8j+MaVCLBlSLg4dOiT0GlQBBrEELNv6g8j+MaVCPNEpF7quC70GVYBBLI5AIDBQZP8RE1MqZCBDykVra6vQa1F2GMTiKCwsnCay/7JHMKVCFqJTLgYMGCD0WpQdBrE4iIvUi+obT/GWi+iUC13XhV2LKsAgJiE8xVs+olMuUHwYxGSDKRXSEn16OOodBjGJ4CnecpPh9HB0MwxiEsFTvOUn+vRwdDMMYpLAU7zVIMPp4eh6GMQkgad4q0P06eHoehjE4rAtm98++riYrxyedZW2zfFaVBAGsTgikch2Hv1gfaSaeNZVDhgwgMu1qCoMYnFMnDixjUc/WB+pLl51lXfccQeXa1FVGMQSsC27P8v2uzq7HsLFfHVVVFSY4XD4IZZ9aJrG9Bp0AgxiCXzrW98KmoZZy6r9yZMn/z9WbSM+xowZw+w9tCyrtri4OMiqfafAINaHCRMmrGXR7l//8lcfi3YRf/3792fyXj7wwANMrj2nwSCWhHH/Oo7q6+T1eAfW1taGaLaJxLnjjjtCXq+X6nY5xcXF+LuZJHyhkqBpmj1+3HiNxtTyr3/5q2/s2LGXaIwLyeOee+65ROOOzLKs2tGjR2uapuEuJknCQzpT9O677xZqunY51ccZEePu0tLSv7AYEw8HDhzg+ks1ZswYZa/Nw4cPf03TtD+n+jhN0/rjGljqlL1QRGtpaSkoKiqaqula3IJg0zBrI7mRlkljJyl/54VBLHV/+tOfBnR1dVUm2g/Mtu2a8+fPb+eV0uNEyl8oiA8MYkhWuCaGEFIaBjGEkNIwiCGElIZBDCGkNAxiCCGlYRBDSTFtc6UT+0LqwyCGkuJ1e7kdkMGzL6Q+DGIoKSdOnDjpxL6Q+jChECWNV8IrJrqiVOCdGEpae3v7MCf0gZwFP/FQSljfjeFdGEoV3omhlASDwUIV20bOhUEMpWTixIltpmmW0m7XNM1S3MkBpQODGEpZSUnJXtM0n6bVnmmaT5eUlOyl1R7KLrj+gNK2f//+CYSQ1kzaME2zFAMYygQGMZSR3bt3FxQWFqa1G2kwGCzEKSTKFAYxREVra+ut+fn5Z5L52fb29mGlpaWfsh4Tyg4YxBBVgUCA3HLLLbe5ve7pRsSYDwDgcrs2REKRrZ9//vk/8LBghBBC6Av+P556OTenadBoAAAAAElFTkSuQmCC"); + -webkit-animation-duration: 1s; + -webkit-animation-iteration-count: infinite; + -webkit-animation-timing-function: linear; + -webkit-animation-name: spinnerAnim; +} +@-webkit-keyframes spinnerAnim { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(360deg); } +} \ No newline at end of file diff --git a/www/js/libs/iscroll.js b/www/js/libs/iscroll.js new file mode 100755 index 0000000..83fed99 --- /dev/null +++ b/www/js/libs/iscroll.js @@ -0,0 +1,1078 @@ +/*! + * iScroll v4.1.9 ~ Copyright (c) 2011 Matteo Spinelli, http://cubiq.org + * Released under MIT license, http://cubiq.org/license + */ +(function(){ +var m = Math, + mround = function (r) { return r >> 0; }, + vendor = (/webkit/i).test(navigator.appVersion) ? 'webkit' : + (/firefox/i).test(navigator.userAgent) ? 'Moz' : + (/trident/i).test(navigator.userAgent) ? 'ms' : + 'opera' in window ? 'O' : '', + + // Browser capabilities + isAndroid = (/android/gi).test(navigator.appVersion), + isIDevice = (/iphone|ipad/gi).test(navigator.appVersion), + isPlaybook = (/playbook/gi).test(navigator.appVersion), + isTouchPad = (/hp-tablet/gi).test(navigator.appVersion), + + has3d = 'WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix(), + hasTouch = 'ontouchstart' in window && !isTouchPad, + hasTransform = vendor + 'Transform' in document.documentElement.style, + hasTransitionEnd = isIDevice || isPlaybook, + + nextFrame = (function() { + return window.requestAnimationFrame + || window.webkitRequestAnimationFrame + || window.mozRequestAnimationFrame + || window.oRequestAnimationFrame + || window.msRequestAnimationFrame + || function(callback) { return setTimeout(callback, 1); } + })(), + cancelFrame = (function () { + return window.cancelRequestAnimationFrame + || window.webkitCancelAnimationFrame + || window.webkitCancelRequestAnimationFrame + || window.mozCancelRequestAnimationFrame + || window.oCancelRequestAnimationFrame + || window.msCancelRequestAnimationFrame + || clearTimeout + })(), + + // Events + RESIZE_EV = 'onorientationchange' in window ? 'orientationchange' : 'resize', + START_EV = hasTouch ? 'touchstart' : 'mousedown', + MOVE_EV = hasTouch ? 'touchmove' : 'mousemove', + END_EV = hasTouch ? 'touchend' : 'mouseup', + CANCEL_EV = hasTouch ? 'touchcancel' : 'mouseup', + WHEEL_EV = vendor == 'Moz' ? 'DOMMouseScroll' : 'mousewheel', + + // Helpers + trnOpen = 'translate' + (has3d ? '3d(' : '('), + trnClose = has3d ? ',0)' : ')', + + // Constructor + iScroll = function (el, options) { + var that = this, + doc = document, + i; + + that.wrapper = typeof el == 'object' ? el : doc.getElementById(el); + that.wrapper.style.overflow = 'hidden'; + that.scroller = that.wrapper.children[0]; + + // Default options + that.options = { + hScroll: true, + vScroll: true, + x: 0, + y: 0, + bounce: true, + bounceLock: false, + momentum: true, + lockDirection: true, + useTransform: true, + useTransition: false, + topOffset: 0, + checkDOMChanges: false, // Experimental + + // Scrollbar + hScrollbar: true, + vScrollbar: true, + fixedScrollbar: isAndroid, + hideScrollbar: isIDevice, + fadeScrollbar: isIDevice && has3d, + scrollbarClass: '', + + // Zoom + zoom: false, + zoomMin: 1, + zoomMax: 4, + doubleTapZoom: 2, + wheelAction: 'scroll', + + // Snap + snap: false, + snapThreshold: 1, + + // Events + onRefresh: null, + onBeforeScrollStart: function (e) { e.preventDefault(); }, + onScrollStart: null, + onBeforeScrollMove: null, + onScrollMove: null, + onBeforeScrollEnd: null, + onScrollEnd: null, + onTouchEnd: null, + onDestroy: null, + onZoomStart: null, + onZoom: null, + onZoomEnd: null + }; + + // User defined options + for (i in options) that.options[i] = options[i]; + + // Set starting position + that.x = that.options.x; + that.y = that.options.y; + + // Normalize options + that.options.useTransform = hasTransform ? that.options.useTransform : false; + that.options.hScrollbar = that.options.hScroll && that.options.hScrollbar; + that.options.vScrollbar = that.options.vScroll && that.options.vScrollbar; + that.options.zoom = that.options.useTransform && that.options.zoom; + that.options.useTransition = hasTransitionEnd && that.options.useTransition; + + // Helpers FIX ANDROID BUG! + // translate3d and scale doesn't work together! + // Ignoring 3d ONLY WHEN YOU SET that.options.zoom + if ( that.options.zoom && isAndroid ){ + trnOpen = 'translate('; + trnClose = ')'; + } + + // Set some default styles + that.scroller.style[vendor + 'TransitionProperty'] = that.options.useTransform ? '-' + vendor.toLowerCase() + '-transform' : 'top left'; + that.scroller.style[vendor + 'TransitionDuration'] = '0'; + that.scroller.style[vendor + 'TransformOrigin'] = '0 0'; + if (that.options.useTransition) that.scroller.style[vendor + 'TransitionTimingFunction'] = 'cubic-bezier(0.33,0.66,0.66,1)'; + + if (that.options.useTransform) that.scroller.style[vendor + 'Transform'] = trnOpen + that.x + 'px,' + that.y + 'px' + trnClose; + else that.scroller.style.cssText += ';position:absolute;top:' + that.y + 'px;left:' + that.x + 'px'; + + if (that.options.useTransition) that.options.fixedScrollbar = true; + + that.refresh(); + + that._bind(RESIZE_EV, window); + that._bind(START_EV); + if (!hasTouch) { + that._bind('mouseout', that.wrapper); + if (that.options.wheelAction != 'none') + that._bind(WHEEL_EV); + } + + if (that.options.checkDOMChanges) that.checkDOMTime = setInterval(function () { + that._checkDOMChanges(); + }, 500); + }; + +// Prototype +iScroll.prototype = { + enabled: true, + x: 0, + y: 0, + steps: [], + scale: 1, + currPageX: 0, currPageY: 0, + pagesX: [], pagesY: [], + aniTime: null, + wheelZoomCount: 0, + + handleEvent: function (e) { + var that = this; + switch(e.type) { + case START_EV: + if (!hasTouch && e.button !== 0) return; + var nodeName = e.target.nodeName.toUpperCase(); + if (nodeName == "TEXTAREA" || nodeName == "INPUT" || nodeName == "SELECT" ) return; + that._start(e); + break; + case MOVE_EV: that._move(e); break; + case END_EV: + case CANCEL_EV: that._end(e); break; + case RESIZE_EV: that._resize(); break; + case WHEEL_EV: that._wheel(e); break; + case 'mouseout': that._mouseout(e); break; + case 'webkitTransitionEnd': that._transitionEnd(e); break; + } + }, + + _checkDOMChanges: function () { + if (this.moved || this.zoomed || this.animating || + (this.scrollerW == this.scroller.offsetWidth * this.scale && this.scrollerH == this.scroller.offsetHeight * this.scale)) return; + + this.refresh(); + }, + + _scrollbar: function (dir) { + var that = this, + doc = document, + bar; + + if (!that[dir + 'Scrollbar']) { + if (that[dir + 'ScrollbarWrapper']) { + if (hasTransform) that[dir + 'ScrollbarIndicator'].style[vendor + 'Transform'] = ''; + that[dir + 'ScrollbarWrapper'].parentNode.removeChild(that[dir + 'ScrollbarWrapper']); + that[dir + 'ScrollbarWrapper'] = null; + that[dir + 'ScrollbarIndicator'] = null; + } + + return; + } + + if (!that[dir + 'ScrollbarWrapper']) { + // Create the scrollbar wrapper + bar = doc.createElement('div'); + + if (that.options.scrollbarClass) bar.className = that.options.scrollbarClass + dir.toUpperCase(); + else bar.style.cssText = 'position:absolute;z-index:100;' + (dir == 'h' ? 'height:7px;bottom:1px;left:2px;right:' + (that.vScrollbar ? '7' : '2') + 'px' : 'width:7px;bottom:' + (that.hScrollbar ? '7' : '2') + 'px;top:2px;right:1px'); + + bar.style.cssText += ';pointer-events:none;-' + vendor + '-transition-property:opacity;-' + vendor + '-transition-duration:' + (that.options.fadeScrollbar ? '350ms' : '0') + ';overflow:hidden;opacity:' + (that.options.hideScrollbar ? '0' : '1'); + + that.wrapper.appendChild(bar); + that[dir + 'ScrollbarWrapper'] = bar; + + // Create the scrollbar indicator + bar = doc.createElement('div'); + if (!that.options.scrollbarClass) { + bar.style.cssText = 'position:absolute;z-index:100;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);-' + vendor + '-background-clip:padding-box;-' + vendor + '-box-sizing:border-box;' + (dir == 'h' ? 'height:100%' : 'width:100%') + ';-' + vendor + '-border-radius:3px;border-radius:3px'; + } + bar.style.cssText += ';pointer-events:none;-' + vendor + '-transition-property:-' + vendor + '-transform;-' + vendor + '-transition-timing-function:cubic-bezier(0.33,0.66,0.66,1);-' + vendor + '-transition-duration:0;-' + vendor + '-transform:' + trnOpen + '0,0' + trnClose; + if (that.options.useTransition) bar.style.cssText += ';-' + vendor + '-transition-timing-function:cubic-bezier(0.33,0.66,0.66,1)'; + + that[dir + 'ScrollbarWrapper'].appendChild(bar); + that[dir + 'ScrollbarIndicator'] = bar; + } + + if (dir == 'h') { + that.hScrollbarSize = that.hScrollbarWrapper.clientWidth; + that.hScrollbarIndicatorSize = m.max(mround(that.hScrollbarSize * that.hScrollbarSize / that.scrollerW), 8); + that.hScrollbarIndicator.style.width = that.hScrollbarIndicatorSize + 'px'; + that.hScrollbarMaxScroll = that.hScrollbarSize - that.hScrollbarIndicatorSize; + that.hScrollbarProp = that.hScrollbarMaxScroll / that.maxScrollX; + } else { + that.vScrollbarSize = that.vScrollbarWrapper.clientHeight; + that.vScrollbarIndicatorSize = m.max(mround(that.vScrollbarSize * that.vScrollbarSize / that.scrollerH), 8); + that.vScrollbarIndicator.style.height = that.vScrollbarIndicatorSize + 'px'; + that.vScrollbarMaxScroll = that.vScrollbarSize - that.vScrollbarIndicatorSize; + that.vScrollbarProp = that.vScrollbarMaxScroll / that.maxScrollY; + } + + // Reset position + that._scrollbarPos(dir, true); + }, + + _resize: function () { + var that = this; + setTimeout(function () { that.refresh(); }, isAndroid ? 200 : 0); + }, + + _pos: function (x, y) { + x = this.hScroll ? x : 0; + y = this.vScroll ? y : 0; + + if (this.options.useTransform) { + this.scroller.style[vendor + 'Transform'] = trnOpen + x + 'px,' + y + 'px' + trnClose + ' scale(' + this.scale + ')'; + } else { + x = mround(x); + y = mround(y); + this.scroller.style.left = x + 'px'; + this.scroller.style.top = y + 'px'; + } + + this.x = x; + this.y = y; + + this._scrollbarPos('h'); + this._scrollbarPos('v'); + }, + + _scrollbarPos: function (dir, hidden) { + var that = this, + pos = dir == 'h' ? that.x : that.y, + size; + + if (!that[dir + 'Scrollbar']) return; + + pos = that[dir + 'ScrollbarProp'] * pos; + + if (pos < 0) { + if (!that.options.fixedScrollbar) { + size = that[dir + 'ScrollbarIndicatorSize'] + mround(pos * 3); + if (size < 8) size = 8; + that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px'; + } + pos = 0; + } else if (pos > that[dir + 'ScrollbarMaxScroll']) { + if (!that.options.fixedScrollbar) { + size = that[dir + 'ScrollbarIndicatorSize'] - mround((pos - that[dir + 'ScrollbarMaxScroll']) * 3); + if (size < 8) size = 8; + that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px'; + pos = that[dir + 'ScrollbarMaxScroll'] + (that[dir + 'ScrollbarIndicatorSize'] - size); + } else { + pos = that[dir + 'ScrollbarMaxScroll']; + } + } + + that[dir + 'ScrollbarWrapper'].style[vendor + 'TransitionDelay'] = '0'; + that[dir + 'ScrollbarWrapper'].style.opacity = hidden && that.options.hideScrollbar ? '0' : '1'; + that[dir + 'ScrollbarIndicator'].style[vendor + 'Transform'] = trnOpen + (dir == 'h' ? pos + 'px,0' : '0,' + pos + 'px') + trnClose; + }, + + _start: function (e) { + var that = this, + point = hasTouch ? e.touches[0] : e, + matrix, x, y, + c1, c2; + + if (!that.enabled) return; + + if (that.options.onBeforeScrollStart) that.options.onBeforeScrollStart.call(that, e); + + if (that.options.useTransition || that.options.zoom) that._transitionTime(0); + + that.moved = false; + that.animating = false; + that.zoomed = false; + that.distX = 0; + that.distY = 0; + that.absDistX = 0; + that.absDistY = 0; + that.dirX = 0; + that.dirY = 0; + + // Gesture start + if (that.options.zoom && hasTouch && e.touches.length > 1) { + c1 = m.abs(e.touches[0].pageX-e.touches[1].pageX); + c2 = m.abs(e.touches[0].pageY-e.touches[1].pageY); + that.touchesDistStart = m.sqrt(c1 * c1 + c2 * c2); + + that.originX = m.abs(e.touches[0].pageX + e.touches[1].pageX - that.wrapperOffsetLeft * 2) / 2 - that.x; + that.originY = m.abs(e.touches[0].pageY + e.touches[1].pageY - that.wrapperOffsetTop * 2) / 2 - that.y; + + if (that.options.onZoomStart) that.options.onZoomStart.call(that, e); + } + + if (that.options.momentum) { + if (that.options.useTransform) { + // Very lame general purpose alternative to CSSMatrix + matrix = getComputedStyle(that.scroller, null)[vendor + 'Transform'].replace(/[^0-9-.,]/g, '').split(','); + x = matrix[4] * 1; + y = matrix[5] * 1; + } else { + x = getComputedStyle(that.scroller, null).left.replace(/[^0-9-]/g, '') * 1; + y = getComputedStyle(that.scroller, null).top.replace(/[^0-9-]/g, '') * 1; + } + + if (x != that.x || y != that.y) { + if (that.options.useTransition) that._unbind('webkitTransitionEnd'); + else cancelFrame(that.aniTime); + that.steps = []; + that._pos(x, y); + } + } + + that.absStartX = that.x; // Needed by snap threshold + that.absStartY = that.y; + + that.startX = that.x; + that.startY = that.y; + that.pointX = point.pageX; + that.pointY = point.pageY; + + that.startTime = e.timeStamp || Date.now(); + + if (that.options.onScrollStart) that.options.onScrollStart.call(that, e); + + that._bind(MOVE_EV); + that._bind(END_EV); + that._bind(CANCEL_EV); + }, + + _move: function (e) { + var that = this, + point = hasTouch ? e.touches[0] : e, + deltaX = point.pageX - that.pointX, + deltaY = point.pageY - that.pointY, + newX = that.x + deltaX, + newY = that.y + deltaY, + c1, c2, scale, + timestamp = e.timeStamp || Date.now(); + + if (that.options.onBeforeScrollMove) that.options.onBeforeScrollMove.call(that, e); + + // Zoom + if (that.options.zoom && hasTouch && e.touches.length > 1) { + c1 = m.abs(e.touches[0].pageX - e.touches[1].pageX); + c2 = m.abs(e.touches[0].pageY - e.touches[1].pageY); + that.touchesDist = m.sqrt(c1*c1+c2*c2); + + that.zoomed = true; + + scale = 1 / that.touchesDistStart * that.touchesDist * this.scale; + + if (scale < that.options.zoomMin) scale = 0.5 * that.options.zoomMin * Math.pow(2.0, scale / that.options.zoomMin); + else if (scale > that.options.zoomMax) scale = 2.0 * that.options.zoomMax * Math.pow(0.5, that.options.zoomMax / scale); + + that.lastScale = scale / this.scale; + + newX = this.originX - this.originX * that.lastScale + this.x, + newY = this.originY - this.originY * that.lastScale + this.y; + + this.scroller.style[vendor + 'Transform'] = trnOpen + newX + 'px,' + newY + 'px' + trnClose + ' scale(' + scale + ')'; + + if (that.options.onZoom) that.options.onZoom.call(that, e); + return; + } + + that.pointX = point.pageX; + that.pointY = point.pageY; + + // Slow down if outside of the boundaries + if (newX > 0 || newX < that.maxScrollX) { + newX = that.options.bounce ? that.x + (deltaX / 2) : newX >= 0 || that.maxScrollX >= 0 ? 0 : that.maxScrollX; + } + if (newY > that.minScrollY || newY < that.maxScrollY) { + newY = that.options.bounce ? that.y + (deltaY / 2) : newY >= that.minScrollY || that.maxScrollY >= 0 ? that.minScrollY : that.maxScrollY; + } + + that.distX += deltaX; + that.distY += deltaY; + that.absDistX = m.abs(that.distX); + that.absDistY = m.abs(that.distY); + + if (that.absDistX < 6 && that.absDistY < 6) { + return; + } + + // Lock direction + if (that.options.lockDirection) { + if (that.absDistX > that.absDistY + 5) { + newY = that.y; + deltaY = 0; + } else if (that.absDistY > that.absDistX + 5) { + newX = that.x; + deltaX = 0; + } + } + + that.moved = true; + that._pos(newX, newY); + that.dirX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; + that.dirY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; + + if (timestamp - that.startTime > 300) { + that.startTime = timestamp; + that.startX = that.x; + that.startY = that.y; + } + + if (that.options.onScrollMove) that.options.onScrollMove.call(that, e); + }, + + _end: function (e) { + if (hasTouch && e.touches.length != 0) return; + + var that = this, + point = hasTouch ? e.changedTouches[0] : e, + target, ev, + momentumX = { dist:0, time:0 }, + momentumY = { dist:0, time:0 }, + duration = (e.timeStamp || Date.now()) - that.startTime, + newPosX = that.x, + newPosY = that.y, + distX, distY, + newDuration, + snap, + scale; + + that._unbind(MOVE_EV); + that._unbind(END_EV); + that._unbind(CANCEL_EV); + + if (that.options.onBeforeScrollEnd) that.options.onBeforeScrollEnd.call(that, e); + + if (that.zoomed) { + scale = that.scale * that.lastScale; + scale = Math.max(that.options.zoomMin, scale); + scale = Math.min(that.options.zoomMax, scale); + that.lastScale = scale / that.scale; + that.scale = scale; + + that.x = that.originX - that.originX * that.lastScale + that.x; + that.y = that.originY - that.originY * that.lastScale + that.y; + + that.scroller.style[vendor + 'TransitionDuration'] = '200ms'; + that.scroller.style[vendor + 'Transform'] = trnOpen + that.x + 'px,' + that.y + 'px' + trnClose + ' scale(' + that.scale + ')'; + + that.zoomed = false; + that.refresh(); + + if (that.options.onZoomEnd) that.options.onZoomEnd.call(that, e); + return; + } + + if (!that.moved) { + if (hasTouch) { + if (that.doubleTapTimer && that.options.zoom) { + // Double tapped + clearTimeout(that.doubleTapTimer); + that.doubleTapTimer = null; + if (that.options.onZoomStart) that.options.onZoomStart.call(that, e); + that.zoom(that.pointX, that.pointY, that.scale == 1 ? that.options.doubleTapZoom : 1); + if (that.options.onZoomEnd) { + setTimeout(function() { + that.options.onZoomEnd.call(that, e); + }, 200); // 200 is default zoom duration + } + } else { + that.doubleTapTimer = setTimeout(function () { + that.doubleTapTimer = null; + + // Find the last touched element + target = point.target; + while (target.nodeType != 1) target = target.parentNode; + + if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') { + ev = document.createEvent('MouseEvents'); + ev.initMouseEvent('click', true, true, e.view, 1, + point.screenX, point.screenY, point.clientX, point.clientY, + e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, + 0, null); + ev._fake = true; + target.dispatchEvent(ev); + } + }, that.options.zoom ? 250 : 0); + } + } + + that._resetPos(200); + + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + return; + } + + if (duration < 300 && that.options.momentum) { + momentumX = newPosX ? that._momentum(newPosX - that.startX, duration, -that.x, that.scrollerW - that.wrapperW + that.x, that.options.bounce ? that.wrapperW : 0) : momentumX; + momentumY = newPosY ? that._momentum(newPosY - that.startY, duration, -that.y, (that.maxScrollY < 0 ? that.scrollerH - that.wrapperH + that.y - that.minScrollY : 0), that.options.bounce ? that.wrapperH : 0) : momentumY; + + newPosX = that.x + momentumX.dist; + newPosY = that.y + momentumY.dist; + + if ((that.x > 0 && newPosX > 0) || (that.x < that.maxScrollX && newPosX < that.maxScrollX)) momentumX = { dist:0, time:0 }; + if ((that.y > that.minScrollY && newPosY > that.minScrollY) || (that.y < that.maxScrollY && newPosY < that.maxScrollY)) momentumY = { dist:0, time:0 }; + } + + if (momentumX.dist || momentumY.dist) { + newDuration = m.max(m.max(momentumX.time, momentumY.time), 10); + + // Do we need to snap? + if (that.options.snap) { + distX = newPosX - that.absStartX; + distY = newPosY - that.absStartY; + if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) { that.scrollTo(that.absStartX, that.absStartY, 200); } + else { + snap = that._snap(newPosX, newPosY); + newPosX = snap.x; + newPosY = snap.y; + newDuration = m.max(snap.time, newDuration); + } + } + + that.scrollTo(mround(newPosX), mround(newPosY), newDuration); + + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + return; + } + + // Do we need to snap? + if (that.options.snap) { + distX = newPosX - that.absStartX; + distY = newPosY - that.absStartY; + if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) that.scrollTo(that.absStartX, that.absStartY, 200); + else { + snap = that._snap(that.x, that.y); + if (snap.x != that.x || snap.y != that.y) that.scrollTo(snap.x, snap.y, snap.time); + } + + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + return; + } + + that._resetPos(200); + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + }, + + _resetPos: function (time) { + var that = this, + resetX = that.x >= 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x, + resetY = that.y >= that.minScrollY || that.maxScrollY > 0 ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y; + + if (resetX == that.x && resetY == that.y) { + if (that.moved) { + that.moved = false; + if (that.options.onScrollEnd) that.options.onScrollEnd.call(that); // Execute custom code on scroll end + } + + if (that.hScrollbar && that.options.hideScrollbar) { + if (vendor == 'webkit') that.hScrollbarWrapper.style[vendor + 'TransitionDelay'] = '300ms'; + that.hScrollbarWrapper.style.opacity = '0'; + } + if (that.vScrollbar && that.options.hideScrollbar) { + if (vendor == 'webkit') that.vScrollbarWrapper.style[vendor + 'TransitionDelay'] = '300ms'; + that.vScrollbarWrapper.style.opacity = '0'; + } + + return; + } + + that.scrollTo(resetX, resetY, time || 0); + }, + + _wheel: function (e) { + var that = this, + wheelDeltaX, wheelDeltaY, + deltaX, deltaY, + deltaScale; + + if ('wheelDeltaX' in e) { + wheelDeltaX = e.wheelDeltaX / 12; + wheelDeltaY = e.wheelDeltaY / 12; + } else if('wheelDelta' in e) { + wheelDeltaX = wheelDeltaY = e.wheelDelta / 12; + } else if ('detail' in e) { + wheelDeltaX = wheelDeltaY = -e.detail * 3; + } else { + return; + } + + if (that.options.wheelAction == 'zoom') { + deltaScale = that.scale * Math.pow(2, 1/3 * (wheelDeltaY ? wheelDeltaY / Math.abs(wheelDeltaY) : 0)); + if (deltaScale < that.options.zoomMin) deltaScale = that.options.zoomMin; + if (deltaScale > that.options.zoomMax) deltaScale = that.options.zoomMax; + + if (deltaScale != that.scale) { + if (!that.wheelZoomCount && that.options.onZoomStart) that.options.onZoomStart.call(that, e); + that.wheelZoomCount++; + + that.zoom(e.pageX, e.pageY, deltaScale, 400); + + setTimeout(function() { + that.wheelZoomCount--; + if (!that.wheelZoomCount && that.options.onZoomEnd) that.options.onZoomEnd.call(that, e); + }, 400); + } + + return; + } + + deltaX = that.x + wheelDeltaX; + deltaY = that.y + wheelDeltaY; + + if (deltaX > 0) deltaX = 0; + else if (deltaX < that.maxScrollX) deltaX = that.maxScrollX; + + if (deltaY > that.minScrollY) deltaY = that.minScrollY; + else if (deltaY < that.maxScrollY) deltaY = that.maxScrollY; + + that.scrollTo(deltaX, deltaY, 0); + }, + + _mouseout: function (e) { + var t = e.relatedTarget; + + if (!t) { + this._end(e); + return; + } + + while (t = t.parentNode) if (t == this.wrapper) return; + + this._end(e); + }, + + _transitionEnd: function (e) { + var that = this; + + if (e.target != that.scroller) return; + + that._unbind('webkitTransitionEnd'); + + that._startAni(); + }, + + + /** + * + * Utilities + * + */ + _startAni: function () { + var that = this, + startX = that.x, startY = that.y, + startTime = Date.now(), + step, easeOut, + animate; + + if (that.animating) return; + + if (!that.steps.length) { + that._resetPos(400); + return; + } + + step = that.steps.shift(); + + if (step.x == startX && step.y == startY) step.time = 0; + + that.animating = true; + that.moved = true; + + if (that.options.useTransition) { + that._transitionTime(step.time); + that._pos(step.x, step.y); + that.animating = false; + if (step.time) that._bind('webkitTransitionEnd'); + else that._resetPos(0); + return; + } + + animate = function () { + var now = Date.now(), + newX, newY; + + if (now >= startTime + step.time) { + that._pos(step.x, step.y); + that.animating = false; + if (that.options.onAnimationEnd) that.options.onAnimationEnd.call(that); // Execute custom code on animation end + that._startAni(); + return; + } + + now = (now - startTime) / step.time - 1; + easeOut = m.sqrt(1 - now * now); + newX = (step.x - startX) * easeOut + startX; + newY = (step.y - startY) * easeOut + startY; + that._pos(newX, newY); + if (that.animating) that.aniTime = nextFrame(animate); + }; + + animate(); + }, + + _transitionTime: function (time) { + time += 'ms'; + this.scroller.style[vendor + 'TransitionDuration'] = time; + if (this.hScrollbar) this.hScrollbarIndicator.style[vendor + 'TransitionDuration'] = time; + if (this.vScrollbar) this.vScrollbarIndicator.style[vendor + 'TransitionDuration'] = time; + }, + + _momentum: function (dist, time, maxDistUpper, maxDistLower, size) { + var deceleration = 0.0006, + speed = m.abs(dist) / time, + newDist = (speed * speed) / (2 * deceleration), + newTime = 0, outsideDist = 0; + + // Proportinally reduce speed if we are outside of the boundaries + if (dist > 0 && newDist > maxDistUpper) { + outsideDist = size / (6 / (newDist / speed * deceleration)); + maxDistUpper = maxDistUpper + outsideDist; + speed = speed * maxDistUpper / newDist; + newDist = maxDistUpper; + } else if (dist < 0 && newDist > maxDistLower) { + outsideDist = size / (6 / (newDist / speed * deceleration)); + maxDistLower = maxDistLower + outsideDist; + speed = speed * maxDistLower / newDist; + newDist = maxDistLower; + } + + newDist = newDist * (dist < 0 ? -1 : 1); + newTime = speed / deceleration; + + return { dist: newDist, time: mround(newTime) }; + }, + + _offset: function (el) { + var left = -el.offsetLeft, + top = -el.offsetTop; + + while (el = el.offsetParent) { + left -= el.offsetLeft; + top -= el.offsetTop; + } + + if (el != this.wrapper) { + left *= this.scale; + top *= this.scale; + } + + return { left: left, top: top }; + }, + + _snap: function (x, y) { + var that = this, + i, l, + page, time, + sizeX, sizeY; + + // Check page X + page = that.pagesX.length - 1; + for (i=0, l=that.pagesX.length; i= that.pagesX[i]) { + page = i; + break; + } + } + if (page == that.currPageX && page > 0 && that.dirX < 0) page--; + x = that.pagesX[page]; + sizeX = m.abs(x - that.pagesX[that.currPageX]); + sizeX = sizeX ? m.abs(that.x - x) / sizeX * 500 : 0; + that.currPageX = page; + + // Check page Y + page = that.pagesY.length-1; + for (i=0; i= that.pagesY[i]) { + page = i; + break; + } + } + if (page == that.currPageY && page > 0 && that.dirY < 0) page--; + y = that.pagesY[page]; + sizeY = m.abs(y - that.pagesY[that.currPageY]); + sizeY = sizeY ? m.abs(that.y - y) / sizeY * 500 : 0; + that.currPageY = page; + + // Snap with constant speed (proportional duration) + time = mround(m.max(sizeX, sizeY)) || 200; + + return { x: x, y: y, time: time }; + }, + + _bind: function (type, el, bubble) { + (el || this.scroller).addEventListener(type, this, !!bubble); + }, + + _unbind: function (type, el, bubble) { + (el || this.scroller).removeEventListener(type, this, !!bubble); + }, + + + /** + * + * Public methods + * + */ + destroy: function () { + var that = this; + + that.scroller.style[vendor + 'Transform'] = ''; + + // Remove the scrollbars + that.hScrollbar = false; + that.vScrollbar = false; + that._scrollbar('h'); + that._scrollbar('v'); + + // Remove the event listeners + that._unbind(RESIZE_EV, window); + that._unbind(START_EV); + that._unbind(MOVE_EV); + that._unbind(END_EV); + that._unbind(CANCEL_EV); + + if (!that.options.hasTouch) { + that._unbind('mouseout', that.wrapper); + that._unbind(WHEEL_EV); + } + + if (that.options.useTransition) that._unbind('webkitTransitionEnd'); + + if (that.options.checkDOMChanges) clearInterval(that.checkDOMTime); + + if (that.options.onDestroy) that.options.onDestroy.call(that); + }, + + refresh: function () { + var that = this, + offset, + i, l, + els, + pos = 0, + page = 0; + + if (that.scale < that.options.zoomMin) that.scale = that.options.zoomMin; + that.wrapperW = that.wrapper.clientWidth || 1; + that.wrapperH = that.wrapper.clientHeight || 1; + + that.minScrollY = -that.options.topOffset || 0; + that.scrollerW = mround(that.scroller.offsetWidth * that.scale); + that.scrollerH = mround((that.scroller.offsetHeight + that.minScrollY) * that.scale); + that.maxScrollX = that.wrapperW - that.scrollerW; + that.maxScrollY = that.wrapperH - that.scrollerH + that.minScrollY; + that.dirX = 0; + that.dirY = 0; + + if (that.options.onRefresh) that.options.onRefresh.call(that); + + that.hScroll = that.options.hScroll && that.maxScrollX < 0; + that.vScroll = that.options.vScroll && (!that.options.bounceLock && !that.hScroll || that.scrollerH > that.wrapperH); + + that.hScrollbar = that.hScroll && that.options.hScrollbar; + that.vScrollbar = that.vScroll && that.options.vScrollbar && that.scrollerH > that.wrapperH; + + offset = that._offset(that.wrapper); + that.wrapperOffsetLeft = -offset.left; + that.wrapperOffsetTop = -offset.top; + + // Prepare snap + if (typeof that.options.snap == 'string') { + that.pagesX = []; + that.pagesY = []; + els = that.scroller.querySelectorAll(that.options.snap); + for (i=0, l=els.length; i= that.maxScrollX) { + that.pagesX[page] = pos; + pos = pos - that.wrapperW; + page++; + } + if (that.maxScrollX%that.wrapperW) that.pagesX[that.pagesX.length] = that.maxScrollX - that.pagesX[that.pagesX.length-1] + that.pagesX[that.pagesX.length-1]; + + pos = 0; + page = 0; + that.pagesY = []; + while (pos >= that.maxScrollY) { + that.pagesY[page] = pos; + pos = pos - that.wrapperH; + page++; + } + if (that.maxScrollY%that.wrapperH) that.pagesY[that.pagesY.length] = that.maxScrollY - that.pagesY[that.pagesY.length-1] + that.pagesY[that.pagesY.length-1]; + } + + // Prepare the scrollbars + that._scrollbar('h'); + that._scrollbar('v'); + + if (!that.zoomed) { + that.scroller.style[vendor + 'TransitionDuration'] = '0'; + that._resetPos(200); + } + }, + + scrollTo: function (x, y, time, relative) { + var that = this, + step = x, + i, l; + + that.stop(); + + if (!step.length) step = [{ x: x, y: y, time: time, relative: relative }]; + + for (i=0, l=step.length; i 0 ? 0 : pos.left < that.maxScrollX ? that.maxScrollX : pos.left; + pos.top = pos.top > that.minScrollY ? that.minScrollY : pos.top < that.maxScrollY ? that.maxScrollY : pos.top; + time = time === undefined ? m.max(m.abs(pos.left)*2, m.abs(pos.top)*2) : time; + + that.scrollTo(pos.left, pos.top, time); + }, + + scrollToPage: function (pageX, pageY, time) { + var that = this, x, y; + + time = time === undefined ? 400 : time; + + if (that.options.onScrollStart) that.options.onScrollStart.call(that); + + if (that.options.snap) { + pageX = pageX == 'next' ? that.currPageX+1 : pageX == 'prev' ? that.currPageX-1 : pageX; + pageY = pageY == 'next' ? that.currPageY+1 : pageY == 'prev' ? that.currPageY-1 : pageY; + + pageX = pageX < 0 ? 0 : pageX > that.pagesX.length-1 ? that.pagesX.length-1 : pageX; + pageY = pageY < 0 ? 0 : pageY > that.pagesY.length-1 ? that.pagesY.length-1 : pageY; + + that.currPageX = pageX; + that.currPageY = pageY; + x = that.pagesX[pageX]; + y = that.pagesY[pageY]; + } else { + x = -that.wrapperW * pageX; + y = -that.wrapperH * pageY; + if (x < that.maxScrollX) x = that.maxScrollX; + if (y < that.maxScrollY) y = that.maxScrollY; + } + + that.scrollTo(x, y, time); + }, + + disable: function () { + this.stop(); + this._resetPos(0); + this.enabled = false; + + // If disabled after touchstart we make sure that there are no left over events + this._unbind(MOVE_EV); + this._unbind(END_EV); + this._unbind(CANCEL_EV); + }, + + enable: function () { + this.enabled = true; + }, + + stop: function () { + if (this.options.useTransition) this._unbind('webkitTransitionEnd'); + else cancelFrame(this.aniTime); + this.steps = []; + this.moved = false; + this.animating = false; + }, + + zoom: function (x, y, scale, time) { + var that = this, + relScale = scale / that.scale; + + if (!that.options.useTransform) return; + + that.zoomed = true; + time = time === undefined ? 200 : time; + x = x - that.wrapperOffsetLeft - that.x; + y = y - that.wrapperOffsetTop - that.y; + that.x = x - x * relScale + that.x; + that.y = y - y * relScale + that.y; + + that.scale = scale; + that.refresh(); + + that.x = that.x > 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x; + that.y = that.y > that.minScrollY ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y; + + that.scroller.style[vendor + 'TransitionDuration'] = time + 'ms'; + that.scroller.style[vendor + 'Transform'] = trnOpen + that.x + 'px,' + that.y + 'px' + trnClose + ' scale(' + scale + ')'; + that.zoomed = false; + }, + + isReady: function () { + return !this.moved && !this.zoomed && !this.animating; + } +}; + +if (typeof exports !== 'undefined') exports.iScroll = iScroll; +else window.iScroll = iScroll; + +})(); diff --git a/www/js/libs/jquery.animateEnhanced.js b/www/js/libs/jquery.animateEnhanced.js new file mode 100755 index 0000000..d0117e9 --- /dev/null +++ b/www/js/libs/jquery.animateEnhanced.js @@ -0,0 +1,779 @@ +/* +jquery.animate-enhanced plugin v0.91 +--- +http://github.com/benbarnett/jQuery-Animate-Enhanced +http://benbarnett.net +@benpbarnett +--- +Copyright (c) 2012 Ben Barnett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +--- +Extends jQuery.animate() to automatically use CSS3 transformations where applicable. +Tested with jQuery 1.3.2+ + +Supports -moz-transition, -webkit-transition, -o-transition, transition + +Targetted properties (for now): + - left + - top + - opacity + - width + - height + +Usage (exactly the same as it would be normally): + + jQuery(element).animate({left: 200}, 500, function() { + // callback + }); + +Changelog: + 0.91 (2/4/2012): + - Merge Pull Request #74 - Unit Management + + 0.90 (7/3/2012): + - Adding public $.toggleDisabledByDefault() feature to disable entire plugin by default (Issue #73) + + 0.89 (24/1/2012): + - Adding 'avoidCSSTransitions' property. Set to true to disable entire plugin. (Issue #47) + + 0.88 (24/1/2012): + - Fix Issue #67 for HighchartsJS compatibility + + 0.87 (24/1/2012): + - Fix Issue #66 selfCSSData.original is undefined + + 0.86 (9/1/2012): + - Strict JS fix for undefined variable + + 0.85 (20/12/2011): + - Merge Pull request #57 from Kronuz + - Codebase cleaned and now passes jshint. + - Fixed a few bugs (it now saves and restores the original css transition properties). + - fadeOut() is fixed, it wasn't restoring the opacity after hiding it. + + 0.80 (13/09/2011): + - Issue #28 - Report $(el).is(':animated') fix + + 0.79 (06/09/2011): + - Issue #42 - Right negative position animation: please see issue notes on Github. + + 0.78 (02/09/2011): + - Issue #18 - jQuery/$ reference joys + + 0.77 (02/09/2011): + - Adding feature on Github issue #44 - Use 3D Transitions by default + + 0.76 (28/06/2011): + - Fixing issue #37 - fixed stop() method (with gotoEnd == false) + + 0.75 (15/06/2011): + - Fixing issue #35 to pass actual object back as context for callback + + 0.74 (28/05/2011): + - Fixing issue #29 to play nice with 1.6+ + + 0.73 (05/03/2011): + - Merged Pull Request #26: Fixed issue with fadeOut() / "hide" shortcut + + 0.72 (05/03/2011): + - Merged Pull Request #23: Added Penner equation approximations from Matthew Lein's Ceaser, and added failsafe fallbacks + + 0.71 (05/03/2011): + - Merged Pull Request #24: Changes translation object to integers instead of strings to fix relative values bug with leaveTransforms = true + + 0.70 (17/03/2011): + - Merged Pull Request from amlw-nyt to add bottom/right handling + + 0.68 (15/02/2011): + - width/height fixes & queue issues resolved. + + 0.67 (15/02/2011): + - Code cleanups & file size improvements for compression. + + 0.66 (15/02/2011): + - Zero second fadeOut(), fadeIn() fixes + + 0.65 (01/02/2011): + - Callbacks with queue() support refactored to support element arrays + + 0.64 (27/01/2011): + - BUGFIX #13: .slideUp(), .slideToggle(), .slideDown() bugfixes in Webkit + + 0.63 (12/01/2011): + - BUGFIX #11: callbacks not firing when new value == old value + + 0.62 (10/01/2011): + - BUGFIX #11: queue is not a function issue fixed + + 0.61 (10/01/2011): + - BUGFIX #10: Negative positions converting to positive + + 0.60 (06/01/2011): + - Animate function rewrite in accordance with new queue system + - BUGFIX #8: Left/top position values always assumed relative rather than absolute + - BUGFIX #9: animation as last item in a chain - the chain is ignored? + - BUGFIX: width/height CSS3 transformation with left/top working + + 0.55 (22/12/2010): + - isEmptyObject function for