diff options
Diffstat (limited to 'StoneIsland/platforms/ios/CordovaLib/cordova.js')
| -rw-r--r--[-rwxr-xr-x] | StoneIsland/platforms/ios/CordovaLib/cordova.js | 324 |
1 files changed, 145 insertions, 179 deletions
diff --git a/StoneIsland/platforms/ios/CordovaLib/cordova.js b/StoneIsland/platforms/ios/CordovaLib/cordova.js index 46ab90b7..9dce1f9f 100755..100644 --- a/StoneIsland/platforms/ios/CordovaLib/cordova.js +++ b/StoneIsland/platforms/ios/CordovaLib/cordova.js @@ -1,5 +1,5 @@ // Platform: ios -// 49a8db57fa070d20ea7b304a53ffec3d7250c5af +// f28234fbc27c578b9a335f1dabfa2d1b96bfc03d /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -19,7 +19,7 @@ under the License. */ ;(function() { -var PLATFORM_VERSION_BUILD_LABEL = '3.9.2'; +var PLATFORM_VERSION_BUILD_LABEL = '4.3.0'; // file: src/scripts/require.js /*jshint -W079 */ @@ -697,8 +697,13 @@ var Channel = function(type, sticky) { } }; -function forceFunction(f) { - if (typeof f != 'function') throw "Function required as first argument!"; +function checkSubscriptionArgument(argument) { + if (typeof argument !== "function" && typeof argument.handleEvent !== "function") { + throw new Error( + "Must provide a function or an EventListener object " + + "implementing the handleEvent interface." + ); + } } /** @@ -708,28 +713,39 @@ function forceFunction(f) { * and a guid that can be used to stop subscribing to the channel. * Returns the guid. */ -Channel.prototype.subscribe = function(f, c) { - // need a function to call - forceFunction(f); +Channel.prototype.subscribe = function(eventListenerOrFunction, eventListener) { + checkSubscriptionArgument(eventListenerOrFunction); + var handleEvent, guid; + + if (eventListenerOrFunction && typeof eventListenerOrFunction === "object") { + // Received an EventListener object implementing the handleEvent interface + handleEvent = eventListenerOrFunction.handleEvent; + eventListener = eventListenerOrFunction; + } else { + // Received a function to handle event + handleEvent = eventListenerOrFunction; + } + if (this.state == 2) { - f.apply(c || this, this.fireArgs); + handleEvent.apply(eventListener || this, this.fireArgs); return; } - var func = f, - guid = f.observer_guid; - if (typeof c == "object") { func = utils.close(c, f); } + guid = eventListenerOrFunction.observer_guid; + if (typeof eventListener === "object") { + handleEvent = utils.close(eventListener, handleEvent); + } if (!guid) { - // first time any channel has seen this subscriber + // First time any channel has seen this subscriber guid = '' + nextGuid++; } - func.observer_guid = guid; - f.observer_guid = guid; + handleEvent.observer_guid = guid; + eventListenerOrFunction.observer_guid = guid; // Don't add the same handler more than once. if (!this.handlers[guid]) { - this.handlers[guid] = func; + this.handlers[guid] = handleEvent; this.numHandlers++; if (this.numHandlers == 1) { this.onHasSubscribersChange && this.onHasSubscribersChange(); @@ -740,12 +756,20 @@ Channel.prototype.subscribe = function(f, c) { /** * Unsubscribes the function with the given guid from the channel. */ -Channel.prototype.unsubscribe = function(f) { - // need a function to unsubscribe - forceFunction(f); +Channel.prototype.unsubscribe = function(eventListenerOrFunction) { + checkSubscriptionArgument(eventListenerOrFunction); + var handleEvent, guid, handler; + + if (eventListenerOrFunction && typeof eventListenerOrFunction === "object") { + // Received an EventListener object implementing the handleEvent interface + handleEvent = eventListenerOrFunction.handleEvent; + } else { + // Received a function to handle event + handleEvent = eventListenerOrFunction; + } - var guid = f.observer_guid, - handler = this.handlers[guid]; + guid = handleEvent.observer_guid; + handler = this.handlers[guid]; if (handler) { delete this.handlers[guid]; this.numHandlers--; @@ -817,58 +841,23 @@ module.exports = channel; }); -// file: e:/cordova/cordova-ios/cordova-js-src/exec.js +// file: /Users/shazron/Documents/git/apache/cordova-ios/cordova-js-src/exec.js define("cordova/exec", function(require, exports, module) { +/*global require, module, atob, document */ + /** * Creates a gap bridge iframe used to notify the native code about queued * commands. */ var cordova = require('cordova'), - channel = require('cordova/channel'), utils = require('cordova/utils'), base64 = require('cordova/base64'), - // XHR mode does not work on iOS 4.2. - // XHR mode's main advantage is working around a bug in -webkit-scroll, which - // doesn't exist only on iOS 5.x devices. - // IFRAME_NAV is the fastest. - // IFRAME_HASH could be made to enable synchronous bridge calls if we wanted this feature. - jsToNativeModes = { - IFRAME_NAV: 0, // Default. Uses a new iframe for each poke. - // XHR bridge appears to be flaky sometimes: CB-3900, CB-3359, CB-5457, CB-4970, CB-4998, CB-5134 - XHR_NO_PAYLOAD: 1, // About the same speed as IFRAME_NAV. Performance not about the same as IFRAME_NAV, but more variable. - XHR_WITH_PAYLOAD: 2, // Flakey, and not as performant - XHR_OPTIONAL_PAYLOAD: 3, // Flakey, and not as performant - IFRAME_HASH_NO_PAYLOAD: 4, // Not fully baked. A bit faster than IFRAME_NAV, but risks jank since poke happens synchronously. - IFRAME_HASH_WITH_PAYLOAD: 5, // Slower than no payload. Maybe since it has to be URI encoded / decoded. - WK_WEBVIEW_BINDING: 6 // Only way that works for WKWebView :) - }, - bridgeMode, execIframe, - execHashIframe, - hashToggle = 1, - execXhr, - requestCount = 0, - vcHeaderValue = null, commandQueue = [], // Contains pending JS->Native messages. isInContextOfEvalJs = 0, failSafeTimerId = 0; -function shouldBundleCommandJson() { - if (bridgeMode === jsToNativeModes.XHR_WITH_PAYLOAD) { - return true; - } - if (bridgeMode === jsToNativeModes.XHR_OPTIONAL_PAYLOAD) { - var payloadLength = 0; - for (var i = 0; i < commandQueue.length; ++i) { - payloadLength += commandQueue[i].length; - } - // The value here was determined using the benchmark within CordovaLibApp on an iPad 3. - return payloadLength < 4500; - } - return false; -} - function massageArgsJsToNative(args) { if (!args || utils.typeName(args) != 'Array') { return args; @@ -919,17 +908,10 @@ function convertMessageToArgsNativeToJs(message) { } function iOSExec() { - if (bridgeMode === undefined) { - bridgeMode = jsToNativeModes.IFRAME_NAV; - } - - if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.cordova && window.webkit.messageHandlers.cordova.postMessage) { - bridgeMode = jsToNativeModes.WK_WEBVIEW_BINDING; - } - var successCallback, failCallback, service, action, actionArgs, splitCommand; + var successCallback, failCallback, service, action, actionArgs; var callbackId = null; - if (typeof arguments[0] !== "string") { + if (typeof arguments[0] !== 'string') { // FORMAT ONE successCallback = arguments[0]; failCallback = arguments[1]; @@ -943,18 +925,9 @@ function iOSExec() { // an invalid callbackId and passes it even if no callbacks were given. callbackId = 'INVALID'; } else { - // FORMAT TWO, REMOVED - try { - splitCommand = arguments[0].split("."); - action = splitCommand.pop(); - service = splitCommand.join("."); - actionArgs = Array.prototype.splice.call(arguments, 1); - - console.log('The old format of this exec call has been removed (deprecated since 2.1). Change to: ' + - "cordova.exec(null, null, \"" + service + "\", \"" + action + "\"," + JSON.stringify(actionArgs) + ");" - ); - return; - } catch (e) {} + throw new Error('The old format of this exec call has been removed (deprecated since 2.1). Change to: ' + + 'cordova.exec(null, null, \'Service\', \'action\', [ arg1, arg2 ]);' + ); } // If actionArgs is not provided, default to an empty array @@ -976,116 +949,79 @@ function iOSExec() { // effectively clone the command arguments in case they are mutated before // the command is executed. commandQueue.push(JSON.stringify(command)); - - if (bridgeMode === jsToNativeModes.WK_WEBVIEW_BINDING) { - window.webkit.messageHandlers.cordova.postMessage(command); - } else { - // If we're in the context of a stringByEvaluatingJavaScriptFromString call, - // then the queue will be flushed when it returns; no need for a poke. - // Also, if there is already a command in the queue, then we've already - // poked the native side, so there is no reason to do so again. - if (!isInContextOfEvalJs && commandQueue.length == 1) { - pokeNative(); - } + + // If we're in the context of a stringByEvaluatingJavaScriptFromString call, + // then the queue will be flushed when it returns; no need for a poke. + // Also, if there is already a command in the queue, then we've already + // poked the native side, so there is no reason to do so again. + if (!isInContextOfEvalJs && commandQueue.length == 1) { + pokeNative(); } } -function pokeNative() { - switch (bridgeMode) { - case jsToNativeModes.XHR_NO_PAYLOAD: - case jsToNativeModes.XHR_WITH_PAYLOAD: - case jsToNativeModes.XHR_OPTIONAL_PAYLOAD: - pokeNativeViaXhr(); - break; - default: // iframe-based. - pokeNativeViaIframe(); - } +// CB-10530 +function proxyChanged() { + var cexec = cordovaExec(); + + return (execProxy !== cexec && // proxy objects are different + iOSExec !== cexec // proxy object is not the current iOSExec + ); } -function pokeNativeViaXhr() { - // This prevents sending an XHR when there is already one being sent. - // This should happen only in rare circumstances (refer to unit tests). - if (execXhr && execXhr.readyState != 4) { - execXhr = null; - } - // Re-using the XHR improves exec() performance by about 10%. - execXhr = execXhr || new XMLHttpRequest(); - // Changing this to a GET will make the XHR reach the URIProtocol on 4.2. - // For some reason it still doesn't work though... - // Add a timestamp to the query param to prevent caching. - execXhr.open('HEAD', "/!gap_exec?" + (+new Date()), true); - if (!vcHeaderValue) { - vcHeaderValue = /.*\((.*)\)$/.exec(navigator.userAgent)[1]; - } - execXhr.setRequestHeader('vc', vcHeaderValue); - execXhr.setRequestHeader('rc', ++requestCount); - if (shouldBundleCommandJson()) { - execXhr.setRequestHeader('cmds', iOSExec.nativeFetchMessages()); +// CB-10106 +function handleBridgeChange() { + if (proxyChanged()) { + var commandString = commandQueue.shift(); + while(commandString) { + var command = JSON.parse(commandString); + var callbackId = command[0]; + var service = command[1]; + var action = command[2]; + var actionArgs = command[3]; + var callbacks = cordova.callbacks[callbackId] || {}; + + execProxy(callbacks.success, callbacks.fail, service, action, actionArgs); + + commandString = commandQueue.shift(); + }; + return true; } - execXhr.send(null); + + return false; } -function pokeNativeViaIframe() { +function pokeNative() { // CB-5488 - Don't attempt to create iframe before document.body is available. if (!document.body) { - setTimeout(pokeNativeViaIframe); + setTimeout(pokeNative); return; } - if (bridgeMode === jsToNativeModes.IFRAME_HASH_NO_PAYLOAD || bridgeMode === jsToNativeModes.IFRAME_HASH_WITH_PAYLOAD) { - // TODO: This bridge mode doesn't properly support being removed from the DOM (CB-7735) - if (!execHashIframe) { - execHashIframe = document.createElement('iframe'); - execHashIframe.style.display = 'none'; - document.body.appendChild(execHashIframe); - // Hash changes don't work on about:blank, so switch it to file:///. - execHashIframe.contentWindow.history.replaceState(null, null, 'file:///#'); - } - // The delegate method is called only when the hash changes, so toggle it back and forth. - hashToggle = hashToggle ^ 3; - var hashValue = '%0' + hashToggle; - if (bridgeMode === jsToNativeModes.IFRAME_HASH_WITH_PAYLOAD) { - hashValue += iOSExec.nativeFetchMessages(); - } - execHashIframe.contentWindow.location.hash = hashValue; + + // Check if they've removed it from the DOM, and put it back if so. + if (execIframe && execIframe.contentWindow) { + execIframe.contentWindow.location = 'gap://ready'; } else { - // Check if they've removed it from the DOM, and put it back if so. - if (execIframe && execIframe.contentWindow) { - execIframe.contentWindow.location = 'gap://ready'; - } else { - execIframe = document.createElement('iframe'); - execIframe.style.display = 'none'; - execIframe.src = 'gap://ready'; - document.body.appendChild(execIframe); - } - // Use a timer to protect against iframe being unloaded during the poke (CB-7735). - // This makes the bridge ~ 7% slower, but works around the poke getting lost - // when the iframe is removed from the DOM. - // An onunload listener could be used in the case where the iframe has just been - // created, but since unload events fire only once, it doesn't work in the normal - // case of iframe reuse (where unload will have already fired due to the attempted - // navigation of the page). - failSafeTimerId = setTimeout(function() { - if (commandQueue.length) { - pokeNative(); - } - }, 50); // Making this > 0 improves performance (marginally) in the normal case (where it doesn't fire). + execIframe = document.createElement('iframe'); + execIframe.style.display = 'none'; + execIframe.src = 'gap://ready'; + document.body.appendChild(execIframe); } -} - -iOSExec.jsToNativeModes = jsToNativeModes; - -iOSExec.setJsToNativeBridgeMode = function(mode) { - // Remove the iFrame since it may be no longer required, and its existence - // can trigger browser bugs. - // https://issues.apache.org/jira/browse/CB-593 - if (execIframe) { - if (execIframe.parentNode) { - execIframe.parentNode.removeChild(execIframe); + // Use a timer to protect against iframe being unloaded during the poke (CB-7735). + // This makes the bridge ~ 7% slower, but works around the poke getting lost + // when the iframe is removed from the DOM. + // An onunload listener could be used in the case where the iframe has just been + // created, but since unload events fire only once, it doesn't work in the normal + // case of iframe reuse (where unload will have already fired due to the attempted + // navigation of the page). + failSafeTimerId = setTimeout(function() { + if (commandQueue.length) { + // CB-10106 - flush the queue on bridge change + if (!handleBridgeChange()) { + pokeNative(); + } } - execIframe = null; - } - bridgeMode = mode; -}; + }, 50); // Making this > 0 improves performance (marginally) in the normal case (where it doesn't fire). +} iOSExec.nativeFetchMessages = function() { // Stop listing for window detatch once native side confirms poke. @@ -1102,11 +1038,14 @@ iOSExec.nativeFetchMessages = function() { return json; }; -iOSExec.nativeCallback = function(callbackId, status, message, keepCallback) { +iOSExec.nativeCallback = function(callbackId, status, message, keepCallback, debug) { return iOSExec.nativeEvalAndFetch(function() { var success = status === 0 || status === 1; var args = convertMessageToArgsNativeToJs(message); - cordova.callbackFromNative(callbackId, success, status, args, keepCallback); + function nc2() { + cordova.callbackFromNative(callbackId, success, status, args, keepCallback); + } + setTimeout(nc2, 0); }); }; @@ -1121,7 +1060,31 @@ iOSExec.nativeEvalAndFetch = function(func) { } }; -module.exports = iOSExec; +// Proxy the exec for bridge changes. See CB-10106 + +function cordovaExec() { + var cexec = require('cordova/exec'); + var cexec_valid = (typeof cexec.nativeFetchMessages === 'function') && (typeof cexec.nativeEvalAndFetch === 'function') && (typeof cexec.nativeCallback === 'function'); + return (cexec_valid && execProxy !== cexec)? cexec : iOSExec; +} + +function execProxy() { + cordovaExec().apply(null, arguments); +}; + +execProxy.nativeFetchMessages = function() { + return cordovaExec().nativeFetchMessages.apply(null, arguments); +}; + +execProxy.nativeEvalAndFetch = function() { + return cordovaExec().nativeEvalAndFetch.apply(null, arguments); +}; + +execProxy.nativeCallback = function() { + return cordovaExec().nativeCallback.apply(null, arguments); +}; + +module.exports = execProxy; }); @@ -1606,7 +1569,7 @@ exports.reset(); }); -// file: e:/cordova/cordova-ios/cordova-js-src/platform.js +// file: /Users/shazron/Documents/git/apache/cordova-ios/cordova-js-src/platform.js define("cordova/platform", function(require, exports, module) { module.exports = { @@ -1888,7 +1851,10 @@ utils.clone = function(obj) { retVal = {}; for(i in obj){ - if(!(i in retVal) || retVal[i] != obj[i]) { + // https://issues.apache.org/jira/browse/CB-11522 'unknown' type may be returned in + // custom protocol activation case on Windows Phone 8.1 causing "No such interface supported" exception + // on cloning. + if((!(i in retVal) || retVal[i] != obj[i]) && typeof obj[i] != 'undefined' && typeof obj[i] != 'unknown') { retVal[i] = utils.clone(obj[i]); } } |
