Merge branch 'master' into next
diff --git a/lib/android/exec.js b/lib/android/exec.js
index 506fd3d..7a101c6 100644
--- a/lib/android/exec.js
+++ b/lib/android/exec.js
@@ -203,7 +203,7 @@
} else {
payload = JSON.parse(message.slice(nextSpaceIdx + 1));
}
- cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);
+ cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback);
} else {
console.log("processMessage failed: invalid message:" + message);
}
diff --git a/lib/bada/plugin/bada/device.js b/lib/bada/plugin/bada/device.js
index 75a41e8..c2db705 100644
--- a/lib/bada/plugin/bada/device.js
+++ b/lib/bada/plugin/bada/device.js
@@ -22,9 +22,6 @@
var channel = require('cordova/channel'),
utils = require('cordova/utils');
-// Tell cordova channel to wait on the CordovaInfoReady event
-channel.waitForInitialization('onCordovaInfoReady');
-
function Device() {
this.platform = null;
this.version = null;
diff --git a/lib/common/channel.js b/lib/common/channel.js
index 6e90603..38daedf 100644
--- a/lib/common/channel.js
+++ b/lib/common/channel.js
@@ -242,6 +242,10 @@
// Event to indicate that the connection property has been set.
channel.createSticky('onCordovaConnectionReady');
+// Event to indicate that all automatically loaded JS plugins are loaded and ready.
+// This is used in conjunction with the automatic plugin JS loading CLI prototype.
+channel.createSticky('onPluginsReady');
+
// Event to indicate that Cordova is ready
channel.createSticky('onDeviceReady');
diff --git a/lib/common/plugin/FileTransfer.js b/lib/common/plugin/FileTransfer.js
index 7e7af61..3a9fda2 100644
--- a/lib/common/plugin/FileTransfer.js
+++ b/lib/common/plugin/FileTransfer.js
@@ -79,7 +79,7 @@
}
var fail = errorCallback && function(e) {
- var error = new FileTransferError(e.code, e.source, e.target, e.http_status);
+ var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
errorCallback(error);
};
@@ -129,7 +129,7 @@
};
var fail = errorCallback && function(e) {
- var error = new FileTransferError(e.code, e.source, e.target, e.http_status);
+ var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
errorCallback(error);
};
diff --git a/lib/common/plugin/echo.js b/lib/common/plugin/echo.js
index 87a495f..76fe3f0 100644
--- a/lib/common/plugin/echo.js
+++ b/lib/common/plugin/echo.js
@@ -19,7 +19,8 @@
*
*/
-var exec = require('cordova/exec');
+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.
@@ -29,10 +30,24 @@
* @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';
+ 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, [message]);
+
+ exec(successCallback, errorCallback, "Echo", action, args);
};
diff --git a/lib/cordova.js b/lib/cordova.js
index ef68b2b..a31c40e 100644
--- a/lib/cordova.js
+++ b/lib/cordova.js
@@ -189,7 +189,7 @@
*/
callbackSuccess: function(callbackId, args) {
try {
- cordova.callbackFromNative(callbackId, true, args.status, args.message, args.keepCallback);
+ cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
} catch (e) {
console.log("Error in error callback: " + callbackId + " = "+e);
}
@@ -202,7 +202,7 @@
// TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
// Derive success from status.
try {
- cordova.callbackFromNative(callbackId, false, args.status, args.message, args.keepCallback);
+ cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
} catch (e) {
console.log("Error in error callback: " + callbackId + " = "+e);
}
@@ -211,13 +211,13 @@
/**
* Called by native code when returning the result from an action.
*/
- callbackFromNative: function(callbackId, success, status, message, keepCallback) {
+ callbackFromNative: function(callbackId, success, status, args, keepCallback) {
var callback = cordova.callbacks[callbackId];
if (callback) {
if (success && status == cordova.callbackStatus.OK) {
- callback.success && callback.success(message);
+ callback.success && callback.success.apply(null, args);
} else if (!success) {
- callback.fail && callback.fail(message);
+ callback.fail && callback.fail.apply(null, args);
}
// Clear callback if not expecting any more results
diff --git a/lib/ios/exec.js b/lib/ios/exec.js
index 58e73d2..5e237d9 100644
--- a/lib/ios/exec.js
+++ b/lib/ios/exec.js
@@ -68,6 +68,7 @@
if (!args || utils.typeName(args) != 'Array') {
return args;
}
+ var ret = [];
var encodeArrayBufferAs8bitString = function(ab) {
return String.fromCharCode.apply(null, new Uint8Array(ab));
};
@@ -76,17 +77,19 @@
};
args.forEach(function(arg, i) {
if (utils.typeName(arg) == 'ArrayBuffer') {
- args[i] = {
+ ret.push({
'CDVType': 'ArrayBuffer',
'data': encodeArrayBufferAsBase64(arg)
- };
+ });
+ } else {
+ ret.push(arg);
}
});
- return args;
+ return ret;
}
-function massagePayloadNativeToJs(payload) {
- if (payload && payload.hasOwnProperty('CDVType') && payload.CDVType == 'ArrayBuffer') {
+function massageMessageNativeToJs(message) {
+ if (message.CDVType == 'ArrayBuffer') {
var stringToArrayBuffer = function(str) {
var ret = new Uint8Array(str.length);
for (var i = 0; i < str.length; i++) {
@@ -97,9 +100,23 @@
var base64ToArrayBuffer = function(b64) {
return stringToArrayBuffer(atob(b64));
};
- payload = base64ToArrayBuffer(payload.data);
+ message = base64ToArrayBuffer(message.data);
}
- return payload;
+ return message;
+}
+
+function convertMessageToArgsNativeToJs(message) {
+ var args = [];
+ if (!message || !message.hasOwnProperty('CDVType')) {
+ args.push(message);
+ } else if (message.CDVType == 'MultiPart') {
+ message.messages.forEach(function(e) {
+ args.push(massageMessageNativeToJs(e));
+ });
+ } else {
+ args.push(massageMessageNativeToJs(message));
+ }
+ return args;
}
function iOSExec() {
@@ -206,11 +223,11 @@
return json;
};
-iOSExec.nativeCallback = function(callbackId, status, payload, keepCallback) {
+iOSExec.nativeCallback = function(callbackId, status, message, keepCallback) {
return iOSExec.nativeEvalAndFetch(function() {
var success = status === 0 || status === 1;
- payload = massagePayloadNativeToJs(payload);
- cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);
+ var args = convertMessageToArgsNativeToJs(message);
+ cordova.callbackFromNative(callbackId, success, status, args, keepCallback);
});
};
diff --git a/lib/scripts/bootstrap.js b/lib/scripts/bootstrap.js
index 45c70aa..6213165 100644
--- a/lib/scripts/bootstrap.js
+++ b/lib/scripts/bootstrap.js
@@ -22,44 +22,26 @@
(function (context) {
// 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.
- if (context.navigator) {
+ function replaceNavigator(origNavigator) {
var CordovaNavigator = function() {};
- CordovaNavigator.prototype = context.navigator;
- context.navigator = new CordovaNavigator();
+ CordovaNavigator.prototype = origNavigator;
+ var newNavigator = new CordovaNavigator();
+ // This work-around really only applies to new APIs that are newer than Function.bind.
+ // Without it, APIs such as getGamepads() break.
+ if (CordovaNavigator.bind) {
+ for (var key in origNavigator) {
+ if (typeof origNavigator[key] == 'function') {
+ newNavigator[key] = origNavigator[key].bind(origNavigator);
+ }
+ }
+ }
+ return newNavigator;
+ }
+ if (context.navigator) {
+ context.navigator = replaceNavigator(context.navigator);
}
- var channel = require("cordova/channel"),
- _self = {
- boot: function () {
- /**
- * Create all cordova objects once page has fully loaded and 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();
-
- // 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.
- channel.join(function() {
- require('cordova').fireDocumentEvent('deviceready');
- }, channel.deviceReadyChannelsArray);
-
- }, [ channel.onDOMContentLoaded, channel.onNativeReady ]);
- }
- };
-
- // boot up once native side is ready
- channel.onNativeReady.subscribe(_self.boot);
+ 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
@@ -68,4 +50,38 @@
channel.onNativeReady.fire();
}
+ /**
+ * Create all cordova objects once page has fully loaded and native side is ready.
+ */
+ var joinEvents = [ channel.onDOMContentLoaded, channel.onNativeReady ];
+
+ // If this property is set to something truthy, join on onPluginsReady too.
+ // This property is set by the automatic JS installation prototype in cordova-cli,
+ // and will be removed when the prototype either becomes mainline or is dropped.
+ if (window.__onPluginsLoadedHack) {
+ joinEvents.push(channel.onPluginsReady);
+ }
+
+ 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();
+
+ // 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.
+ channel.join(function() {
+ require('cordova').fireDocumentEvent('deviceready');
+ }, channel.deviceReadyChannelsArray);
+
+ }, joinEvents);
+
}(window));
diff --git a/test/android/test.exec.js b/test/android/test.exec.js
index 3363e45..3e185d9 100644
--- a/test/android/test.exec.js
+++ b/test/android/test.exec.js
@@ -107,50 +107,50 @@
it('should handle payloads of false', function() {
var messages = createCallbackMessage(true, true, 1, 'id', 'f');
exec.processMessages(messages);
- expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, false, true);
+ expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, [false], true);
});
it('should handle payloads of true', function() {
var messages = createCallbackMessage(true, true, 1, 'id', 't');
exec.processMessages(messages);
- expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, true, true);
+ expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, [true], true);
});
it('should handle payloads of null', function() {
var messages = createCallbackMessage(true, true, 1, 'id', 'N');
exec.processMessages(messages);
- expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, null, true);
+ expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, [null], true);
});
it('should handle payloads of numbers', function() {
var messages = createCallbackMessage(true, true, 1, 'id', 'n-3.3');
exec.processMessages(messages);
- expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, -3.3, true);
+ expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, [-3.3], true);
});
it('should handle payloads of strings', function() {
var messages = createCallbackMessage(true, true, 1, 'id', 'sHello world');
exec.processMessages(messages);
- expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, 'Hello world', true);
+ expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, ['Hello world'], true);
});
it('should handle payloads of JSON objects', function() {
var messages = createCallbackMessage(true, true, 1, 'id', '{"a":1}');
exec.processMessages(messages);
- expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, {a:1}, true);
+ expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, [{a:1}], true);
});
it('should handle payloads of JSON arrays', function() {
var messages = createCallbackMessage(true, true, 1, 'id', '[1]');
exec.processMessages(messages);
- expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, [1], true);
+ expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, [[1]], true);
});
it('should handle other callback opts', function() {
var messages = createCallbackMessage(false, false, 3, 'id', 'sfoo');
exec.processMessages(messages);
- expect(callbackSpy).toHaveBeenCalledWith('id', false, 3, 'foo', false);
+ expect(callbackSpy).toHaveBeenCalledWith('id', false, 3, ['foo'], false);
});
it('should handle multiple messages', function() {
var message1 = createCallbackMessage(false, false, 3, 'id', 'sfoo');
var message2 = createCallbackMessage(true, true, 1, 'id', 'f');
var messages = message1 + message2;
exec.processMessages(messages);
- expect(callbackSpy).toHaveBeenCalledWith('id', false, 3, 'foo', false);
- expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, false, true);
+ expect(callbackSpy).toHaveBeenCalledWith('id', false, 3, ['foo'], false);
+ expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, [false], true);
});
it('should poll for more messages when hitting an *', function() {
var message1 = createCallbackMessage(false, false, 3, 'id', 'sfoo');
@@ -161,10 +161,10 @@
});
var messages = message1 + '*';
exec.processMessages(messages);
- expect(callbackSpy).toHaveBeenCalledWith('id', false, 3, 'foo', false);
+ expect(callbackSpy).toHaveBeenCalledWith('id', false, 3, ['foo'], false);
waitsFor(function() { return nativeApi.retrieveJsMessages.wasCalled }, 500);
runs(function() {
- expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, false, true);
+ expect(callbackSpy).toHaveBeenCalledWith('id', true, 1, [false], true);
});
});
it('should call callbacks in order when one callback enqueues another.', function() {
@@ -179,9 +179,9 @@
});
exec.processMessages(message1 + message2);
expect(callbackSpy.argsForCall.length).toEqual(3);
- expect(callbackSpy.argsForCall[0]).toEqual(['id', false, 3, 'call1', false]);
- expect(callbackSpy.argsForCall[1]).toEqual(['id', false, 3, 'call2', false]);
- expect(callbackSpy.argsForCall[2]).toEqual(['id', false, 3, 'call3', false]);
+ expect(callbackSpy.argsForCall[0]).toEqual(['id', false, 3, ['call1'], false]);
+ expect(callbackSpy.argsForCall[1]).toEqual(['id', false, 3, ['call2'], false]);
+ expect(callbackSpy.argsForCall[2]).toEqual(['id', false, 3, ['call3'], false]);
});
});
});