Index: dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java =================================================================== --- dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java (revision 1523) +++ dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java (working copy) @@ -275,28 +275,31 @@ HttpServletResponse response, TreeLogger logger, String partialPath, String moduleName) throws IOException { - // If the request is of the form ".../moduleName.nocache.js" or - // ".../moduleName-xs.nocache.js" then generate the selection script for - // them. - boolean nocacheHtml = partialPath.equals(moduleName + ".nocache.js"); - boolean nocacheScript = !nocacheHtml - && partialPath.equals(moduleName + "-xs.nocache.js"); - if (nocacheHtml || nocacheScript) { - // If the '?compiled' request property is specified, don't auto-generate. - if (request.getParameter("compiled") == null) { - // Generate the .js file. - try { - String js = genSelectionScript(logger, moduleName, nocacheScript); - setResponseCacheHeaders(response, 0); // do not cache selection script - response.setStatus(HttpServletResponse.SC_OK); - response.setContentType("text/javascript"); - response.getWriter().println(js); - return true; - } catch (UnableToCompleteException e) { - // The error will have already been logged. Continue, since this could - // actually be a request for a static file that happens to have an - // unfortunately confusing name. - } + // Check whether the requested filename matches the filename of + // one of our generated scripts. + if (!partialPath.startsWith(moduleName)) { + return false; + } + SelectionScriptGenerator.Type type = SelectionScriptGenerator.Type + .forFilenameSuffix(partialPath.substring(moduleName.length())); + if (type == null) { + return false; + } + + // If the '?compiled' request property is specified, don't auto-generate. + if (request.getParameter("compiled") == null) { + // Generate the .js file. + try { + String js = genSelectionScript(logger, moduleName, type); + setResponseCacheHeaders(response, 0); // do not cache selection script + response.setStatus(HttpServletResponse.SC_OK); + response.setContentType("text/javascript"); + response.getWriter().println(js); + return true; + } catch (UnableToCompleteException e) { + // The error will have already been logged. Continue, since this could + // actually be a request for a static file that happens to have an + // unfortunately confusing name. } } @@ -492,15 +495,14 @@ * definition of "hosted mode" JavaScript hasn't been compiled at this point. */ private String genSelectionScript(TreeLogger logger, String moduleName, - boolean asScript) throws UnableToCompleteException { - String msg = asScript ? "Generating a script selection script for module " - : "Generating an html selection script for module "; - msg += moduleName; + SelectionScriptGenerator.Type type) throws UnableToCompleteException { + String msg = "Generating a(n) " + type + + " selection script for module " + moduleName; logger.log(TreeLogger.TRACE, msg, null); ModuleDef moduleDef = getModuleDef(logger, moduleName); SelectionScriptGenerator gen = new SelectionScriptGenerator(moduleDef); - return gen.generateSelectionScript(false, asScript); + return gen.generateSelectionScript(false, type); } /** Index: dev/core/src/com/google/gwt/dev/GWTCompiler.java =================================================================== --- dev/core/src/com/google/gwt/dev/GWTCompiler.java (revision 1523) +++ dev/core/src/com/google/gwt/dev/GWTCompiler.java (working copy) @@ -902,23 +902,15 @@ private void writeSelectionScripts(TreeLogger logger, SelectionScriptGenerator selGen) { - { - String html = selGen.generateSelectionScript(obfuscate, false); - String fn = module.getName() + ".nocache.js"; + for (SelectionScriptGenerator.Type type : + SelectionScriptGenerator.Type.values()) { + String content = selGen.generateSelectionScript(obfuscate, type); + String fn = module.getName() + type.getFilenameSuffix(); File selectionFile = new File(outDir, fn); - Util.writeStringAsFile(selectionFile, html); + Util.writeStringAsFile(selectionFile, content); String msg = "Compilation selection script written to " + selectionFile.getAbsolutePath(); logger.log(TreeLogger.TRACE, msg, null); } - { - String html = selGen.generateSelectionScript(obfuscate, true); - String fn = module.getName() + "-xs.nocache.js"; - File selectionFile = new File(outDir, fn); - Util.writeStringAsFile(selectionFile, html); - String msg = "Compilation selection script written to " - + selectionFile.getAbsolutePath(); - logger.log(TreeLogger.TRACE, msg, null); - } } } Index: dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate.js =================================================================== --- dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate.js (revision 1523) +++ dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate.js (working copy) @@ -88,6 +88,20 @@ } } + // How to dynamically inject an external script reference. + // All templates must provide a version of this function. + // + function insertScript(uri) { + $doc.write(''); + } + + // How to dynamically inject an external stylesheet reference. + // All templates must provide a version of this function. + // + function insertStylesheet(uri) { + $doc.write(''); + } + // Determine our own script's URL via magic :) // This function produces one side-effect, it sets base to the module's // base url. @@ -279,7 +293,7 @@ // __SHELL_SERVLET_ONLY_BEGIN__ // Force shell servlet to serve compiled output for web mode if (!isHostedMode()) { - $doc.write(''); + insertScript(base + '__MODULE_NAME__.nocache.js?compiled'); return; } Index: dev/core/src/com/google/gwt/dev/util/SelectionScriptGenerator.java =================================================================== --- dev/core/src/com/google/gwt/dev/util/SelectionScriptGenerator.java (revision 1523) +++ dev/core/src/com/google/gwt/dev/util/SelectionScriptGenerator.java (working copy) @@ -55,21 +55,88 @@ */ public class SelectionScriptGenerator { + /** + * Specifies which type of selection script should be generated. + */ + public enum Type { + + /** + * For hosted mode. + */ + SCRIPT("-xs"), + + /** + * For traditional HTML documents. + */ + HTML(""), + + /** + * For SVG documents. + */ + SVG("-svg"), + +// /** +// * For XHTML documents. +// */ +// XHTML("-xhtml"), + +// /** +// * For XUL documents. +// */ +// XUL("-xul"), + + ; + + /** + * Derive the {@link Type} based on a filename suffix. + * This is the inverse of {@link #getFilenameSuffix}. + * + *
+ * Note that some suffixes are suffixes of other suffixes, so give
+ * the "whole" suffix.
+ *
+ * @param suffix filename suffix
+ * @return corresponding {@link Type}, or null
if none
+ */
+ public static Type forFilenameSuffix(String suffix) {
+ for (Type type : values()) {
+ if (type.suffix.equals(suffix)) {
+ return type;
+ }
+ }
+ return null;
+ }
+
+ private final String suffix;
+
+ Type(String suffix) {
+ this.suffix = suffix;
+ }
+
+ /**
+ * Get the filename suffix for generated scripts of this type.
+ */
+ public String getFilenameSuffix() {
+ return suffix + ".nocache.js";
+ }
+
+ /**
+ * Get the resource suffix for the internal template for this type.
+ */
+ public String getTemplateSuffix() {
+ return suffix + ".js";
+ }
+ };
+
private static String cssInjector(String cssUrl) {
if (isRelativeURL(cssUrl)) {
- return " if (!__gwt_stylesLoaded['"
- + cssUrl
- + "']) {\n"
- + " __gwt_stylesLoaded['"
- + cssUrl
- + "'] = true;\n"
- + " document.write('');\n" + " }\n";
+ return " if (!__gwt_stylesLoaded['" + cssUrl + "']) {\n"
+ + " __gwt_stylesLoaded['" + cssUrl + "'] = true;\n"
+ + " insertStylesheet(base + '" + cssUrl + "');\n" + " }\n";
} else {
return " if (!__gwt_stylesLoaded['" + cssUrl + "']) {\n"
+ " __gwt_stylesLoaded['" + cssUrl + "'] = true;\n"
- + " document.write('');\n" + " }\n";
+ + " insertStylesheet('" + cssUrl + "');\n" + " }\n";
}
}
@@ -114,19 +181,13 @@
private static String scriptInjector(String scriptUrl) {
if (isRelativeURL(scriptUrl)) {
- return " if (!__gwt_scriptsLoaded['"
- + scriptUrl
- + "']) {\n"
- + " __gwt_scriptsLoaded['"
- + scriptUrl
- + "'] = true;\n"
- + " document.write('');\n" + " }\n";
+ return " if (!__gwt_scriptsLoaded['" + scriptUrl + "']) {\n"
+ + " __gwt_scriptsLoaded['" + scriptUrl + "'] = true;\n"
+ + " insertScript(base + '" + scriptUrl + "');\n" + " }\n";
} else {
return " if (!__gwt_scriptsLoaded['" + scriptUrl + "']) {\n"
+ " __gwt_scriptsLoaded['" + scriptUrl + "'] = true;\n"
- + " document.write('');\n" + " }\n";
+ + " insertScript('" + scriptUrl + "');\n" + " }\n";
}
}
@@ -182,19 +243,21 @@
/**
* Generates a selection script based on the current settings.
*
+ * @param obfuscate whether to obfuscate the generated script
+ * @param type type of script to generate
* @return an JavaScript whose contents are the definition of a module.js file
*/
- public String generateSelectionScript(boolean obfuscate, boolean asScript) {
+ public String generateSelectionScript(boolean obfuscate, Type type) {
try {
String rawSource;
{
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
- String template = Utility.getFileFromClassPath(asScript
- ? "com/google/gwt/dev/util/SelectionScriptTemplate-xs.js"
- : "com/google/gwt/dev/util/SelectionScriptTemplate.js");
- genScript(pw, template);
+ String template = Utility.getFileFromClassPath(
+ "com/google/gwt/dev/util/SelectionScriptTemplate"
+ + type.getTemplateSuffix());
+ genScript(pw, template, type);
pw.close();
rawSource = sw.toString();
@@ -348,10 +411,11 @@
*
* @param pw
*/
- private void genScript(PrintWriter mainPw, String template) {
+ private void genScript(PrintWriter mainPw, String template, Type type) {
StringBuffer buf = new StringBuffer(template);
replaceAll(buf, "__MODULE_FUNC__", moduleFunction);
replaceAll(buf, "__MODULE_NAME__", moduleName);
+ replaceAll(buf, "__SCRIPT_SUFFIX__", type.getFilenameSuffix());
if (orderedProps != null) {
// Remove shell servlet only stuff (hosted mode support)
Index: dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate-xs.js
===================================================================
--- dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate-xs.js (revision 1523)
+++ dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate-xs.js (working copy)
@@ -77,6 +77,20 @@
}
}
+ // How to dynamically inject an external script reference.
+ // All templates must provide a version of this function
+ //
+ function insertScript(uri) {
+ $doc.write('');
+ }
+
+ // How to dynamically inject an external stylesheet reference.
+ // All templates must provide a version of this function.
+ //
+ function insertStylesheet(uri) {
+ $doc.write('');
+ }
+
// Determine our own script's URL via magic :)
//
function computeScriptBase() {
@@ -255,12 +269,12 @@
// __SHELL_SERVLET_ONLY_BEGIN__
if (!isHostedMode()) {
// Force shell servlet to serve compiled output for web mode
- $doc.write('');
+ insertScript(base + '__MODULE_NAME__-xs.nocache.js?compiled');
return;
} else {
// This script cannot run hosted mode properly; redirect to the html version
// TODO: figure out how to run hosted mode in the main window
- $doc.write('');
+ insertScript(base + '__MODULE_NAME__.nocache.js');
return;
}
// __SHELL_SERVLET_ONLY_END__
@@ -309,7 +323,7 @@
// __MODULE_DEPS_BEGIN__
// Module dependencies, such as scripts and css
// __MODULE_DEPS_END__
- $doc.write('');
+ insertScript(base + strongName);
}
// Called from compiled code to hook the window's resize & load events (the
Index: dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate-svg.js
===================================================================
--- dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate-svg.js (revision 1520)
+++ dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate-svg.js (working copy)
@@ -22,8 +22,8 @@
,$doc = document
,external = $wnd.external
- // These variables gate calling gwtOnLoad; all must be true to start
- ,scriptsDone, loadDone, bodyDone
+ // Wait for body to load before inserting ');
- markerScript = $doc.getElementById(markerId);
+ // Parse an URI
+ function parseURI(uri) {
+ var pat = /^(([^\/:?#]+):)?(\/\/([^\/?#]*))?([^?#]*)((\?([^#]*))?(#(.*))?)$/;
+ var parse = pat.exec(uri);
+ return {
+ scheme: parse[1] ? parse[1] : "",
+ authority: parse[3] ? parse[3] : "",
+ path: parse[5] ? parse[5] : "",
+ extra: parse[6] ? parse[6] : ""
+ };
+ }
- // Our script element is assumed to be the closest previous script element
- // to the marker, so start at the marker and walk backwards until we find
- // a script.
- thisScript = markerScript && markerScript.previousSibling;
- while (thisScript && thisScript.tagName != 'SCRIPT') {
- thisScript = thisScript.previousSibling;
+ // Resolve an URI reference relative to a base URI
+ function resolveURI(base, uri) {
+
+ // Parse uri
+ var uriParse = parseURI(uri);
+
+ // If URI is absolute, we ignore base URI
+ if (uriParse.authority) {
+ return uri;
+ }
+
+ // Combine base and uri paths
+ var baseParse = parseURI(base);
+ var path = uriParse.path && uriParse.path.match(/^\//) ?
+ uriParse.path : getDirectoryOfFile(baseParse.path) + uriParse.path;
+
+ // Return combined URI
+ return baseParse.scheme + baseParse.authority + path + uriParse.extra;
}
+ // Get the directory part of a path
function getDirectoryOfFile(path) {
var eq = path.lastIndexOf('/');
return (eq >= 0) ? path.substring(0, eq + 1) : '';
- };
+ }
- if (thisScript && thisScript.src) {
- // Compute our base url
- base = getDirectoryOfFile(thisScript.src);
+ // Get the last filename component of a path
+ function getBasenameOfFile(path) {
+ return path.substring(path.lastIndexOf('/') + 1);
}
- // Make the base URL absolute
- if (base == '') {
- // 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;
- } else {
- // No base tag; the base must be the same as the document location.
- var loc = $doc.location;
- var href = loc.href;
- base = getDirectoryOfFile(href.substr(0, href.length
- - loc.hash.length));
+ // Determine the absolute base URI for an element. We must walk the
+ // parent chain looking for "xml:base" tags and apply them top down.
+ function getXMLBase(elem) {
+
+ // Walk up to the document root gathering xml:base attributes
+ var bases = [];
+ for (node = elem; node; node = node.parentNode) {
+ if (node.getAttributeNS) {
+ var base = node.getAttributeNS(xmlNS, "base");
+ if (base) {
+ bases.push(base);
+ }
+ }
}
- } else if ((base.match(/^\w+:\/\//))) {
- // If the URL is obviously absolute, do nothing.
- } else {
- // Probably a relative URL; use magic to make the browser absolutify it.
- // I wish there were a better way to do this, but this seems the only
- // 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);
+
+ // Now collapse them into a single base URI
+ var base = elem.ownerDocument.documentURI;
+ while (bases.length > 0) {
+ base = resolveURI(base, bases.pop());
+ }
+ return base;
}
- if (markerScript) {
- // remove the marker element
- markerScript.parentNode.removeChild(markerScript);
+ // Find our script tag. We look for a ');
+ insertScript(base + '__MODULE_NAME____SCRIPT_SUFFIX__?compiled');
return;
}
@@ -322,56 +372,33 @@
// intentionally silent on property failure
return;
}
- strongName += '.cache.html';
+ strongName += '.cache.js';
}
var onBodyDoneTimerId;
function onBodyDone() {
if (!bodyDone) {
bodyDone = true;
- maybeStartModule();
-
if ($doc.removeEventListener) {
$doc.removeEventListener("DOMContentLoaded", onBodyDone, false);
}
if (onBodyDoneTimerId) {
clearInterval(onBodyDoneTimerId);
}
- }
- }
- var frameInjected;
- function maybeInjectFrame() {
- if (!frameInjected) {
- frameInjected = true;
- var iframe = $doc.createElement('iframe');
- // Prevents mixed mode security in IE6/7.
- iframe.src = "javascript:''";
- iframe.id = "__MODULE_NAME__";
- iframe.style.cssText = "position:absolute;width:0;height:0;border:none";
- // Due to an IE6/7 refresh quirk, this must be an appendChild.
- $doc.body.appendChild(iframe);
-
- /*
- * The src has to be set after the iframe is attached to the DOM to avoid
- * refresh quirks in Safari.
- */
- iframe.src = base + strongName;
+ // Inject chosen script once DOM is fully loaded
+ insertScript(base + strongName, "__MODULE_NAME__");
}
}
// For everyone that supports DOMContentLoaded.
if ($doc.addEventListener) {
- $doc.addEventListener("DOMContentLoaded", function() {
- maybeInjectFrame();
- onBodyDone();
- }, false);
+ $doc.addEventListener("DOMContentLoaded", onBodyDone, false);
}
// Fallback. If onBodyDone() gets fired twice, it's not a big deal.
var onBodyDoneTimerId = setInterval(function() {
- if (/loaded|complete/.test($doc.readyState)) {
- maybeInjectFrame();
+ if ($doc.getElementById('__MODULE_NAME__')) {
onBodyDone();
}
}, 50);
@@ -379,7 +406,6 @@
// __MODULE_DEPS_BEGIN__
// Module dependencies, such as scripts and css
// __MODULE_DEPS_END__
- $doc.write('');
}
// Called from compiled code to hook the window's resize & load events (the
Index: user/src/com/google/gwt/user/DocType.gwt.xml
===================================================================
--- user/src/com/google/gwt/user/DocType.gwt.xml (revision 0)
+++ user/src/com/google/gwt/user/DocType.gwt.xml (revision 0)
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+