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 2014/03/27 15:22:17 UTC

[08/34] js commit: CB-5671 Don't fail plugin loading if plugin modules are already loaded.

CB-5671 Don't fail plugin loading if plugin modules are already loaded.

This can happen when a build step concats all your JS.


Project: http://git-wip-us.apache.org/repos/asf/cordova-js/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-js/commit/5f811bbf
Tree: http://git-wip-us.apache.org/repos/asf/cordova-js/tree/5f811bbf
Diff: http://git-wip-us.apache.org/repos/asf/cordova-js/diff/5f811bbf

Branch: refs/heads/browserify
Commit: 5f811bbf2be9f6b18ee1575ab7fa506866291573
Parents: ddf13aa
Author: Andrew Grieve <ag...@chromium.org>
Authored: Mon Feb 24 15:59:26 2014 -0500
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Mon Feb 24 15:59:26 2014 -0500

----------------------------------------------------------------------
 src/common/pluginloader.js |  79 ++++++++++++--------------
 test/test.pluginloader.js  | 123 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 160 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-js/blob/5f811bbf/src/common/pluginloader.js
----------------------------------------------------------------------
diff --git a/src/common/pluginloader.js b/src/common/pluginloader.js
index 92cbaed..f72bfda 100644
--- a/src/common/pluginloader.js
+++ b/src/common/pluginloader.js
@@ -23,43 +23,51 @@ var modulemapper = require('cordova/modulemapper');
 var urlutil = require('cordova/urlutil');
 
 // Helper function to inject a <script> tag.
