Repository: cordova-ios
Updated Branches:
  refs/heads/master dd54d96bd -> 9e53aa997


CB-8002 CB-7735 Update cordova.js to include bridge fix


Project: http://git-wip-us.apache.org/repos/asf/cordova-ios/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-ios/commit/9e53aa99
Tree: http://git-wip-us.apache.org/repos/asf/cordova-ios/tree/9e53aa99
Diff: http://git-wip-us.apache.org/repos/asf/cordova-ios/diff/9e53aa99

Branch: refs/heads/master
Commit: 9e53aa9976772ea0a6861d6c451fef019d29fc65
Parents: dd54d96
Author: Andrew Grieve <[email protected]>
Authored: Tue Nov 25 13:42:40 2014 -0500
Committer: Andrew Grieve <[email protected]>
Committed: Tue Nov 25 13:42:40 2014 -0500

----------------------------------------------------------------------
 CordovaLib/cordova.js | 122 +++++++++++++++++++++++----------------------
 1 file changed, 62 insertions(+), 60 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/9e53aa99/CordovaLib/cordova.js
----------------------------------------------------------------------
diff --git a/CordovaLib/cordova.js b/CordovaLib/cordova.js
index 75729c1..9588ca4 100644
--- a/CordovaLib/cordova.js
+++ b/CordovaLib/cordova.js
@@ -1,5 +1,5 @@
 // Platform: ios
