You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2010/05/07 19:47:30 UTC

svn commit: r942158 - /tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js

Author: hlship
Date: Fri May  7 17:47:30 2010
New Revision: 942158

URL: http://svn.apache.org/viewvc?rev=942158&view=rev
Log:
TAP5-1137: Dynamically adding JavaScript libraries to a page via a partial page update does not seem to work consistently in Safari and Chrome

Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js?rev=942158&r1=942157&r2=942158&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js Fri May  7 17:47:30 2010
@@ -1772,66 +1772,6 @@ Tapestry.FormInjector = Class.create( {
 	}
 });
 
-/**
- * Wait for a set of JavaScript libraries to load (in terms of DOM script
- * elements), then invokes a callback function.
- */
-Tapestry.ScriptLoadMonitor = Class
-		.create( {
-
-			initialize : function(scriptElements, callback) {
-				this.callback = callback;
-				this.loaded = 0;
-				this.toload = scriptElements.length;
-
-				var executor = this;
-
-				scriptElements
-						.each(function(scriptElement) {
-							if (Prototype.Browser.IE) {
-								var loaded = false;
-
-								scriptElement.onreadystatechange = function() {
-									/*
-									 * IE may fire either loaded or complete, or
-									 * perhaps even both.
-									 */
-									if (!loaded
-											&& (this.readyState == 'loaded' || this.readyState == 'complete')) {
-										loaded = true;
-										executor.loadComplete(scriptElement);
-									}
-								};
-							} else {
-								/* Much simpler in FF, Safari, etc. */
-								scriptElement.onload = executor.loadComplete
-										.bindAsEventListener(executor,
-												scriptElement);
-							}
-						});
-
-				/*
-				 * If no scripts to actually load, call the callback
-				 * immediately.
-				 */
-
-				if (this.toload == 0)
-					this.callback.call(this);
-			},
-
-			loadComplete : function() {
-				this.loaded++;
-
-				/*
-				 * Evaluated the dependent script only once all the elements
-				 * have loaded.
-				 */
-
-				if (this.loaded == this.toload)
-					this.callback.call(this);
-			}
-		});
-
 Tapestry.ScriptManager = {
 
 	/**
@@ -1846,7 +1786,6 @@ Tapestry.ScriptManager = {
 		 * Check to see if document.scripts is supported; if not (for example,
 		 * FireFox), we can fake it.
 		 */
-
 		this.emulated = false;
 
 		if (!document.scripts) {
@@ -1860,6 +1799,41 @@ Tapestry.ScriptManager = {
 		}
 	},
 
+	loadScript : function(scriptURL, callback) {
+		/* IE needs the type="text/javascript" as well. */
+		var element = new Element('script', {
+			src : scriptURL,
+			type : 'text/javascript'
+		});
+
+		$$("head").first().insert( {
+			bottom : element
+		});
+
+		if (this.emulated)
+			document.scripts.push(element);
+
+		if (Prototype.Browser.IE) {
+			var loaded = false;
+
+			element.onreadystatechange = function() {
+				/* IE may fire either 'loaded' or 'complete', or possibly both. */
+				if (!loaded && this.readyState == 'loaded'
+						|| this.readyState == 'complete') {
+					loaded = true;
+
+					callback.call(this);
+				}
+			};
+
+			return;
+		}
+
+		/* Safari, Firefox, etc. are easier. */
+
+		element.onload = callback.bindAsEventListener(this);
+	},
+
 	/**
 	 * Checks to see if the given collection (of <script> or <style> elements)
 	 * contains the given asset URL.
@@ -1897,51 +1871,44 @@ Tapestry.ScriptManager = {
 	 *            invoked after scripts are loaded
 	 */
 	addScripts : function(scripts, callback) {
-		var added = new Array();
 
-		if (scripts) {
-			var emulated = this.emulated;
-			/*
-			 * Looks like IE really needs the new <script> tag to be in the
-			 * <head>. FF doesn't seem to care. See
-			 * http://unixpapa.com/js/dyna.html
-			 */
-			var head = $$("head").first();
+		var scriptsToLoad = [];
 
-			scripts.each(function(s) {
-				var assetURL = Tapestry.rebuildURL(s);
+		/* scripts may be null or undefined */
+		(scripts || []).each(function(s) {
+			var assetURL = Tapestry.rebuildURL(s);
 
-				/*
-				 * Check to see if the script is already loaded, either as a
-				 * virtual script, or as an individual script src="" element.
-				 */
-
-				if (Tapestry.ScriptManager.virtualScripts.member(assetURL))
-					return;
-				if (Tapestry.ScriptManager.contains(document.scripts, "src",
-						assetURL))
-					return;
-
-				/* IE needs the type="text/javascript" as well. */
-
-				var element = new Element('script', {
-					src : assetURL,
-					type : 'text/javascript'
-				});
+			/*
+			 * Check to see if the script is already loaded, either as a virtual
+			 * script, or as an individual script src="" element.
+			 */
+			if (Tapestry.ScriptManager.virtualScripts.member(assetURL))
+				return;
 
-				head.insert( {
-					bottom : element
-				});
+			if (Tapestry.ScriptManager.contains(document.scripts, "src",
+					assetURL))
+				return;
 
-				added.push(element);
+			scriptsToLoad.push(assetURL);
+		});
 
-				if (emulated)
-					document.scripts.push(element);
-			});
+		/*
+		 * Set it up last script to first script. The last script's callback is
+		 * the main callback (the code to execute after all scripts are loaded).
+		 * The 2nd to last script's callback loads the last script. Prototype's
+		 * Array.inject() is effectively the same as Clojure's reduce().
+		 */
+		scriptsToLoad.reverse();
 
-		}
+		var topCallback = scriptsToLoad.inject(callback, function(nextCallback,
+				scriptURL) {
+			return function() {
+				Tapestry.ScriptManager.loadScript(scriptURL, nextCallback);
+			};
+		});
 
-		new Tapestry.ScriptLoadMonitor(added, callback);
+		/* Kick it off with the callback that loads the first script. */
+		topCallback.call();
 	},
 
 	addStylesheets : function(stylesheets) {
@@ -1967,7 +1934,6 @@ Tapestry.ScriptManager = {
 					 * Careful about media types, some browser will break if it
 					 * ends up as 'null'.
 					 */
-
 					if (s.media != undefined)
 						element.writeAttribute('media', s.media);