You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by an...@apache.org on 2013/05/10 01:00:36 UTC
[34/43] Version 2.7.0-rc.1
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java b/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
index 0d5d496..8e78baa 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
@@ -51,6 +51,7 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebChromeClient;
import android.webkit.GeolocationPermissions.Callback;
+import android.webkit.JsPromptResult;
import android.webkit.WebSettings;
import android.webkit.WebStorage;
import android.webkit.WebView;
@@ -92,12 +93,9 @@ public class InAppBrowser extends CordovaPlugin {
* @return A PluginResult object with a status and message.
*/
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
- PluginResult.Status status = PluginResult.Status.OK;
- String result = "";
- this.callbackContext = callbackContext;
-
try {
if (action.equals("open")) {
+ this.callbackContext = callbackContext;
String url = args.getString(0);
String target = args.optString(1);
if (target == null || target.equals("") || target.equals(NULL)) {
@@ -108,6 +106,7 @@ public class InAppBrowser extends CordovaPlugin {
Log.d(LOG_TAG, "target = " + target);
url = updateUrl(url);
+ String result = "";
// SELF
if (SELF.equals(target)) {
@@ -143,35 +142,52 @@ public class InAppBrowser extends CordovaPlugin {
Log.d(LOG_TAG, "in blank");
result = this.showWebPage(url, features);
}
+
+ PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result);
+ pluginResult.setKeepCallback(true);
+ this.callbackContext.sendPluginResult(pluginResult);
}
else if (action.equals("close")) {
closeDialog();
-
- PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
- pluginResult.setKeepCallback(false);
- this.callbackContext.sendPluginResult(pluginResult);
+ this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
}
else if (action.equals("injectScriptCode")) {
- String source = args.getString(0);
-
- org.json.JSONArray jsonEsc = new org.json.JSONArray();
- jsonEsc.put(source);
- String jsonRepr = jsonEsc.toString();
- String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
- String scriptEnclosure = "(function(d){var c=d.createElement('script');c.type='text/javascript';c.innerText="
- + jsonSourceString
- + ";d.getElementsByTagName('head')[0].appendChild(c);})(document)";
- this.inAppWebView.loadUrl("javascript:" + scriptEnclosure);
-
- PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
- this.callbackContext.sendPluginResult(pluginResult);
+ String jsWrapper = null;
+ if (args.getBoolean(1)) {
+ jsWrapper = String.format("prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')", callbackContext.getCallbackId());
+ }
+ injectDeferredObject(args.getString(0), jsWrapper);
+ }
+ else if (action.equals("injectScriptFile")) {
+ String jsWrapper;
+ if (args.getBoolean(1)) {
+ jsWrapper = String.format("(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'gap-iab://%s'); }; d.body.appendChild(c); })(document)", callbackContext.getCallbackId());
+ } else {
+ jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
+ }
+ injectDeferredObject(args.getString(0), jsWrapper);
+ }
+ else if (action.equals("injectStyleCode")) {
+ String jsWrapper;
+ if (args.getBoolean(1)) {
+ jsWrapper = String.format("(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
+ } else {
+ jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
+ }
+ injectDeferredObject(args.getString(0), jsWrapper);
+ }
+ else if (action.equals("injectStyleFile")) {
+ String jsWrapper;
+ if (args.getBoolean(1)) {
+ jsWrapper = String.format("(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%s; d.head.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
+ } else {
+ jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)";
+ }
+ injectDeferredObject(args.getString(0), jsWrapper);
}
else {
- status = PluginResult.Status.INVALID_ACTION;
+ return false;
}
- PluginResult pluginResult = new PluginResult(status, result);
- pluginResult.setKeepCallback(true);
- this.callbackContext.sendPluginResult(pluginResult);
} catch (JSONException e) {
this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
}
@@ -179,6 +195,37 @@ public class InAppBrowser extends CordovaPlugin {
}
/**
+ * Inject an object (script or style) into the InAppBrowser WebView.
+ *
+ * This is a helper method for the inject{Script|Style}{Code|File} API calls, which
+ * provides a consistent method for injecting JavaScript code into the document.
+ *
+ * If a wrapper string is supplied, then the source string will be JSON-encoded (adding
+ * quotes) and wrapped using string formatting. (The wrapper string should have a single
+ * '%s' marker)
+ *
+ * @param source The source object (filename or script/style text) to inject into
+ * the document.
+ * @param jsWrapper A JavaScript string to wrap the source string in, so that the object
+ * is properly injected, or null if the source string is JavaScript text
+ * which should be executed directly.
+ */
+ private void injectDeferredObject(String source, String jsWrapper) {
+ String scriptToInject;
+ if (jsWrapper != null) {
+ org.json.JSONArray jsonEsc = new org.json.JSONArray();
+ jsonEsc.put(source);
+ String jsonRepr = jsonEsc.toString();
+ String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
+ scriptToInject = String.format(jsWrapper, jsonSourceString);
+ } else {
+ scriptToInject = source;
+ }
+ // This action will have the side-effect of blurring the currently focused element
+ this.inAppWebView.loadUrl("javascript:" + scriptToInject);
+ }
+
+ /**
* Put the list of features into a hash map
*
* @param optString
@@ -444,7 +491,7 @@ public class InAppBrowser extends CordovaPlugin {
// WebView
inAppWebView = new WebView(cordova.getActivity());
inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- inAppWebView.setWebChromeClient(new InAppChromeClient());
+ inAppWebView.setWebChromeClient(new InAppChromeClient(thatWebView));
WebViewClient client = new InAppBrowserClient(thatWebView, edittext);
inAppWebView.setWebViewClient(client);
WebSettings settings = inAppWebView.getSettings();
@@ -527,8 +574,15 @@ public class InAppBrowser extends CordovaPlugin {
result.setKeepCallback(keepCallback);
this.callbackContext.sendPluginResult(result);
}
+
public class InAppChromeClient extends WebChromeClient {
+ private CordovaWebView webView;
+
+ public InAppChromeClient(CordovaWebView webView) {
+ super();
+ this.webView = webView;
+ }
/**
* Handle database quota exceeded notification.
*
@@ -571,6 +625,57 @@ public class InAppBrowser extends CordovaPlugin {
super.onGeolocationPermissionsShowPrompt(origin, callback);
callback.invoke(origin, true, false);
}
+
+ /**
+ * Tell the client to display a prompt dialog to the user.
+ * If the client returns true, WebView will assume that the client will
+ * handle the prompt dialog and call the appropriate JsPromptResult method.
+ *
+ * The prompt bridge provided for the InAppBrowser is capable of executing any
+ * oustanding callback belonging to the InAppBrowser plugin. Care has been
+ * taken that other callbacks cannot be triggered, and that no other code
+ * execution is possible.
+ *
+ * To trigger the bridge, the prompt default value should be of the form:
+ *
+ * gap-iab://<callbackId>
+ *
+ * where <callbackId> is the string id of the callback to trigger (something
+ * like "InAppBrowser0123456789")
+ *
+ * If present, the prompt message is expected to be a JSON-encoded value to
+ * pass to the callback. A JSON_EXCEPTION is returned if the JSON is invalid.
+ *
+ * @param view
+ * @param url
+ * @param message
+ * @param defaultValue
+ * @param result
+ */
+ @Override
+ public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
+ // See if the prompt string uses the 'gap-iab' protocol. If so, the remainder should be the id of a callback to execute.
+ if (defaultValue != null && defaultValue.startsWith("gap-iab://")) {
+ PluginResult scriptResult;
+ String scriptCallbackId = defaultValue.substring(10);
+ if (scriptCallbackId.startsWith("InAppBrowser")) {
+ if(message == null || message.length() == 0) {
+ scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray());
+ } else {
+ try {
+ scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray(message));
+ } catch(JSONException e) {
+ scriptResult = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
+ }
+ }
+ this.webView.sendPluginResult(scriptResult, scriptCallbackId);
+ result.confirm("");
+ return true;
+ }
+ }
+ return false;
+ }
+
}
/**
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java b/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
index ea684a4..8a13213 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
@@ -50,13 +50,10 @@ public class NativeToJsMessageQueue {
// exec() is asynchronous. Set this to true when running bridge benchmarks.
static final boolean DISABLE_EXEC_CHAINING = false;
- // Upper limit for how much data to send to JS in one shot.
- // TODO(agrieve): This is currently disable. It should be re-enabled once we
- // remove support for returning values from exec() calls. This was
- // deprecated in 2.2.0.
- // Also, this currently only chops up on message boundaries. It may be useful
+ // Arbitrarily chosen upper limit for how much data to send to JS in one shot.
+ // This currently only chops up on message boundaries. It may be useful
// to allow it to break up messages.
- private static int MAX_PAYLOAD_SIZE = -1; //50 * 1024 * 10240;
+ private static int MAX_PAYLOAD_SIZE = 50 * 1024 * 10240;
/**
* The index into registeredListeners to treat as active.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/api/Plugin.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/Plugin.java b/lib/cordova-android/framework/src/org/apache/cordova/api/Plugin.java
deleted file mode 100755
index 72171f2..0000000
--- a/lib/cordova-android/framework/src/org/apache/cordova/api/Plugin.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- 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 org.apache.cordova.api;
-
-import org.apache.cordova.CordovaWebView;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * Legacy Plugin class. This acts as a shim to support the old execute() signature.
- * New plugins should extend CordovaPlugin directly.
- */
-@Deprecated
-public abstract class Plugin extends CordovaPlugin {
- public LegacyContext ctx; // LegacyContext object
-
- public abstract PluginResult execute(String action, JSONArray args, String callbackId);
-
- public boolean isSynch(String action) {
- return false;
- }
-
- @Override
- public void initialize(CordovaInterface cordova, CordovaWebView webView) {
- super.initialize(cordova, webView);
- this.setContext(cordova);
- this.setView(webView);
- }
-
- /**
- * Sets the context of the Plugin. This can then be used to do things like
- * get file paths associated with the Activity.
- *
- * @param ctx The context of the main Activity.
- */
- public void setContext(CordovaInterface ctx) {
- this.cordova = ctx;
- this.ctx = new LegacyContext(cordova);
- }
-
- /**
- * Sets the main View of the application, this is the WebView within which
- * a Cordova app runs.
- *
- * @param webView The Cordova WebView
- */
- public void setView(CordovaWebView webView) {
- this.webView = webView;
- }
-
- @Override
- public boolean execute(final String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException {
- final String callbackId = callbackContext.getCallbackId();
- boolean runAsync = !isSynch(action);
- if (runAsync) {
- // Run this on a different thread so that this one can return back to JS
- cordova.getThreadPool().execute(new Runnable() {
- public void run() {
- PluginResult cr;
- try {
- cr = execute(action, args, callbackId);
- } catch (Throwable e) {
- cr = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
- }
- sendPluginResult(cr, callbackId);
- }
- });
- } else {
- PluginResult cr = execute(action, args, callbackId);
-
- // Interpret a null response as NO_RESULT, which *does* clear the callbacks on the JS side.
- if (cr == null) {
- cr = new PluginResult(PluginResult.Status.NO_RESULT);
- }
-
- callbackContext.sendPluginResult(cr);
- }
- return true;
- }
-
- /**
- * Send generic JavaScript statement back to JavaScript.
- * sendPluginResult() should be used instead where possible.
- */
- public void sendJavascript(String statement) {
- this.webView.sendJavascript(statement);
- }
-
- /**
- * Send generic JavaScript statement back to JavaScript.
- */
- public void sendPluginResult(PluginResult pluginResult, String callbackId) {
- this.webView.sendPluginResult(pluginResult, callbackId);
- }
-
- /**
- * Call the JavaScript success callback for this plugin.
- *
- * This can be used if the execute code for the plugin is asynchronous meaning
- * that execute should return null and the callback from the async operation can
- * call success(...) or error(...)
- *
- * @param pluginResult The result to return.
- * @param callbackId The callback id used when calling back into JavaScript.
- */
- public void success(PluginResult pluginResult, String callbackId) {
- this.webView.sendPluginResult(pluginResult, callbackId);
- }
-
- /**
- * Helper for success callbacks that just returns the Status.OK by default
- *
- * @param message The message to add to the success result.
- * @param callbackId The callback id used when calling back into JavaScript.
- */
- public void success(JSONObject message, String callbackId) {
- this.webView.sendPluginResult(new PluginResult(PluginResult.Status.OK, message), callbackId);
- }
-
- /**
- * Helper for success callbacks that just returns the Status.OK by default
- *
- * @param message The message to add to the success result.
- * @param callbackId The callback id used when calling back into JavaScript.
- */
- public void success(String message, String callbackId) {
- this.webView.sendPluginResult(new PluginResult(PluginResult.Status.OK, message), callbackId);
- }
-
- /**
- * Call the JavaScript error callback for this plugin.
- *
- * @param pluginResult The result to return.
- * @param callbackId The callback id used when calling back into JavaScript.
- */
- public void error(PluginResult pluginResult, String callbackId) {
- this.webView.sendPluginResult(pluginResult, callbackId);
- }
-
- /**
- * Helper for error callbacks that just returns the Status.ERROR by default
- *
- * @param message The message to add to the error result.
- * @param callbackId The callback id used when calling back into JavaScript.
- */
- public void error(JSONObject message, String callbackId) {
- this.webView.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message), callbackId);
- }
-
- /**
- * Helper for error callbacks that just returns the Status.ERROR by default
- *
- * @param message The message to add to the error result.
- * @param callbackId The callback id used when calling back into JavaScript.
- */
- public void error(String message, String callbackId) {
- this.webView.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message), callbackId);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
index 774b21c..7d823cd 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
@@ -119,6 +119,7 @@ public class PluginManager {
service = xml.getAttributeValue(null, "name");
pluginClass = xml.getAttributeValue(null, "value");
// System.out.println("Plugin: "+name+" => "+value);
+ Log.d(TAG, "<plugin> tags are deprecated, please use <features> instead. <plugin> will no longer work as of Cordova 3.0");
onload = "true".equals(xml.getAttributeValue(null, "onload"));
entry = new PluginEntry(service, pluginClass, onload);
this.addService(entry);
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/.gitignore
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/.gitignore b/lib/cordova-blackberry/.gitignore
new file mode 100644
index 0000000..a67abe6
--- /dev/null
+++ b/lib/cordova-blackberry/.gitignore
@@ -0,0 +1,26 @@
+# OS X
+
+.DS_Store
+
+# Eclipse
+
+deliverables/
+.preprocessed/
+
+# Text Editor Tmp
+
+._*
+
+# Generated libraries
+
+build/
+dist/
+bin/node_modules
+bin/templates/project/lib
+example/
+
+# OS X
+
+.DS_Store
+
+tags
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/VERSION b/lib/cordova-blackberry/VERSION
index e70b452..59b7056 100644
--- a/lib/cordova-blackberry/VERSION
+++ b/lib/cordova-blackberry/VERSION
@@ -1 +1 @@
-2.6.0
+2.7.0rc1
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/bin/create
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/create b/lib/cordova-blackberry/bin/create
index b7e719b..54903b8 100755
--- a/lib/cordova-blackberry/bin/create
+++ b/lib/cordova-blackberry/bin/create
@@ -25,11 +25,15 @@ set -e
if [ -n "$1" ] && [ "$1" == "-h" ]
then
- echo 'usage: create path package appname'
- echo 'After you have created your application, make sure to customize the project.properties file inside your app directory with your environment specifics!'
- exit 0
+ echo "Usage: $0 <path_to_new_project> <package_name> <project_name>"
+ echo " <path_to_new_project>: Path to your new Cordova iOS project"
+ echo " <package_name>: Package name, following reverse-domain style convention (ignored on BlackBerry platforms)"
+ echo " <project_name>: Project name"
+ echo 'After you have created your application, make sure to customize the project.properties file inside your app directory with your environment specifics!'
+ exit 0;
fi
+
BUILD_PATH="$( cd "$( dirname "$0" )/.." && pwd )"
VERSION=$(cat "$BUILD_PATH/VERSION")
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/bin/templates/project/lib/ant-contrib/ant-contrib-1.0b3.jar
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/lib/ant-contrib/ant-contrib-1.0b3.jar b/lib/cordova-blackberry/bin/templates/project/lib/ant-contrib/ant-contrib-1.0b3.jar
deleted file mode 100644
index 0625376..0000000
Binary files a/lib/cordova-blackberry/bin/templates/project/lib/ant-contrib/ant-contrib-1.0b3.jar and /dev/null differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/bin/templates/project/www/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/www/VERSION b/lib/cordova-blackberry/bin/templates/project/www/VERSION
index e70b452..59b7056 100644
--- a/lib/cordova-blackberry/bin/templates/project/www/VERSION
+++ b/lib/cordova-blackberry/bin/templates/project/www/VERSION
@@ -1 +1 @@
-2.6.0
+2.7.0rc1
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/bin/templates/project/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/www/index.html b/lib/cordova-blackberry/bin/templates/project/www/index.html
index 4d39cf3..a56d963 100644
--- a/lib/cordova-blackberry/bin/templates/project/www/index.html
+++ b/lib/cordova-blackberry/bin/templates/project/www/index.html
@@ -33,7 +33,7 @@
<p class="event received">Device is Ready</p>
</div>
</div>
- <script type="text/javascript" src="cordova-2.6.0.js"></script>
+ <script type="text/javascript" src="cordova-2.7.0rc1.js"></script>
<script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript">
app.initialize();
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
index af39a49..c332cc4 100644
--- a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
@@ -54,7 +54,7 @@ public final class Device extends Plugin {
JSONObject device = new JSONObject();
device.put( FIELD_PLATFORM, "BlackBerry");
device.put( FIELD_UUID, new Integer( DeviceInfo.getDeviceId()) );
- device.put( FIELD_CORDOVA, "2.6.0" );
+ device.put( FIELD_CORDOVA, "2.7.0rc1" );
device.put( FIELD_MODEL, new String(DeviceInfo.getDeviceName()) );
device.put( FIELD_NAME, new String(DeviceInfo.getDeviceName()) );
device.put( FIELD_VERSION, new String(DeviceInfo.getSoftwareVersion()) );
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/javascript/cordova.blackberry.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/javascript/cordova.blackberry.js b/lib/cordova-blackberry/javascript/cordova.blackberry.js
index 86b9e8b..cd5878b 100644
--- a/lib/cordova-blackberry/javascript/cordova.blackberry.js
+++ b/lib/cordova-blackberry/javascript/cordova.blackberry.js
@@ -1,8 +1,8 @@
// Platform: blackberry
-// commit 125dca530923a44a8f44f68f5e1970cbdd4e7faf
+// commit 4808bdada2a73c3fb2ec69857b8e970414c31d57
-// File generated at :: Wed Apr 03 2013 15:26:44 GMT-0700 (PDT)
+// File generated at :: Fri Apr 19 2013 14:51:35 GMT-0700 (PDT)
/*
Licensed to the Apache Software Foundation (ASF) under one
@@ -219,6 +219,10 @@ var cordova = {
}
else {
setTimeout(function() {
+ // Fire deviceready on listeners that were registered before cordova.js was loaded.
+ if (type == 'deviceready') {
+ document.dispatchEvent(evt);
+ }
documentEventHandlers[type].fire(evt);
}, 0);
}
@@ -742,6 +746,7 @@ channel.createSticky('onDestroy');
// Channels that must fire before "deviceready" is fired.
channel.waitForInitialization('onCordovaReady');
channel.waitForInitialization('onCordovaConnectionReady');
+channel.waitForInitialization('onDOMContentLoaded');
module.exports = channel;
@@ -2222,7 +2227,7 @@ function initRead(reader, file) {
if (typeof file == 'string') {
// Deprecated in Cordova 2.4.
- console.warning('Using a string argument with FileReader.readAs functions is deprecated.');
+ console.warn('Using a string argument with FileReader.readAs functions is deprecated.');
reader._fileName = file;
} else if (typeof file.fullPath == 'string') {
reader._fileName = file.fullPath;
@@ -2580,7 +2585,7 @@ function getBasicAuthHeader(urlString) {
var origin = protocol + url.host;
// check whether there are the username:password credentials in the url
- if (url.href.indexOf(origin) != 0) { // credentials found
+ if (url.href.indexOf(origin) !== 0) { // credentials found
var atIndex = url.href.indexOf("@");
credentials = url.href.substring(protocol.length, atIndex);
}
@@ -2629,15 +2634,11 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
var params = null;
var chunkedMode = true;
var headers = null;
-
+ var httpMethod = null;
var basicAuthHeader = getBasicAuthHeader(server);
if (basicAuthHeader) {
- if (!options) {
- options = new FileUploadOptions();
- }
- if (!options.headers) {
- options.headers = {};
- }
+ options = options || {};
+ options.headers = options.headers || {};
options.headers[basicAuthHeader.name] = basicAuthHeader.value;
}
@@ -2646,6 +2647,12 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
fileName = options.fileName;
mimeType = options.mimeType;
headers = options.headers;
+ httpMethod = options.httpMethod || "POST";
+ if (httpMethod.toUpperCase() == "PUT"){
+ httpMethod = "PUT";
+ } else {
+ httpMethod = "POST";
+ }
if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") {
chunkedMode = options.chunkedMode;
}
@@ -2672,7 +2679,7 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
successCallback && successCallback(result);
}
};
- exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id]);
+ exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
};
/**
@@ -2690,12 +2697,8 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
var basicAuthHeader = getBasicAuthHeader(source);
if (basicAuthHeader) {
- if (!options) {
- options = {};
- }
- if (!options.headers) {
- options.headers = {};
- }
+ options = options || {};
+ options.headers = options.headers || {};
options.headers[basicAuthHeader.name] = basicAuthHeader.value;
}
@@ -2734,12 +2737,11 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
};
/**
- * 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
+ * Aborts the ongoing file transfer on this object. The original error
+ * callback for the file transfer will be called if necessary.
*/
-FileTransfer.prototype.abort = function(successCallback, errorCallback) {
- exec(successCallback, errorCallback, 'FileTransfer', 'abort', [this._id]);
+FileTransfer.prototype.abort = function() {
+ exec(null, null, 'FileTransfer', 'abort', [this._id]);
};
module.exports = FileTransfer;
@@ -2783,12 +2785,13 @@ define("cordova/plugin/FileUploadOptions", function(require, exports, module) {
* @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) {
+var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers, httpMethod) {
this.fileKey = fileKey || null;
this.fileName = fileName || null;
this.mimeType = mimeType || null;
this.params = params || null;
this.headers = headers || null;
+ this.httpMethod = httpMethod || null;
};
module.exports = FileUploadOptions;
@@ -3123,6 +3126,7 @@ define("cordova/plugin/InAppBrowser", function(require, exports, module) {
var exec = require('cordova/exec');
var channel = require('cordova/channel');
+var modulemapper = require('cordova/modulemapper');
function InAppBrowser() {
this.channels = {
@@ -3151,6 +3155,26 @@ InAppBrowser.prototype = {
if (eventname in this.channels) {
this.channels[eventname].unsubscribe(f);
}
+ },
+
+ executeScript: function(injectDetails, cb) {
+ if (injectDetails.code) {
+ exec(cb, null, "InAppBrowser", "injectScriptCode", [injectDetails.code, !!cb]);
+ } else if (injectDetails.file) {
+ exec(cb, null, "InAppBrowser", "injectScriptFile", [injectDetails.file, !!cb]);
+ } else {
+ throw new Error('executeScript requires exactly one of code or file to be specified');
+ }
+ },
+
+ insertCSS: function(injectDetails, cb) {
+ if (injectDetails.code) {
+ exec(cb, null, "InAppBrowser", "injectStyleCode", [injectDetails.code, !!cb]);
+ } else if (injectDetails.file) {
+ exec(cb, null, "InAppBrowser", "injectStyleFile", [injectDetails.file, !!cb]);
+ } else {
+ throw new Error('insertCSS requires exactly one of code or file to be specified');
+ }
}
};
@@ -3159,6 +3183,13 @@ module.exports = function(strUrl, strWindowName, strWindowFeatures) {
var cb = function(eventname) {
iab._eventHandler(eventname);
};
+
+ // Don't catch calls that write to existing frames (e.g. named iframes).
+ if (window.frames && window.frames[strWindowName]) {
+ var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
+ return origOpenFunc.apply(window, arguments);
+ }
+
exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
return iab;
};
@@ -5361,7 +5392,7 @@ module.exports = {
model: "PlayBook",
name: "PlayBook", // deprecated: please use device.model
uuid: info.uuid,
- cordova: "2.6.0"
+ cordova: "2.7.0rc1"
});
}),
request = new blackberry.transport.RemoteFunctionCall("org/apache/cordova/getDeviceInfo");
@@ -6018,7 +6049,7 @@ console.debug = function() {
console.assert = function(expression) {
if (expression) return;
- var message = utils.vformat(arguments[1], [].slice.call(arguments, 2));
+ var message = logger.format.apply(logger.format, [].slice.call(arguments, 1));
console.log("ASSERT: " + message);
};
@@ -8669,10 +8700,10 @@ function logWithArgs(level, args) {
* Parameters passed after message are used applied to
* the message with utils.format()
*/
-logger.logLevel = function(level, message /* , ... */) {
+logger.logLevel = function(level /* , ... */) {
// format the message with the parameters
- var formatArgs = [].slice.call(arguments, 2);
- message = utils.vformat(message, formatArgs);
+ var formatArgs = [].slice.call(arguments, 1);
+ var message = logger.format.apply(logger.format, formatArgs);
if (LevelsMap[level] === null) {
throw new Error("invalid logging level: " + level);
@@ -8707,6 +8738,92 @@ logger.logLevel = function(level, message /* , ... */) {
}
};
+
+/**
+ * Formats a string and arguments following it ala console.log()
+ *
+ * Any remaining arguments will be appended to the formatted string.
+ *
+ * for rationale, see FireBug's Console API:
+ * http://getfirebug.com/wiki/index.php/Console_API
+ */
+logger.format = function(formatString, args) {
+ return __format(arguments[0], [].slice.call(arguments,1)).join(' ');
+};
+
+
+//------------------------------------------------------------------------------
+/**
+ * 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().
+ *
+ * Returns an array containing the formatted string and any remaining
+ * arguments.
+ */
+function __format(formatString, args) {
+ if (formatString === null || formatString === undefined) return [""];
+ if (arguments.length == 1) return [formatString.toString()];
+
+ if (typeof formatString != "string")
+ formatString = formatString.toString();
+
+ var pattern = /(.*?)%(.)(.*)/;
+ var rest = formatString;
+ var result = [];
+
+ while (args.length) {
+ var match = pattern.exec(rest);
+ if (!match) break;
+
+ var arg = args.shift();
+ 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);
+
+ var remainingArgs = [].slice.call(args);
+ remainingArgs.unshift(result.join(''));
+ return remainingArgs;
+}
+
+function __formatted(object, formatChar) {
+
+ try {
+ switch(formatChar) {
+ case 'j':
+ case 'o': return JSON.stringify(object);
+ case 'c': return '';
+ }
+ }
+ catch (e) {
+ return "error JSON.stringify()ing argument: " + e;
+ }
+
+ if ((object === null) || (object === undefined)) {
+ return Object.prototype.toString.call(object);
+ }
+
+ return object.toString();
+}
+
+
+//------------------------------------------------------------------------------
// when deviceready fires, log queued messages
logger.__onDeviceReady = function() {
if (DeviceReady) return;
@@ -8875,13 +8992,13 @@ module.exports = {
console.log("Notification.confirm(string, function, string, string) is deprecated. Use Notification.confirm(string, function, string, array).");
}
- // Android and iOS take an array of button label names.
+ // Some platforms take an array of button label names.
// Other platforms take a comma separated list.
// For compatibility, we convert to the desired type based on the platform.
- if (platform.id == "android" || platform.id == "ios") {
+ if (platform.id == "android" || platform.id == "ios" || platform.id == "windowsphone") {
if (typeof _buttonLabels === 'string') {
var buttonLabelString = _buttonLabels;
- _buttonLabels = buttonLabelString.split(",");
+ _buttonLabels = _buttonLabels.split(","); // not crazy about changing the var type here
}
} else {
if (Array.isArray(_buttonLabels)) {
@@ -9290,7 +9407,7 @@ module.exports = {
model: "Dev Alpha",
name: "Dev Alpha", // deprecated: please use device.model
uuid: blackberry.identity.uuid,
- cordova: "2.6.0"
+ cordova: "2.7.0rc1"
});
return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "Device info returned" };
@@ -9303,6 +9420,7 @@ module.exports = {
define("cordova/plugin/qnx/file", function(require, exports, module) {
/*global WebKitBlobBuilder:false */
+/*global Blob:false */
var cordova = require('cordova'),
FileError = require('cordova/plugin/FileError'),
DirectoryEntry = require('cordova/plugin/DirectoryEntry'),
@@ -9710,6 +9828,7 @@ module.exports = {
// file: lib/blackberry/plugin/qnx/fileTransfer.js
define("cordova/plugin/qnx/fileTransfer", function(require, exports, module) {
+/*global Blob:false */
var cordova = require('cordova'),
FileEntry = require('cordova/plugin/FileEntry'),
FileTransferError = require('cordova/plugin/FileTransferError'),
@@ -10566,62 +10685,6 @@ utils.alert = function(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) {
@@ -10636,26 +10699,6 @@ function UUIDcreatePart(length) {
return uuidpart;
}
-//------------------------------------------------------------------------------
-function formatted(object, formatChar) {
-
- try {
- switch(formatChar) {
- case 'j':
- case 'o': return JSON.stringify(object);
- case 'c': return '';
- }
- }
- catch (e) {
- return "error JSON.stringify()ing argument: " + e;
- }
-
- if ((object === null) || (object === undefined)) {
- return Object.prototype.toString.call(object);
- }
-
- return object.toString();
-}
});
@@ -10665,6 +10708,25 @@ window.cordova = require('cordova');
// file: lib/scripts/bootstrap.js
(function (context) {
+ var channel = require('cordova/channel');
+ var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];
+
+ function logUnfiredChannels(arr) {
+ for (var i = 0; i < arr.length; ++i) {
+ if (arr[i].state != 2) {
+ console.log('Channel not fired: ' + arr[i].type);
+ }
+ }
+ }
+
+ window.setTimeout(function() {
+ if (channel.onDeviceReady.state != 2) {
+ console.log('deviceready has not fired after 5 seconds.');
+ logUnfiredChannels(platformInitChannelsArray);
+ logUnfiredChannels(channel.deviceReadyChannelsArray);
+ }
+ }, 5000);
+
// Replace navigator before any modules are required(), to ensure it happens as soon as possible.
// We replace it so that properties that can't be clobbered can instead be overridden.
function replaceNavigator(origNavigator) {
@@ -10686,8 +10748,6 @@ window.cordova = require('cordova');
context.navigator = replaceNavigator(context.navigator);
}
- var channel = require("cordova/channel");
-
// _nativeReady is global variable that the native side can set
// to signify that the native code is ready. It is a global since
// it may be called before any cordova JS is ready.
@@ -10696,29 +10756,26 @@ window.cordova = require('cordova');
}
/**
- * Create all cordova objects once page has fully loaded and native side is ready.
+ * Create all cordova objects once native side is ready.
*/
channel.join(function() {
- var builder = require('cordova/builder'),
- platform = require('cordova/platform');
-
- builder.buildIntoButDoNotClobber(platform.defaults, context);
- builder.buildIntoAndClobber(platform.clobbers, context);
- builder.buildIntoAndMerge(platform.merges, context);
-
// Call the platform-specific initialization
- platform.initialize();
+ require('cordova/platform').initialize();
// Fire event to notify that all objects are created
channel.onCordovaReady.fire();
- // Fire onDeviceReady event once all constructors have run and
- // cordova info has been received from native side.
+ // Fire onDeviceReady event once page has fully loaded, all
+ // constructors have run and cordova info has been received from native
+ // side.
+ // This join call is deliberately made after platform.initialize() in
+ // order that plugins may manipulate channel.deviceReadyChannelsArray
+ // if necessary.
channel.join(function() {
require('cordova').fireDocumentEvent('deviceready');
}, channel.deviceReadyChannelsArray);
- }, [ channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady ]);
+ }, platformInitChannelsArray);
}(window));
@@ -10823,31 +10880,27 @@ document.addEventListener("DOMContentLoaded", function () {
}
}
+
// Try to XHR the cordova_plugins.json file asynchronously.
- try { // we commented we were going to try, so let us actually try and catch
+ try { // we commented we were going to try, so let us actually try and catch
var xhr = new context.XMLHttpRequest();
- xhr.onreadystatechange = function() {
- if (this.readyState != 4) { // not DONE
- return;
- }
-
+ xhr.onload = function() {
// If the response is a JSON string which composes an array, call handlePluginsObject.
// If the request fails, or the response is not a JSON array, just call finishPluginLoading.
- if (this.status == 200) {
- var obj = JSON.parse(this.responseText);
- if (obj && obj instanceof Array && obj.length > 0) {
- handlePluginsObject(obj);
- } else {
- finishPluginLoading();
- }
+ var obj = JSON.parse(this.responseText);
+ if (obj && obj instanceof Array && obj.length > 0) {
+ handlePluginsObject(obj);
} else {
finishPluginLoading();
}
};
+ xhr.onerror = function() {
+ finishPluginLoading();
+ };
xhr.open('GET', 'cordova_plugins.json', true); // Async
xhr.send();
}
- catch(err) {
+ catch(err){
finishPluginLoading();
}
}(window));
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/.gitignore
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/.gitignore b/lib/cordova-ios/.gitignore
new file mode 100644
index 0000000..e0ac686
--- /dev/null
+++ b/lib/cordova-ios/.gitignore
@@ -0,0 +1,12 @@
+.DS_Store
+.*.sw?
+*.cso
+tmp
+*.mode1v3
+*.pbxuser
+build
+*.xcworkspace
+xcuserdata
+CordovaLib/javascript/cordova-*.js
+CordovaLib/CordovaLibApp/www/cordova.ios.js
+console.log
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/.gitmodules
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/.gitmodules b/lib/cordova-ios/.gitmodules
new file mode 100644
index 0000000..3625844
--- /dev/null
+++ b/lib/cordova-ios/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "PhoneGapLibTest/www"]
+ path = PhoneGapLibTest/www
+ url = git://github.com/phonegap/mobile-spec.git
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDV.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDV.h b/lib/cordova-ios/CordovaLib/Classes/CDV.h
index 5a0ae6a..15d9316 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDV.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDV.h
@@ -33,7 +33,6 @@
#import "CDVContact.h"
#import "CDVContacts.h"
#import "CDVDebug.h"
-#import "CDVDebugConsole.h"
#import "CDVDevice.h"
#import "CDVFile.h"
#import "CDVFileTransfer.h"
@@ -47,6 +46,7 @@
#import "CDVLocalStorage.h"
#import "CDVInAppBrowser.h"
#import "CDVScreenOrientationDelegate.h"
+#import "CDVTimer.h"
#import "NSArray+Comparisons.h"
#import "NSData+Base64.h"
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h b/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
index 947ae2d..b288522 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
@@ -40,6 +40,7 @@
#define __CORDOVA_2_4_0 20400
#define __CORDOVA_2_5_0 20500
#define __CORDOVA_2_6_0 20600
+#define __CORDOVA_2_7_0 20700
#define __CORDOVA_NA 99999 /* not available */
/*
@@ -50,7 +51,7 @@
#endif
*/
#ifndef CORDOVA_VERSION_MIN_REQUIRED
- #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_6_0
+ #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_7_0
#endif
/*
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.h b/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.h
deleted file mode 100644
index 6a0a185..0000000
--- a/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- 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.
- */
-
-#import <Foundation/Foundation.h>
-#import <UIKit/UIKit.h>
-#import "CDVPlugin.h"
-
-@interface CDVDebugConsole : CDVPlugin {}
-
-- (void)log:(CDVInvokedUrlCommand*)command;
-
-@end
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.m b/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.m
deleted file mode 100644
index 29cbb91..0000000
--- a/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.m
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- 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.
- */
-
-#import "CDVDebugConsole.h"
-
-@implementation CDVDebugConsole
-
-- (void)log:(CDVInvokedUrlCommand*)command
-{
- NSString* message = [command.arguments objectAtIndex:0];
- NSDictionary* options = [command.arguments objectAtIndex:1];
- NSString* log_level = @"INFO";
-
- if ([options objectForKey:@"logLevel"]) {
- log_level = [options objectForKey:@"logLevel"];
- }
-
- NSLog(@"[%@] %@", log_level, message);
-}
-
-@end
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFile.m b/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
index 8c65270..10908ce 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
@@ -227,10 +227,9 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
NSURL* testUri = [NSURL URLWithString:strUri];
CDVPluginResult* result = nil;
- if (!testUri || ![testUri isFileURL]) {
- // issue ENCODING_ERR
+ if (!testUri) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR];
- } else {
+ } else if ([testUri isFileURL]) {
NSFileManager* fileMgr = [[NSFileManager alloc] init];
NSString* path = [testUri path];
// NSLog(@"url path: %@", path);
@@ -262,7 +261,13 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
// return NOT_FOUND_ERR
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
}
+ } else if ([strUri hasPrefix:@"assets-library://"]) {
+ NSDictionary* fileSystem = [self getDirectoryEntry:strUri isDirectory:NO];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
+ } else {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR];
}
+
if (result != nil) {
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
index d82cdd3..233a114 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
@@ -53,10 +53,15 @@ extern NSString* const kOptionsKeyCookie;
AndHttpStatus:(int)httpStatus
AndBody:(NSString*)body;
@property (readonly) NSMutableDictionary* activeTransfers;
+@property (nonatomic, assign) UIBackgroundTaskIdentifier backgroundTaskID;
@end
+@class CDVFileTransferEntityLengthRequest;
+
@interface CDVFileTransferDelegate : NSObject {}
+- (void)updateBytesExpected:(NSInteger)newBytesExpected;
+
@property (strong) NSMutableData* responseData; // atomic
@property (nonatomic, strong) CDVFileTransfer* command;
@property (nonatomic, assign) CDVFileTransferDirection direction;
@@ -70,5 +75,7 @@ extern NSString* const kOptionsKeyCookie;
@property (nonatomic, assign) NSInteger bytesTransfered;
@property (nonatomic, assign) NSInteger bytesExpected;
@property (nonatomic, assign) BOOL trustAllHosts;
+@property (strong) NSFileHandle* targetFileHandle;
+@property (nonatomic, strong) CDVFileTransferEntityLengthRequest* entityLengthRequest;
@end;
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
index 5741aca..5536715 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
@@ -126,17 +126,19 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
// arguments order from js: [filePath, server, fileKey, fileName, mimeType, params, debug, chunkedMode]
// however, params is a JavaScript object and during marshalling is put into the options dict,
// thus debug and chunkedMode are the 6th and 7th arguments
- NSArray* arguments = command.arguments;
- NSString* target = (NSString*)[arguments objectAtIndex:0];
- NSString* server = (NSString*)[arguments objectAtIndex:1];
- NSString* fileKey = [arguments objectAtIndex:2 withDefault:@"file"];
- NSString* fileName = [arguments objectAtIndex:3 withDefault:@"no-filename"];
- NSString* mimeType = [arguments objectAtIndex:4 withDefault:nil];
- NSDictionary* options = [arguments objectAtIndex:5 withDefault:nil];
+ NSString* target = [command argumentAtIndex:0];
+ NSString* server = [command argumentAtIndex:1];
+ NSString* fileKey = [command argumentAtIndex:2 withDefault:@"file"];
+ NSString* fileName = [command argumentAtIndex:3 withDefault:@"no-filename"];
+ NSString* mimeType = [command argumentAtIndex:4 withDefault:nil];
+ NSDictionary* options = [command argumentAtIndex:5 withDefault:nil];
// BOOL trustAllHosts = [[arguments objectAtIndex:6 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs
- BOOL chunkedMode = [[arguments objectAtIndex:7 withDefault:[NSNumber numberWithBool:YES]] boolValue];
- NSDictionary* headers = [arguments objectAtIndex:8 withDefault:nil];
-
+ BOOL chunkedMode = [[command argumentAtIndex:7 withDefault:[NSNumber numberWithBool:YES]] boolValue];
+ NSDictionary* headers = [command argumentAtIndex:8 withDefault:nil];
+ // Allow alternative http method, default to POST. JS side checks
+ // for allowed methods, currently PUT or POST (forces POST for
+ // unrecognised values)
+ NSString* httpMethod = [command argumentAtIndex:10 withDefault:@"POST"];
CDVPluginResult* result = nil;
CDVFileTransferError errorCode = 0;
@@ -158,7 +160,8 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
}
NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url];
- [req setHTTPMethod:@"POST"];
+
+ [req setHTTPMethod:httpMethod];
// Magic value to set a cookie
if ([options objectForKey:kOptionsKeyCookie]) {
@@ -212,6 +215,12 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
CFStreamCreateBoundPair(NULL, &readStream, &writeStream, kStreamBufferSize);
[req setHTTPBodyStream:CFBridgingRelease(readStream)];
+ self.backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
+ [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskID];
+ self.backgroundTaskID = UIBackgroundTaskInvalid;
+ NSLog(@"Background task to upload media finished.");
+ }];
+
[self.commandDelegate runInBackground:^{
if (CFWriteStreamOpen(writeStream)) {
NSData* chunks[] = {postBodyBeforeFile, fileData, postBodyAfterFile};
@@ -456,19 +465,56 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
@end
+@interface CDVFileTransferEntityLengthRequest : NSObject {
+ NSURLConnection* _connection;
+ CDVFileTransferDelegate* __weak _originalDelegate;
+}
+
+- (CDVFileTransferEntityLengthRequest*)initWithOriginalRequest:(NSURLRequest*)originalRequest andDelegate:(CDVFileTransferDelegate*)originalDelegate;
+
+@end;
+
+@implementation CDVFileTransferEntityLengthRequest;
+
+- (CDVFileTransferEntityLengthRequest*)initWithOriginalRequest:(NSURLRequest*)originalRequest andDelegate:(CDVFileTransferDelegate*)originalDelegate
+{
+ if (self) {
+ DLog(@"Requesting entity length for GZIPped content...");
+
+ NSMutableURLRequest* req = [originalRequest mutableCopy];
+ [req setHTTPMethod:@"HEAD"];
+ [req setValue:@"identity" forHTTPHeaderField:@"Accept-Encoding"];
+
+ _originalDelegate = originalDelegate;
+ _connection = [NSURLConnection connectionWithRequest:req delegate:self];
+ }
+ return self;
+}
+
+- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
+{
+ DLog(@"HEAD request returned; content-length is %lld", [response expectedContentLength]);
+ [_originalDelegate updateBytesExpected:[response expectedContentLength]];
+}
+
+- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
+{}
+
+- (void)connectionDidFinishLoading:(NSURLConnection*)connection
+{}
+
+@end
+
@implementation CDVFileTransferDelegate
-@synthesize callbackId, connection, source, target, responseData, command, bytesTransfered, bytesExpected, direction, responseCode, objectId;
+@synthesize callbackId, connection = _connection, source, target, responseData, command, bytesTransfered, bytesExpected, direction, responseCode, objectId, targetFileHandle;
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
NSString* uploadResponse = nil;
NSString* downloadResponse = nil;
- BOOL downloadWriteOK = NO;
NSMutableDictionary* uploadResult;
CDVPluginResult* result = nil;
- NSError* __autoreleasing error = nil;
- NSString* parentPath;
BOOL bDirRequest = NO;
CDVFile* file;
@@ -491,40 +537,15 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
}
}
if (self.direction == CDV_TRANSFER_DOWNLOAD) {
- DLog(@"Write file %@", target);
- // error=[[NSError alloc]init];
-
- if ((self.responseCode >= 200) && (self.responseCode < 300)) {
- @try {
- parentPath = [self.target stringByDeletingLastPathComponent];
-
- // check if the path exists => create directories if needed
- if (![[NSFileManager defaultManager] fileExistsAtPath:parentPath]) {
- [[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:nil];
- }
-
- downloadWriteOK = [self.responseData writeToFile:self.target options:NSDataWritingFileProtectionNone error:&error];
+ if (self.targetFileHandle) {
+ [self.targetFileHandle closeFile];
+ self.targetFileHandle = nil;
+ DLog(@"File Transfer Download success");
- if (downloadWriteOK == NO) {
- // send our results back
- downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:INVALID_URL_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]];
- } else {
- DLog(@"File Transfer Download success");
-
- file = [[CDVFile alloc] init];
-
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[file getDirectoryEntry:target isDirectory:bDirRequest]];
- }
- }
- @catch(id exception) {
- // jump back to main thread
- downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsDictionary:[command createFileTransferError:FILE_NOT_FOUND_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]];
- }
+ file = [[CDVFile alloc] init];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[file getDirectoryEntry:target isDirectory:bDirRequest]];
} else {
downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
-
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]];
}
}
@@ -533,11 +554,28 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
// remove connection for activeTransfers
[command.activeTransfers removeObjectForKey:objectId];
+
+ // remove background id task in case our upload was done in the background
+ [[UIApplication sharedApplication] endBackgroundTask:self.command.backgroundTaskID];
+ self.command.backgroundTaskID = UIBackgroundTaskInvalid;
+}
+
+- (void)cancelTransferWithError:(NSURLConnection*)connection errorMessage:(NSString*)errorMessage
+{
+ CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsDictionary:[self.command createFileTransferError:FILE_NOT_FOUND_ERR AndSource:self.source AndTarget:self.target AndHttpStatus:self.responseCode AndBody:errorMessage]];
+
+ NSLog(@"File Transfer Error: %@", errorMessage);
+ [connection cancel];
+ [self.command.activeTransfers removeObjectForKey:self.objectId];
+ [self.command.commandDelegate sendPluginResult:result callbackId:callbackId];
}
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
{
+ NSError* __autoreleasing error = nil;
+
self.mimeType = [response MIMEType];
+ self.targetFileHandle = nil;
// required for iOS 4.3, for some reason; response is
// a plain NSURLResponse, not the HTTP subclass
@@ -546,6 +584,11 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
self.responseCode = [httpResponse statusCode];
self.bytesExpected = [response expectedContentLength];
+ if ((self.direction == CDV_TRANSFER_DOWNLOAD) && (self.responseCode == 200) && (self.bytesExpected == NSURLResponseUnknownLength)) {
+ // Kick off HEAD request to server to get real length
+ // bytesExpected will be updated when that response is returned
+ self.entityLengthRequest = [[CDVFileTransferEntityLengthRequest alloc] initWithOriginalRequest:connection.currentRequest andDelegate:self];
+ }
} else if ([response.URL isFileURL]) {
NSDictionary* attr = [[NSFileManager defaultManager] attributesOfItemAtPath:[response.URL path] error:nil];
self.responseCode = 200;
@@ -554,6 +597,31 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
self.responseCode = 200;
self.bytesExpected = NSURLResponseUnknownLength;
}
+ if ((self.direction == CDV_TRANSFER_DOWNLOAD) && (self.responseCode >= 200) && (self.responseCode < 300)) {
+ // Download response is okay; begin streaming output to file
+ NSString* parentPath = [self.target stringByDeletingLastPathComponent];
+
+ // create parent directories if needed
+ if ([[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:&error] == NO) {
+ if (error) {
+ [self cancelTransferWithError:connection errorMessage:[NSString stringWithFormat:@"Could not create path to save downloaded file: %@", [error localizedDescription]]];
+ } else {
+ [self cancelTransferWithError:connection errorMessage:@"Could not create path to save downloaded file"];
+ }
+ return;
+ }
+ // create target file
+ if ([[NSFileManager defaultManager] createFileAtPath:self.target contents:nil attributes:nil] == NO) {
+ [self cancelTransferWithError:connection errorMessage:@"Could not create target file"];
+ return;
+ }
+ // open target file for writing
+ self.targetFileHandle = [NSFileHandle fileHandleForWritingAtPath:self.target];
+ if (self.targetFileHandle == nil) {
+ [self cancelTransferWithError:connection errorMessage:@"Could not open target file for writing"];
+ }
+ DLog(@"Streaming to file %@", target);
+ }
}
- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
@@ -571,10 +639,30 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
{
self.bytesTransfered += data.length;
- [self.responseData appendData:data];
+ if (self.targetFileHandle) {
+ [self.targetFileHandle writeData:data];
+ } else {
+ [self.responseData appendData:data];
+ }
+ [self updateProgress];
+}
+
+- (void)updateBytesExpected:(NSInteger)newBytesExpected
+{
+ DLog(@"Updating bytesExpected to %d", newBytesExpected);
+ self.bytesExpected = newBytesExpected;
+ [self updateProgress];
+}
+- (void)updateProgress
+{
if (self.direction == CDV_TRANSFER_DOWNLOAD) {
BOOL lengthComputable = (self.bytesExpected != NSURLResponseUnknownLength);
+ // If the response is GZipped, and we have an outstanding HEAD request to get
+ // the length, then hold off on sending progress events.
+ if (!lengthComputable && (self.entityLengthRequest != nil)) {
+ return;
+ }
NSMutableDictionary* downloadProgress = [NSMutableDictionary dictionaryWithCapacity:3];
[downloadProgress setObject:[NSNumber numberWithBool:lengthComputable] forKey:@"lengthComputable"];
[downloadProgress setObject:[NSNumber numberWithInt:self.bytesTransfered] forKey:@"loaded"];
@@ -618,6 +706,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
{
if ((self = [super init])) {
self.responseData = [NSMutableData data];
+ self.targetFileHandle = nil;
}
return self;
}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
index f63250a..343f40d 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
@@ -24,28 +24,21 @@
@class CDVInAppBrowserViewController;
-@protocol CDVInAppBrowserNavigationDelegate <NSObject>
-
-- (void)browserLoadStart:(NSURL*)url;
-- (void)browserLoadStop:(NSURL*)url;
-- (void)browserLoadError:(NSError*)error forUrl:(NSURL*)url;
-- (void)browserExit;
-
-@end
-
-@interface CDVInAppBrowser : CDVPlugin <CDVInAppBrowserNavigationDelegate>
+@interface CDVInAppBrowser : CDVPlugin {
+ BOOL _injectedIframeBridge;
+}
@property (nonatomic, retain) CDVInAppBrowserViewController* inAppBrowserViewController;
@property (nonatomic, copy) NSString* callbackId;
- (void)open:(CDVInvokedUrlCommand*)command;
- (void)close:(CDVInvokedUrlCommand*)command;
+- (void)injectScriptCode:(CDVInvokedUrlCommand*)command;
@end
@interface CDVInAppBrowserViewController : UIViewController <UIWebViewDelegate>{
@private
- NSURL* _requestedURL;
NSString* _userAgent;
NSString* _prevUserAgent;
NSInteger _userAgentLockToken;
@@ -61,7 +54,8 @@
@property (nonatomic, strong) IBOutlet UIToolbar* toolbar;
@property (nonatomic, weak) id <CDVScreenOrientationDelegate> orientationDelegate;
-@property (nonatomic, weak) id <CDVInAppBrowserNavigationDelegate> navigationDelegate;
+@property (nonatomic, weak) CDVInAppBrowser* navigationDelegate;
+@property (nonatomic) NSURL* requestedURL;
- (void)close;
- (void)navigateTo:(NSURL*)url;
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
index d001dfd..f366bd8 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
@@ -20,6 +20,7 @@
#import "CDVInAppBrowser.h"
#import "CDVPluginResult.h"
#import "CDVUserAgentUtil.h"
+#import "CDVJSON.h"
#define kInAppBrowserTargetSelf @"_self"
#define kInAppBrowserTargetSystem @"_system"
@@ -159,35 +160,161 @@
}
}
-#pragma mark CDVInAppBrowserNavigationDelegate
+// This is a helper method for the inject{Script|Style}{Code|File} API calls, which
+// provides a consistent method for injecting JavaScript code into the document.
+//
+// If a wrapper string is supplied, then the source string will be JSON-encoded (adding
+// quotes) and wrapped using string formatting. (The wrapper string should have a single
+// '%@' marker).
+//
+// If no wrapper is supplied, then the source string is executed directly.
-- (void)browserLoadStart:(NSURL*)url
+- (void)injectDeferredObject:(NSString*)source withWrapper:(NSString*)jsWrapper
{
+ if (!_injectedIframeBridge) {
+ _injectedIframeBridge = YES;
+ // Create an iframe bridge in the new document to communicate with the CDVInAppBrowserViewController
+ [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:@"(function(d){var e = _cdvIframeBridge = d.createElement('iframe');e.style.display='none';d.body.appendChild(e);})(document)"];
+ }
+
+ if (jsWrapper != nil) {
+ NSString* sourceArrayString = [@[source] JSONString];
+ if (sourceArrayString) {
+ NSString* sourceString = [sourceArrayString substringWithRange:NSMakeRange(1, [sourceArrayString length] - 2)];
+ NSString* jsToInject = [NSString stringWithFormat:jsWrapper, sourceString];
+ [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:jsToInject];
+ }
+ } else {
+ [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:source];
+ }
+}
+
+- (void)injectScriptCode:(CDVInvokedUrlCommand*)command
+{
+ NSString* jsWrapper = nil;
+
+ if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) {
+ jsWrapper = [NSString stringWithFormat:@"_cdvIframeBridge.src='gap-iab://%@/'+window.escape(JSON.stringify([eval(%%@)]));", command.callbackId];
+ }
+ [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper];
+}
+
+- (void)injectScriptFile:(CDVInvokedUrlCommand*)command
+{
+ NSString* jsWrapper;
+
+ if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) {
+ jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('script'); c.src = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId];
+ } else {
+ jsWrapper = @"(function(d) { var c = d.createElement('script'); c.src = %@; d.body.appendChild(c); })(document)";
+ }
+ [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper];
+}
+
+- (void)injectStyleCode:(CDVInvokedUrlCommand*)command
+{
+ NSString* jsWrapper;
+
+ if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) {
+ jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('style'); c.innerHTML = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId];
+ } else {
+ jsWrapper = @"(function(d) { var c = d.createElement('style'); c.innerHTML = %@; d.body.appendChild(c); })(document)";
+ }
+ [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper];
+}
+
+- (void)injectStyleFile:(CDVInvokedUrlCommand*)command
+{
+ NSString* jsWrapper;
+
+ if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) {
+ jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId];
+ } else {
+ jsWrapper = @"(function(d) { var c = d.createElement('link'); c.rel='stylesheet', c.type='text/css'; c.href = %@; d.body.appendChild(c); })(document)";
+ }
+ [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper];
+}
+
+/**
+ * The iframe bridge provided for the InAppBrowser is capable of executing any oustanding callback belonging
+ * to the InAppBrowser plugin. Care has been taken that other callbacks cannot be triggered, and that no
+ * other code execution is possible.
+ *
+ * To trigger the bridge, the iframe (or any other resource) should attempt to load a url of the form:
+ *
+ * gap-iab://<callbackId>/<arguments>
+ *
+ * where <callbackId> is the string id of the callback to trigger (something like "InAppBrowser0123456789")
+ *
+ * If present, the path component of the special gap-iab:// url is expected to be a URL-escaped JSON-encoded
+ * value to pass to the callback. [NSURL path] should take care of the URL-unescaping, and a JSON_EXCEPTION
+ * is returned if the JSON is invalid.
+ */
+- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
+{
+ NSURL* url = request.URL;
+
+ // See if the url uses the 'gap-iab' protocol. If so, the host should be the id of a callback to execute,
+ // and the path, if present, should be a JSON-encoded value to pass to the callback.
+ if ([[url scheme] isEqualToString:@"gap-iab"]) {
+ NSString* scriptCallbackId = [url host];
+ CDVPluginResult* pluginResult = nil;
+
+ if ([scriptCallbackId hasPrefix:@"InAppBrowser"]) {
+ NSString* scriptResult = [url path];
+ NSError* __autoreleasing error = nil;
+
+ // The message should be a JSON-encoded array of the result of the script which executed.
+ if ((scriptResult != nil) && ([scriptResult length] > 1)) {
+ scriptResult = [scriptResult substringFromIndex:1];
+ NSData* decodedResult = [NSJSONSerialization JSONObjectWithData:[scriptResult dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error];
+ if ((error == nil) && [decodedResult isKindOfClass:[NSArray class]]) {
+ pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:(NSArray*)decodedResult];
+ } else {
+ pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_JSON_EXCEPTION];
+ }
+ } else {
+ pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:@[]];
+ }
+ [self.commandDelegate sendPluginResult:pluginResult callbackId:scriptCallbackId];
+ return NO;
+ }
+ }
+ return YES;
+}
+
+- (void)webViewDidStartLoad:(UIWebView*)theWebView
+{
+ _injectedIframeBridge = NO;
if (self.callbackId != nil) {
+ NSString* url = [[self.inAppBrowserViewController requestedURL] absoluteString];
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
- messageAsDictionary:@{@"type":@"loadstart", @"url":[url absoluteString]}];
+ messageAsDictionary:@{@"type":@"loadstart", @"url":url}];
[pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
[self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
}
}
-- (void)browserLoadStop:(NSURL*)url
+- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{
if (self.callbackId != nil) {
+ // TODO: It would be more useful to return the URL the page is actually on (e.g. if it's been redirected).
+ NSString* url = [[self.inAppBrowserViewController requestedURL] absoluteString];
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
- messageAsDictionary:@{@"type":@"loadstop", @"url":[url absoluteString]}];
+ messageAsDictionary:@{@"type":@"loadstop", @"url":url}];
[pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
[self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
}
}
-- (void)browserLoadError:(NSError*)error forUrl:(NSURL*)url
+- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error
{
if (self.callbackId != nil) {
+ NSString* url = [[self.inAppBrowserViewController requestedURL] absoluteString];
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
- messageAsDictionary:@{@"type":@"loaderror", @"url":[url absoluteString], @"code": [NSNumber numberWithInt:error.code], @"message": error.localizedDescription}];
+ messageAsDictionary:@{@"type":@"loaderror", @"url":url, @"code": [NSNumber numberWithInt:error.code], @"message": error.localizedDescription}];
[pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
[self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
@@ -214,6 +341,8 @@
@implementation CDVInAppBrowserViewController
+@synthesize requestedURL = _requestedURL;
+
- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent
{
self = [super init];
@@ -431,18 +560,13 @@
self.forwardButton.enabled = theWebView.canGoForward;
[self.spinner startAnimating];
+
+ return [self.navigationDelegate webViewDidStartLoad:theWebView];
}
-- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
+- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
- if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadStart:)]) {
- NSURL* url = request.URL;
- if (url == nil) {
- url = _requestedURL;
- }
- [self.navigationDelegate browserLoadStart:url];
- }
- return YES;
+ return [self.navigationDelegate webView:theWebView shouldStartLoadWithRequest:request navigationType:navigationType];
}
- (void)webViewDidFinishLoad:(UIWebView*)theWebView
@@ -471,10 +595,7 @@
[CDVUserAgentUtil setUserAgent:_prevUserAgent lockToken:_userAgentLockToken];
}
- if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadStop:)]) {
- NSURL* url = theWebView.request.URL;
- [self.navigationDelegate browserLoadStop:url];
- }
+ [self.navigationDelegate webViewDidFinishLoad:theWebView];
}
- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error
@@ -488,10 +609,7 @@
self.addressLabel.text = @"Load Error";
- if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadError:forUrl:)]) {
- NSURL* url = theWebView.request.URL;
- [self.navigationDelegate browserLoadError:error forUrl:url];
- }
+ [self.navigationDelegate webView:theWebView didFailLoadWithError:error];
}
#pragma mark CDVScreenOrientationDelegate