-// 91157c2e1bf3eb098c7e2ab31404e895ccb0df2a
+// 227d83a122733fdf0300ffe75507a221bcef2b06
 /*
  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
@@ -464,9 +464,14 @@ function each(objects, func, context) {
 
 function clobber(obj, key, value) {
     exports.replaceHookForTesting(obj, key);
-    obj[key] = value;
+    var needsProperty = false;
+    try {
+        obj[key] = value;
+    } catch (e) {
+        needsProperty = true;
+    }
     // Getters can only be overridden by getters.
-    if (obj[key] !== value) {
+    if (needsProperty || obj[key] !== value) {
         utils.defineGetter(obj, key, function() {
             return value;
         });
@@ -821,14 +826,13 @@ var cordova = require('cordova'),
     // IFRAME_NAV is the fastest.
     // IFRAME_HASH could be made to enable synchronous bridge calls if we 
wanted this feature.
     jsToNativeModes = {
-        IFRAME_NAV: 0,
-        XHR_NO_PAYLOAD: 1,
-        XHR_WITH_PAYLOAD: 2,
-        XHR_OPTIONAL_PAYLOAD: 3,
-        IFRAME_HASH_NO_PAYLOAD: 4,
-        // Bundling the payload turns out to be slower. Probably since it has 
to be URI encoded / decoded.
-        IFRAME_HASH_WITH_PAYLOAD: 5,
-        WK_WEBVIEW_BINDING: 6
+        IFRAME_NAV: 0, // Default. Uses a new iframe for each poke.
+        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,
@@ -838,26 +842,8 @@ var cordova = require('cordova'),
     requestCount = 0,
     vcHeaderValue = null,
     commandQueue = [], // Contains pending JS->Native messages.
-    isInContextOfEvalJs = 0;
-
-function createExecIframe(src, unloadListener) {
-    var iframe = document.createElement("iframe");
-    iframe.style.display = 'none';
-    // Both the unload listener and the src must be set before adding the 
iframe
-    // to the document in order to avoid race conditions. Callbacks from native
-    // can happen within the appendChild() call!
-    iframe.onunload = unloadListener;
-    iframe.src = src;
-    document.body.appendChild(iframe);
-    return iframe;
-}
-
-function createHashIframe() {
-    var ret = createExecIframe('about:blank');
-    // Hash changes don't work on about:blank, so switch it to file:///.
-    ret.contentWindow.history.replaceState(null, null, 'file:///#');
-    return ret;
-}
+    isInContextOfEvalJs = 0,
+    failSafeTimerId = 0;
 
 function shouldBundleCommandJson() {
     if (bridgeMode === jsToNativeModes.XHR_WITH_PAYLOAD) {
@@ -990,19 +976,23 @@ function iOSExec() {
         // 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) {
-            switch (bridgeMode) {
-            case jsToNativeModes.XHR_NO_PAYLOAD:
-            case jsToNativeModes.XHR_WITH_PAYLOAD:
-            case jsToNativeModes.XHR_OPTIONAL_PAYLOAD:
-                pokeNativeViaXhr();
-                break;
-            default: // iframe-based.
-                pokeNativeViaIframe();
-            }
+            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();
+    }
+}
+
 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).
@@ -1026,11 +1016,6 @@ function pokeNativeViaXhr() {
     execXhr.send(null);
 }
 
-function onIframeUnload() {
-    execIframe = null;
-    setTimeout(pokeNativeViaIframe, 0);
-}
-
 function pokeNativeViaIframe() {
     // CB-5488 - Don't attempt to create iframe before document.body is 
available.
     if (!document.body) {
@@ -1039,10 +1024,12 @@ function pokeNativeViaIframe() {
     }
     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)
-        execHashIframe = execHashIframe || createHashIframe();
-        // Check if they've removed it from the DOM, and put it back if so.
-        if (!execHashIframe.contentWindow) {
-            execHashIframe = createHashIframe();
+        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;
@@ -1054,13 +1041,25 @@ function pokeNativeViaIframe() {
     } else {
         // Check if they've removed it from the DOM, and put it back if so.
         if (execIframe && execIframe.contentWindow) {
-            // Listen for unload, since it can happen (CB-7735) that the 
iframe gets
-            // removed from the DOM before it gets a chance to poke the native 
side.
-            execIframe.contentWindow.onunload = onIframeUnload;
-            execIframe.src = 'gap://ready';
+            execIframe.contentWindow.location = 'gap://ready';
         } else {
-            execIframe = createExecIframe('gap://ready', onIframeUnload);
+            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).
     }
 }
 
@@ -1071,7 +1070,9 @@ iOSExec.setJsToNativeBridgeMode = function(mode) {
     // can trigger browser bugs.
     // https://issues.apache.org/jira/browse/CB-593
     if (execIframe) {
-        execIframe.parentNode.removeChild(execIframe);
+        if (execIframe.parentNode) {
+            execIframe.parentNode.removeChild(execIframe);
+        }
         execIframe = null;
     }
     bridgeMode = mode;
@@ -1079,8 +1080,9 @@ iOSExec.setJsToNativeBridgeMode = function(mode) {
 
 iOSExec.nativeFetchMessages = function() {
     // Stop listing for window detatch once native side confirms poke.
-    if (execIframe && execIframe.contentWindow) {
-        execIframe.contentWindow.onunload = null;
+    if (failSafeTimerId) {
+        clearTimeout(failSafeTimerId);
+        failSafeTimerId = 0;
     }
     // Each entry in commandQueue is a JSON string already.
     if (!commandQueue.length) {
@@ -1184,7 +1186,7 @@ function replaceNavigator(origNavigator) {
         for (var key in origNavigator) {
             if (typeof origNavigator[key] == 'function') {
                 newNavigator[key] = origNavigator[key].bind(origNavigator);
-            } 
+            }
             else {
                 (function(k) {
                     utils.defineGetterSetter(newNavigator,key,function() {
@@ -1312,7 +1314,7 @@ function replaceNavigator(origNavigator) {
         for (var key in origNavigator) {
             if (typeof origNavigator[key] == 'function') {
                 newNavigator[key] = origNavigator[key].bind(origNavigator);
-            } 
+            }
             else {
                 (function(k) {
                     utils.defineGetterSetter(newNavigator,key,function() {
@@ -1367,7 +1369,7 @@ platform.bootstrap && platform.bootstrap();
  * Create all cordova objects once native side is ready.
  */
 channel.join(function() {
-    
+
     platform.initialize && platform.initialize();
 
     // Fire event to notify that all objects are created


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to