-function injectScript(url, onload, onerror) {
+// Exported for testing.
+exports.injectScript = function(url, onload, onerror) {
     var script = document.createElement("script");
     // onload fires even when script fails loads with an error.
     script.onload = onload;
-    script.onerror = onerror || onload;
+    // onerror fires for malformed URLs.
+    script.onerror = onerror;
     script.src = url;
     document.head.appendChild(script);
+};
+
+function injectIfNecessary(id, url, onload, onerror) {
+    onerror = onerror || onload;
+    if (id in define.moduleMap) {
+        onload();
+    } else {
+        exports.injectScript(url, function() {
+            if (id in define.moduleMap) {
+                onload();
+            } else {
+                onerror();
+            }
+        }, onerror);
+    }
 }
 
 function onScriptLoadingComplete(moduleList, finishPluginLoading) {
     // Loop through all the plugins and then through their clobbers and merges.
     for (var i = 0, module; module = moduleList[i]; i++) {
-        if (module) {
-            try {
-                if (module.clobbers && module.clobbers.length) {
-                    for (var j = 0; j < module.clobbers.length; j++) {
-                        modulemapper.clobbers(module.id, module.clobbers[j]);
-                    }
-                }
-
-                if (module.merges && module.merges.length) {
-                    for (var k = 0; k < module.merges.length; k++) {
-                        modulemapper.merges(module.id, module.merges[k]);
-                    }
-                }
-
-                // Finally, if runs is truthy we want to simply require() the module.
-                // This can be skipped if it had any merges or clobbers, though,
-                // since the mapper will already have required the module.
-                if (module.runs && !(module.clobbers && module.clobbers.length) && !(module.merges && module.merges.length)) {
-                    modulemapper.runs(module.id);
-                }
+        if (module.clobbers && module.clobbers.length) {
+            for (var j = 0; j < module.clobbers.length; j++) {
+                modulemapper.clobbers(module.id, module.clobbers[j]);
             }
-            catch(err) {
-                // error with module, most likely clobbers, should we continue?
+        }
+
+        if (module.merges && module.merges.length) {
+            for (var k = 0; k < module.merges.length; k++) {
+                modulemapper.merges(module.id, module.merges[k]);
             }
         }
+
+        // Finally, if runs is truthy we want to simply require() the module.
+        if (module.runs) {
+            modulemapper.runs(module.id);
+        }
     }
 
     finishPluginLoading();
@@ -84,26 +92,10 @@ function handlePluginsObject(path, moduleList, finishPluginLoading) {
     }
 
     for (var i = 0; i < moduleList.length; i++) {
-        injectScript(path + moduleList[i].file, scriptLoadedCallback);
+        injectIfNecessary(moduleList[i].id, path + moduleList[i].file, scriptLoadedCallback);
     }
 }
 
-function injectPluginScript(pathPrefix, finishPluginLoading) {
-    var pluginPath = pathPrefix + 'cordova_plugins.js';
-
-    injectScript(pluginPath, function() {
-        try {
-            var moduleList = require("cordova/plugin_list");
-            handlePluginsObject(pathPrefix, moduleList, finishPluginLoading);
-        }
-        catch (e) {
-            // Error loading cordova_plugins.js, file not found or something
-            // this is an acceptable error, pre-3.0.0, so we just move on.
-            finishPluginLoading();
-        }
-    }, finishPluginLoading); // also, add script load error handler for file not found
-}
-
 function findCordovaPath() {
     var path = null;
     var scripts = document.getElementsByTagName('script');
@@ -127,6 +119,9 @@ exports.load = function(callback) {
         console.log('Could not find cordova.js script tag. Plugin loading may fail.');
         pathPrefix = '';
     }
-    injectPluginScript(pathPrefix, callback);
+    injectIfNecessary('cordova/plugin_list', pathPrefix + 'cordova_plugins.js', function() {
+        var moduleList = require("cordova/plugin_list");
+        handlePluginsObject(pathPrefix, moduleList, callback);
+    }, callback);
 };
 

http://git-wip-us.apache.org/repos/asf/cordova-js/blob/5f811bbf/test/test.pluginloader.js
----------------------------------------------------------------------
diff --git a/test/test.pluginloader.js b/test/test.pluginloader.js
new file mode 100644
index 0000000..bb36f13
--- /dev/null
+++ b/test/test.pluginloader.js
@@ -0,0 +1,123 @@
+/*
+ *
+ * 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.
+ *
+*/
+
+describe('pluginloader', function() {
+    var pluginloader = require('cordova/pluginloader');
+    var injectScript;
+    var cdvScript;
+    var done;
+    var success;
+    beforeEach(function() {
+        injectScript = spyOn(pluginloader, 'injectScript');
+        var el = document.createElement('script');
+        el.setAttribute('type', 'foo');
+        el.src = 'foo/cordova.js?bar';
+        document.body.appendChild(el);
+        cdvScript = el;
+        done = false;
+        success = false;
+    });
+    afterEach(function() {
+        if (cdvScript) {
+            cdvScript.parentNode.removeChild(cdvScript);
+            cdvScript = null;
+        }
+        define.remove('cordova/plugin_list');
+        define.remove('some.id');
+    });
+
+    function setDone() {
+        done = true;
+    }
+
+    it('should inject cordova_plugins.js when it is not already there', function() {
+        injectScript.andCallFake(function(url, onload, onerror) {
+            // jsdom deficiencies:
+            if (typeof location != 'undefined') {
+                expect(url).toBe(window.location.href.replace(/\/[^\/]*?$/, '/foo/cordova_plugins.js'));
+            } else {
+                expect(url).toBe('foo/cordova_plugins.js');
+            }
+            define('cordova/plugin_list', function(require, exports, module) {
+                module.exports = [];
+            });
+            success = true;
+            onload();
+        });
+
+        pluginloader.load(setDone);
+        waitsFor(function() { return done });
+        runs(function() {
+            expect(success).toBe(true);
+        });
+    });
+
+    it('should not inject cordova_plugins.js when it is already there', function() {
+        define('cordova/plugin_list', function(require, exports, module) {
+            module.exports = [];
+        });
+        pluginloader.load(setDone);
+        waitsFor(function() { return done });
+        runs(function() {
+            expect(injectScript).not.toHaveBeenCalled();
+        });
+    });
+
+    it('should inject plugin scripts when they are not already there', function() {
+        define('cordova/plugin_list', function(require, exports, module) {
+            module.exports = [
+                { "file": "some/path.js", "id": "some.id" }
+            ];
+        });
+        injectScript.andCallFake(function(url, onload, onerror) {
+            // jsdom deficiencies:
+            if (typeof location != 'undefined') {
+                expect(url).toBe(window.location.href.replace(/\/[^\/]*?$/, '/foo/some/path.js'));
+            } else {
+                expect(url).toBe('foo/some/path.js');
+            }
+            define('some.id', function(require, exports, module) {
+            });
+            success = true;
+            onload();
+        });
+        pluginloader.load(setDone);
+        waitsFor(function() { return done });
+        runs(function() {
+            expect(success).toBe(true);
+        });
+    });
+
+    it('should not inject plugin scripts when they are already there', function() {
+        define('cordova/plugin_list', function(require, exports, module) {
+            module.exports = [
+                { "file": "some/path.js", "id": "some.id" }
+            ];
+        });
+        define('some.id', function(require, exports, module) {
+        });
+        pluginloader.load(setDone);
+        waitsFor(function() { return done });
+        runs(function() {
+            expect(injectScript).not.toHaveBeenCalled();
+        });
+    });
+});