Fix some issues in the xsiframe linker
- Add support for including <stylesheet> tags
- Fix a bug in computeScriptBase.js
Review at http://gwt-code-reviews.appspot.com/1057801
Review by: jgw@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9158 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/ResourceInjectionUtil.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/ResourceInjectionUtil.java
index 0986ee4..4691444 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/ResourceInjectionUtil.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/ResourceInjectionUtil.java
@@ -27,6 +27,9 @@
* Utility class to help linkers do resource injection.
*/
public class ResourceInjectionUtil {
+ /**
+ * Installs stylesheets and scripts
+ */
public static StringBuffer injectResources(StringBuffer selectionScript,
ArtifactSet artifacts) {
// Add external dependencies
@@ -50,6 +53,40 @@
return selectionScript;
}
+ /**
+ * Installs stylesheets using the installOneStylesheet method, which is
+ * assumed to be defined on the page.
+ */
+ public static StringBuffer injectStylesheets(StringBuffer selectionScript,
+ ArtifactSet artifacts) {
+ int startPos = selectionScript.indexOf("// __MODULE_STYLES__");
+ if (startPos != -1) {
+ for (StylesheetReference resource : artifacts.find(StylesheetReference.class)) {
+ String text = generateNewStylesheetInjector(resource.getSrc());
+ selectionScript.insert(startPos, text);
+ startPos += text.length();
+ }
+ }
+ return selectionScript;
+ }
+
+ /**
+ * Generate a Snippet of JavaScript to inject an external stylesheet using
+ * the installOneStylesheet helper function (which is assumed to already
+ * be defined on the page.
+ *
+ * <pre>
+ * installOneStylesheet(URL, HREF_EXPR);
+ * </pre>
+ */
+ private static String generateNewStylesheetInjector(String stylesheetUrl) {
+ String hrefExpr = "'" + stylesheetUrl + "'";
+ if (isRelativeURL(stylesheetUrl)) {
+ hrefExpr = "__MODULE_FUNC__.__moduleBase + " + hrefExpr;
+ }
+ return "installOneStylesheet('" + stylesheetUrl + "', " + hrefExpr + ");\n";
+ }
+
private static String generateScriptInjector(String scriptUrl) {
if (isRelativeURL(scriptUrl)) {
return " if (!__gwt_scriptsLoaded['"
@@ -67,7 +104,7 @@
+ scriptUrl + "\\\"></script>');\n" + " }\n";
}
}
-
+
/**
* Generate a Snippet of JavaScript to inject an external stylesheet.
*
@@ -95,7 +132,7 @@
+ " $doc.getElementsByTagName('head')[0].appendChild(l);\n "
+ "}\n";
}
-
+
/**
* Determines whether or not the URL is relative.
*
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/computeScriptBase.js b/dev/core/src/com/google/gwt/core/ext/linker/impl/computeScriptBase.js
index 066ce99..dd27fa0 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/computeScriptBase.js
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/computeScriptBase.js
@@ -15,11 +15,13 @@
*/
/**
- * Determine our own script's URL via magic :)
- * This function produces one side-effect, it sets base to the module's
- * base url. Note: although this script returns the module's base url, it
- * also sets the global 'base' variable for backwards compatability with older
- * linkers.
+ * Determine our own script's URL by trying various things
+ *
+ * First - use the baseUrl meta tag if it exists
+ * Second - look for a script tag with the src set to MODULE_NAME.nocache.js and
+ * if it's found, use it to determine the baseUrl
+ * Third - if the page is not already loaded, try to use some document.write
+ * magic to install a temporary tag and use that to determine the baseUrl.
*
* This is included into the selection scripts
* wherever COMPUTE_SCRIPT_BASE appears with underlines
@@ -32,10 +34,15 @@
// Note: the base variable should not be defined in this function because in
// the older templates (like IFrameTemplate.js), base is defined outside this
// function, and they rely on the fact that calling computeScriptBase will set
- // that base variable rather than using the return value.
+ // that base variable rather than using the return value. Instead, we define
+ // a tempBase variable, and then right before we return, we also set the
+ // base variable for backwards compatability
+ var tempBase = '';
+
if (metaVal != null) {
- base = metaVal;
- return base;
+ tempBase = metaVal;
+ base = tempBase;
+ return tempBase;
}
// The baseUrl will be similar to the URL for this script's URL
@@ -54,16 +61,18 @@
// it. Note that this will not work in the Late Loading case due to the
// document.write call.
if (!thisScript) {
- // Put in a marker script element which should be the first script tag after
- // the tag we're looking for. To find it, we start at the marker and walk
- // backwards until we find a script.
- var markerId = "__gwt_marker___MODULE_NAME__";
- var markerScript;
- $doc.write('<script id="' + markerId + '"></script>');
- markerScript = $doc.getElementById(markerId);
- thisScript = markerScript && markerScript.previousSibling;
- while (thisScript && thisScript.tagName != 'SCRIPT') {
- thisScript = thisScript.previousSibling;
+ if (typeof isBodyLoaded == 'undefined' || !isBodyLoaded()) {
+ // Put in a marker script element which should be the first script tag after
+ // the tag we're looking for. To find it, we start at the marker and walk
+ // backwards until we find a script.
+ var markerId = "__gwt_marker___MODULE_NAME__";
+ var markerScript;
+ $doc.write('<script id="' + markerId + '"></script>');
+ markerScript = $doc.getElementById(markerId);
+ thisScript = markerScript && markerScript.previousSibling;
+ while (thisScript && thisScript.tagName != 'SCRIPT') {
+ thisScript = thisScript.previousSibling;
+ }
}
}
@@ -84,21 +93,21 @@
if (thisScript && thisScript.src) {
// Compute our base url
- base = getDirectoryOfFile(thisScript.src);
+ tempBase = getDirectoryOfFile(thisScript.src);
}
// Make the base URL absolute
- if (base == '') {
+ if (tempBase == '') {
// If there's a base tag, use it.
var baseElements = $doc.getElementsByTagName('base');
if (baseElements.length > 0) {
// It's always the last parsed base tag that will apply to this script.
- base = baseElements[baseElements.length - 1].href;
+ tempBase = baseElements[baseElements.length - 1].href;
} else {
// No base tag; the base must be the same as the document location.
- base = getDirectoryOfFile($doc.location.href);
+ tempBase = getDirectoryOfFile($doc.location.href);
}
- } else if ((base.match(/^\w+:\/\//))) {
+ } else if ((tempBase.match(/^\w+:\/\//))) {
// If the URL is obviously absolute, do nothing.
} else {
// Probably a relative URL; use magic to make the browser absolutify it.
@@ -106,8 +115,8 @@
// sure way! (A side benefit is it preloads clear.cache.gif)
// Note: this trick is harmless if the URL was really already absolute.
var img = $doc.createElement("img");
- img.src = base + 'clear.cache.gif';
- base = getDirectoryOfFile(img.src);
+ img.src = tempBase + 'clear.cache.gif';
+ tempBase = getDirectoryOfFile(img.src);
}
if (markerScript) {
@@ -115,5 +124,6 @@
markerScript.parentNode.removeChild(markerScript);
}
- return base;
-}
\ No newline at end of file
+ base = tempBase;
+ return tempBase;
+}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptAlreadyIncluded.js b/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptAlreadyIncluded.js
index 43d4b0a..0e3d90f 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptAlreadyIncluded.js
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptAlreadyIncluded.js
@@ -1,8 +1,13 @@
+// Installs a script which has already been downloaded (usually because the
+// script contents are combined with the bootstrap script in cases like SSSS).
+// Since the script contents are wrapped in a call to onScriptDownloaded, all
+// we do here is set up that function, which will install the contents in
+// a script tag appended to the install location.
function installScript(filename) {
// Provides the getInstallLocation() and getInstallLocationDoc() functions
__INSTALL_LOCATION__
- // Provides the setupWaitForBodyLoad() and isBodyLoaded() functions
+ // Provides the setupWaitForBodyLoad() function
__WAIT_FOR_BODY_LOADED__
function installCode(code) {
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptDirect.js b/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptDirect.js
index 16c19aa..e843e7b 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptDirect.js
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptDirect.js
@@ -1,8 +1,10 @@
+// Installs the script directly, by simply appending a script tag with the
+// src set to the correct location to the install location.
function installScript(filename) {
// Provides the getInstallLocation() and getInstallLocationDoc() functions
__INSTALL_LOCATION__
- // Provides the setupWaitForBodyLoad() and isBodyLoaded() functions
+ // Provides the setupWaitForBodyLoad()function
__WAIT_FOR_BODY_LOADED__
function installCode(code) {
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptEarlyDownload.js b/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptEarlyDownload.js
index 877e4e2..a9aa739 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptEarlyDownload.js
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptEarlyDownload.js
@@ -1,8 +1,12 @@
+// Installs the script by immediately appending a script tag to the body head
+// with the src set, to get the script contents. The script contents are then
+// installed into a script tag which is added to the install location (because
+// the script contents will be wrapped in a call to onScriptDownloaded()).
function installScript(filename) {
// Provides the getInstallLocation() and getInstallLocationDoc() functions
__INSTALL_LOCATION__
- // Provides the setupWaitForBodyLoad() and isBodyLoaded() functions
+ // Provides the setupWaitForBodyLoad() function
__WAIT_FOR_BODY_LOADED__
function installCode(code) {
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptNull.js b/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptNull.js
index e3787b9..382e34a 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptNull.js
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptNull.js
@@ -1,3 +1,5 @@
+// Assumes that the script contents are directly part of the bootstrap script
+// and do not need to be installed anywhere.
function installScript(filename) {
// Does nothing
}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/loadExternalStylesheets.js b/dev/core/src/com/google/gwt/core/ext/linker/impl/loadExternalStylesheets.js
new file mode 100644
index 0000000..8935924
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/loadExternalStylesheets.js
@@ -0,0 +1,24 @@
+function loadExternalStylesheets() {
+ // Setup for loading of external stylesheets. Resources are loaded
+ // only once, even when multiple modules depend on them. This API must not
+ // change across GWT versions.
+ if (!$wnd.__gwt_stylesLoaded) { $wnd.__gwt_stylesLoaded = {}; }
+
+ function installOneStylesheet(stylesheetUrl, hrefExpr) {
+ if (!__gwt_stylesLoaded[stylesheetUrl]) {
+ if (isBodyLoaded()) {
+ var l = $doc.createElement('link');
+ l.setAttribute('rel', 'stylesheet');
+ l.setAttribute('href', hrefExpr);
+ $doc.getElementsByTagName('head')[0].appendChild(l);
+ } else {
+ $doc.write("<link id='' rel='stylesheet' href='" + hrefExpr + "'></li" + "nk>");
+ }
+ __gwt_stylesLoaded[stylesheetUrl] = true;
+ }
+ }
+
+ sendStats('loadExternalRefs', 'begin');
+ // __MODULE_STYLES__
+ sendStats('loadExternalRefs', 'end');
+}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/waitForBodyLoaded.js b/dev/core/src/com/google/gwt/core/ext/linker/impl/waitForBodyLoaded.js
index 839a68d..35ed95d 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/waitForBodyLoaded.js
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/waitForBodyLoaded.js
@@ -1,8 +1,3 @@
-// Check whether the body is loaded.
-function isBodyLoaded() {
- return (/loaded|complete/.test($doc.readyState));
-}
-
// Setup code which waits for the body to be loaded and then calls the
// callback function
function setupWaitForBodyLoad(callback) {
diff --git a/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeLinker.java b/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeLinker.java
index 23d8b9f..8ea1b9e 100644
--- a/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeLinker.java
+++ b/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeLinker.java
@@ -25,6 +25,7 @@
import com.google.gwt.core.ext.linker.LinkerOrder.Order;
import com.google.gwt.core.ext.linker.Shardable;
import com.google.gwt.core.ext.linker.impl.PropertiesMappingArtifact;
+import com.google.gwt.core.ext.linker.impl.ResourceInjectionUtil;
import com.google.gwt.core.ext.linker.impl.SelectionScriptLinker;
import com.google.gwt.dev.About;
import com.google.gwt.dev.js.JsToStringGenerationVisitor;
@@ -65,13 +66,15 @@
includeJs(ss, logger, getJsProperties(context), "__PROPERTIES__");
includeJs(ss, logger, getJsProcessMetas(context), "__PROCESS_METAS__");
includeJs(ss, logger, getJsComputeScriptBase(context), "__COMPUTE_SCRIPT_BASE__");
+ includeJs(ss, logger, getJsLoadExternalStylesheets(context), "__LOAD_STYLESHEETS__");
+ ss = ResourceInjectionUtil.injectStylesheets(ss, artifacts);
+ ss = permutationsUtil.addPermutationsJs(ss, logger, context);
+
replaceAll(ss, "__MODULE_FUNC__", context.getModuleFunctionName());
replaceAll(ss, "__MODULE_NAME__", context.getModuleName());
replaceAll(ss, "__HOSTED_FILENAME__", getHostedFilename());
- permutationsUtil.addPermutationsJs(ss, logger, context);
-
return ss.toString();
}
@@ -99,6 +102,10 @@
protected String getJsInstallScript(LinkerContext context) {
return "com/google/gwt/core/ext/linker/impl/installScriptEarlyDownload.js";
}
+
+ protected String getJsLoadExternalStylesheets(LinkerContext context) {
+ return "com/google/gwt/core/ext/linker/impl/loadExternalStylesheets.js";
+ }
protected String getJsPermutations(LinkerContext context) {
return "com/google/gwt/core/ext/linker/impl/permutations.js";
diff --git a/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeTemplate.js b/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeTemplate.js
index 5b458ca..fe7c0dc 100644
--- a/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeTemplate.js
+++ b/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeTemplate.js
@@ -22,6 +22,10 @@
* Internal Helper Functions
***************************************************************************/
+ function isBodyLoaded() {
+ return (/loaded|complete/.test($doc.readyState));
+ }
+
function isHostedMode() {
var query = $wnd.location.search;
return (query.indexOf('gwt.codesvr=') != -1);
@@ -90,6 +94,8 @@
// __MODULE_FUNC__.__softPermutationId variables if needed
__PERMUTATIONS__
+ // Provides the loadExternalStylesheets() function
+ __LOAD_STYLESHEETS__
/****************************************************************************
* Bootstrap startup code
@@ -103,11 +109,9 @@
// Must be done right before the "bootstrap" "end" stat is sent
var filename = getCompiledCodeFilename();
+ loadExternalStylesheets();
+
sendStats('bootstrap', 'end');
- // For now, send this dummy statistic since some people are depending on it
- // being present. TODO(unnurg): remove this statistic soon
- sendStats('loadExternalRefs', 'begin');
- sendStats('loadExternalRefs', 'end');
installScript(filename);