Fixed a number of problems with the new startup, including:
- Got rid of gwt:base; module base URL now automagically computed from script include tag
- Resolved several module base URL problems
- Hosted mode now almost identical startup to web mode
Review by: jgw
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@576 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/GWTCompiler.java b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
index fa7ab4b..df3aa23 100644
--- a/dev/core/src/com/google/gwt/dev/GWTCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
@@ -481,7 +481,8 @@
// Generate the call to tell the bootstrap code that we're ready to go.
sb.append("\n");
- sb.append("parent." + moduleFunction + ".onScriptLoad(window);\n");
+ sb.append("if ($wnd." + moduleFunction + ") $wnd." + moduleFunction
+ + ".onScriptLoad();\n");
sb.append("--></script></body></html>\n");
String s = sb.toString();
diff --git a/dev/core/src/com/google/gwt/dev/util/SelectionScriptGenerator.java b/dev/core/src/com/google/gwt/dev/util/SelectionScriptGenerator.java
index aa3709a..6b13ca6 100644
--- a/dev/core/src/com/google/gwt/dev/util/SelectionScriptGenerator.java
+++ b/dev/core/src/com/google/gwt/dev/util/SelectionScriptGenerator.java
@@ -56,10 +56,52 @@
public class SelectionScriptGenerator {
private static String cssInjector(String cssUrl) {
- return " if (!__gwt_stylesLoaded['" + cssUrl + "']) {\n"
- + " __gwt_stylesLoaded['" + cssUrl + "'] = true;\n"
- + " document.write('<link rel=\\\"stylesheet\\\" href=\\\"" + cssUrl
- + "\\\">');\n" + " }\n";
+ if (isRelativeURL(cssUrl)) {
+ return " if (!__gwt_stylesLoaded['"
+ + cssUrl
+ + "']) {\n"
+ + " __gwt_stylesLoaded['"
+ + cssUrl
+ + "'] = true;\n"
+ + " document.write('<link rel=\\\"stylesheet\\\" href=\\\"'+base+'"
+ + cssUrl + "\\\">');\n" + " }\n";
+ } else {
+ return " if (!__gwt_stylesLoaded['" + cssUrl + "']) {\n"
+ + " __gwt_stylesLoaded['" + cssUrl + "'] = true;\n"
+ + " document.write('<link rel=\\\"stylesheet\\\" href=\\\""
+ + cssUrl + "\\\">');\n" + " }\n";
+ }
+ }
+
+ /**
+ * Determines whether or not the URL is relative.
+ *
+ * @param src the test url
+ * @return <code>true</code> if the URL is relative, <code>false</code> if
+ * not
+ */
+ private static boolean isRelativeURL(String src) {
+ // A straight absolute url for the same domain, server, and protocol.
+ if (src.startsWith("/")) {
+ return false;
+ }
+
+ // If it can be parsed as a URL, then it's probably absolute.
+ try {
+ URL testUrl = new URL(src);
+
+ // Let's guess that it is absolute (thus, not relative).
+ return false;
+ } catch (MalformedURLException e) {
+ // Do nothing, since it was a speculative parse.
+ }
+
+ // Since none of the above matched, let's guess that it's relative.
+ return true;
+ }
+
+ private static String literal(String lit) {
+ return "\"" + lit + "\"";
}
private static void replaceAll(StringBuffer buf, String search, String replace) {
@@ -71,10 +113,21 @@
}
private static String scriptInjector(String scriptUrl) {
- return " if (!__gwt_scriptsLoaded['" + scriptUrl + "']) {\n"
- + " __gwt_scriptsLoaded['" + scriptUrl + "'] = true;\n"
- + " document.write('<script language=\\\"javascript\\\" src=\\\""
- + scriptUrl + "\\\"></script>');\n" + " }\n";
+ if (isRelativeURL(scriptUrl)) {
+ return " if (!__gwt_scriptsLoaded['"
+ + scriptUrl
+ + "']) {\n"
+ + " __gwt_scriptsLoaded['"
+ + scriptUrl
+ + "'] = true;\n"
+ + " document.write('<script language=\\\"javascript\\\" src=\\\"'+base+'"
+ + scriptUrl + "\\\"></script>');\n" + " }\n";
+ } else {
+ return " if (!__gwt_scriptsLoaded['" + scriptUrl + "']) {\n"
+ + " __gwt_scriptsLoaded['" + scriptUrl + "'] = true;\n"
+ + " document.write('<script language=\\\"javascript\\\" src=\\\""
+ + scriptUrl + "\\\"></script>');\n" + " }\n";
+ }
}
private final String moduleFunction;
@@ -88,9 +141,7 @@
* same generated code for the same set of compilations.
*/
private final Map propertyValuesSetByStrongName = new TreeMap();
-
private final Scripts scripts;
-
private final Styles styles;
/**
@@ -208,12 +259,24 @@
for (Iterator iterator = propValuesSet.iterator(); iterator.hasNext();) {
String[] propValues = (String[]) iterator.next();
- pw.print(" O([");
+ pw.print(" unflattenKeylistIntoAnswers([");
+ boolean firstPrint = true;
for (int i = 0; i < orderedProps.length; i++) {
- if (i > 0) {
- pw.print(",");
+ Property prop = orderedProps[i];
+ String activeValue = prop.getActiveValue();
+ if (activeValue == null) {
+ // This is a call to a property provider function; we need it to
+ // select the script.
+ //
+ if (!firstPrint) {
+ pw.print(",");
+ }
+ firstPrint = false;
+ pw.print(literal(propValues[i]));
+ } else {
+ // This property was explicitly set at compile-time; we do not need
+ // it.
}
- pw.print(literal(propValues[i]));
}
pw.print("]");
pw.print(",");
@@ -253,56 +316,30 @@
}
pw.println();
pw.println("};");
-
- // Emit a wrapper that verifies that the value is valid.
- // It is this function that is called directly to get the propery.
- pw.println();
- pw.println("props['" + prop.getName() + "'] = function() {");
- pw.println(" var v = providers['" + prop.getName() + "']();");
- pw.println(" var ok = values['" + prop.getName() + "'];");
- // Make sure this is an allowed value; if so, return.
- pw.println(" if (v in ok)");
- pw.println(" return v;");
- // Not an allowed value, so build a nice message and call the handler.
- pw.println(" var a = new Array(" + knownValues.length + ");");
- pw.println(" for (var k in ok)");
- pw.println(" a[ok[k]] = k;");
- pw.print(" " + moduleFunction + ".onBadProperty(");
- pw.print(literal(prop.getName()));
- pw.println(", a, v);");
- pw.println(" if (arguments.length > 0) throw null; else return null;");
- pw.println("};");
- pw.println();
}
}
}
private void genPropValues(PrintWriter pw) {
- pw.println(" var F;");
- pw.print(" var I = [");
for (int i = 0; i < orderedProps.length; i++) {
- if (i > 0) {
- pw.print(", ");
- }
-
Property prop = orderedProps[i];
String activeValue = prop.getActiveValue();
if (activeValue == null) {
- // This is a call to a property provider function.
+ // This is a call to a property provider function; we need it to
+ // select the script.
//
PropertyProvider provider = prop.getProvider();
assert (provider != null) : "expecting a default property provider to have been set";
// When we call the provider, we supply a bogus argument to indicate
// that it should throw an exception if the property is a bad value.
// The absence of arguments (as in hosted mode) tells it to return null.
- pw.print("(F=props['" + prop.getName() + "'],F(1))");
+ pw.print("[");
+ pw.print("computePropValue('" + prop.getName() + "')");
+ pw.print("]");
} else {
- // This property was explicitly set at compile-time.
- //
- pw.print(literal(activeValue));
+ // This property was explicitly set at compile-time; we do not need it.
}
}
- pw.println("];");
}
/**
@@ -316,8 +353,8 @@
replaceAll(buf, "__MODULE_FUNC__", moduleFunction);
replaceAll(buf, "__MODULE_NAME__", moduleName);
- // Remove hosted mode only stuff
if (orderedProps != null) {
+ // Remove shell servlet only stuff (hosted mode support)
int startPos = buf.indexOf("// __SHELL_SERVLET_ONLY_BEGIN__");
int endPos = buf.indexOf("// __SHELL_SERVLET_ONLY_END__");
buf.delete(startPos, endPos);
@@ -361,14 +398,10 @@
// Web mode or hosted mode.
if (orderedProps.length > 0) {
pw.println();
- genPropValues(pw);
- pw.println();
genAnswers(pw);
pw.println();
pw.print(" strongName = answers");
- for (int i = 0; i < orderedProps.length; i++) {
- pw.print("[I[" + i + "]]");
- }
+ genPropValues(pw);
} else {
// Rare case of no properties; happens if you inherit from Core
// alone.
@@ -393,35 +426,4 @@
mainPw.print(buf.toString());
}
- /**
- * Determines whether or not the URL is relative.
- *
- * @param src the test url
- * @return <code>true</code> if the URL is relative, <code>false</code> if
- * not
- */
- private boolean isRelativeURL(String src) {
- // A straight absolute url for the same domain, server, and protocol.
- if (src.startsWith("/")) {
- return false;
- }
-
- // If it can be parsed as a URL, then it's probably absolute.
- try {
- URL testUrl = new URL(src);
-
- // Let's guess that it is absolute (thus, not relative).
- return false;
- } catch (MalformedURLException e) {
- // Do nothing, since it was a speculative parse.
- }
-
- // Since none of the above matched, let's guess that it's relative.
- return true;
- }
-
- private String literal(String lit) {
- return "\"" + lit + "\"";
- }
-
}
diff --git a/dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate.js b/dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate.js
index e10caba..c9cd47e 100644
--- a/dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate.js
+++ b/dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate.js
@@ -18,27 +18,33 @@
// ---------------- INTERNAL GLOBALS ----------------
// Cache symbols locally for good obfuscation
- var wnd = window;
- var external = wnd.external;
+ var wnd = window
+ ,doc = document
+ ,external = wnd.external
// These two variables gate calling gwtOnLoad; both must be true to start
- var scriptsDone, loadDone;
+ ,scriptsDone, loadDone
+
+ // If non-empty, an alternate base url for this module
+ ,base = ''
// A map of properties that were declared in meta tags
- var __gwt_metaProps = {};
+ ,metaProps = {}
- // A map of module rebasings
- var __gwt_base = {};
+ // Maps property names onto sets of legal values for that property.
+ ,values = []
- // These variables contain deferred-binding properties, values, and
- // providers.
- //
- var props = [];
- var values = [];
- var providers = [];
+ // Maps property names onto a function to compute that property.
+ ,providers = []
- // Property answers go here
- var answers = [];
+ // A multi-tier lookup map that uses actual property values to quickly find
+ // the strong name of the cache.js file to load.
+ ,answers = []
+
+ // Error functions. Default unset in compiled mode, may be set by meta props.
+ ,onLoadErrorFunc, propertyErrorFunc
+
+ ; // end of global vars
// ------------------ TRUE GLOBALS ------------------
@@ -50,31 +56,9 @@
// --------------- INTERNAL FUNCTIONS ---------------
- // The default module load error function; may be overwritten via meta props
- //
- function __gwt_onLoadError() {
- alert('Failed to load module __MODULE_NAME__' +
- '".\nPlease see the log in the development shell for details.');
- }
-
- // The default bad property error function; may be overwritten via meta props
- //
- function __gwt_onPropertyError(propName, allowedValues, badValue) {
- var msg = 'While attempting to load module __MODULE_NAME__, property \"'
- + propName;
- if (badValue != null) {
- msg += '\" was set to the unexpected value \"' + badValue + '\"';
- } else {
- msg += '\" was not specified';
- }
- msg += 'Allowed values: ' + allowedValues;
- alert(msg);
- }
-
-
function isHostedMode() {
return (external && external.gwtOnLoad &&
- (document.location.href.indexOf('gwt.hybrid') == -1));
+ (wnd.location.search.indexOf('gwt.hybrid') == -1));
}
@@ -83,66 +67,80 @@
//
function maybeStartModule() {
if (scriptsDone && loadDone) {
- var iframe = document.getElementById('__MODULE_NAME__');
+ var iframe = doc.getElementById('__MODULE_NAME__');
var frameWnd = iframe.contentWindow;
// copy the init handlers function into the iframe
frameWnd.__gwt_initHandlers = __MODULE_FUNC__.__gwt_initHandlers;
+ // inject hosted mode property evaluation function
+ if (isHostedMode()) {
+ frameWnd.__gwt_getProperty = function(name) {
+ return computePropValue(name);
+ };
+ }
// remove this whole function from the global namespace to allow GC
__MODULE_FUNC__ = null;
- iframe.contentWindow.gwtOnLoad(__gwt_onLoadError, '__MODULE_NAME__');
+ frameWnd.gwtOnLoad(onLoadErrorFunc, '__MODULE_NAME__');
+ }
+ }
+
+ // Determine our own script's URL via magic :)
+ //
+ function computeScriptBase() {
+ doc.write('<script id="__gwt_marker___MODULE_NAME__"></script>');
+ var markerScript = doc.getElementById("__gwt_marker___MODULE_NAME__");
+ // the previous script element is this script
+ var content = markerScript.previousSibling.src;
+ if (content) {
+ var eq = content.lastIndexOf('/');
+ if (eq >= 0) {
+ base = content.substring(0, eq + 1);
+ }
+ // remove the marker element
+ markerScript.parentNode.removeChild(markerScript);
}
}
// Called to slurp up all <meta> tags:
- // gwt:property, gwt:base, gwt:onPropertyErrorFn, gwt:onLoadErrorFn
+ // gwt:property, gwt:onPropertyErrorFn, gwt:onLoadErrorFn
//
function processMetas() {
var metas = document.getElementsByTagName('meta');
-
for (var i = 0, n = metas.length; i < n; ++i) {
- var meta = metas[i];
- var name = meta.getAttribute('name');
+ var meta = metas[i], name = meta.getAttribute('name'), content;
if (name) {
if (name == 'gwt:property') {
- var content = meta.getAttribute('content');
+ content = meta.getAttribute('content');
if (content) {
- var name = content, value = '';
- var eq = content.indexOf('=');
- if (eq != -1) {
+ var value, eq = content.indexOf('=');
+ if (eq >= 0) {
name = content.substring(0, eq);
value = content.substring(eq+1);
+ } else {
+ name = content;
+ value = '';
}
- __gwt_metaProps[name] = value;
+ metaProps[content] = value;
}
} else if (name == 'gwt:onPropertyErrorFn') {
- var content = meta.getAttribute('content');
+ content = meta.getAttribute('content');
if (content) {
try {
- __gwt_onPropertyError = eval(content);
+ propertyErrorFunc = eval(content);
} catch (e) {
alert('Bad handler \"' + content +
'\" for \"gwt:onPropertyErrorFn\"');
}
}
} else if (name == 'gwt:onLoadErrorFn') {
- var content = meta.getAttribute('content');
+ content = meta.getAttribute('content');
if (content) {
try {
- __gwt_onLoadError = eval(content);
+ onLoadErrorFunc = eval(content);
} catch (e) {
alert('Bad handler \"' + content + '\" for \"gwt:onLoadErrorFn\"');
}
}
- } else if (name == 'gwt:base') {
- var content = meta.getAttribute('content');
- var eqPos = content.lastIndexOf('=');
- if (eqPos == -1) {
- continue;
- }
- var moduleBase = content.substring(0, eqPos);
- var moduleName = content.substring(eqPos + 1);
- __gwt_base[moduleName] = moduleBase;
}
}
}
@@ -163,23 +161,41 @@
* Returns a meta property value, if any. Used by DefaultPropertyProvider.
*/
function __gwt_getMetaProperty(name) {
- var value = __gwt_metaProps[name];
+ var value = metaProps[name];
return (value == null) ? null : value;
}
- // Deferred-binding mapper function.
+ // Deferred-binding mapper function. Sets a value into the several-level-deep
+ // answers map. The keys are specified by a non-zero-length propValArray,
+ // which should be a flat array target property values. Used by the generated
+ // PERMUTATIONS code.
//
- function O(a,v) {
+ function unflattenKeylistIntoAnswers(propValArray, value) {
var answer = answers;
- var i = -1;
- var n = a.length - 1;
- while (++i < n) {
- if (!(a[i] in answer)) {
- answer[a[i]] = [];
- }
- answer = answer[a[i]];
+ for (var i = 0, n = propValArray.length - 1; i < n; ++i) {
+ // lazy initialize an empty object for the current key if needed
+ answer = answer[propValArray[i]] || (answer[propValArray[i]] = []);
}
- answer[a[n]] = v;
+ // set the final one to the value
+ answer[propValArray[n]] = value;
+ }
+
+ // Computes the value of a given property. propName must be a valid property
+ // name. Used by the generated PERMUTATIONS code.
+ //
+ function computePropValue(propName) {
+ var value = providers[propName](), allowedValuesMap = values[propName];
+ if (value in allowedValuesMap) {
+ return value;
+ }
+ var allowedValuesList = [];
+ for (var k in allowedValuesMap) {
+ allowedValuesList[allowedValuesMap[k]] = k;
+ }
+ if (propertyErrorFunc) {
+ propertyErrorFunc(propName, allowedValuesList, value);
+ }
+ throw null;
}
// --------------- PROPERTY PROVIDERS ---------------
@@ -204,55 +220,47 @@
loadDone = true;
maybeStartModule();
}
-
+
// --------------- STRAIGHT-LINE CODE ---------------
+ // do it early for compile/browse rebasing
+ computeScriptBase();
+
// __SHELL_SERVLET_ONLY_BEGIN__
// Force shell servlet to serve compiled output for web mode
if (!isHostedMode()) {
- document.write('<script src="__MODULE_NAME__.nocache.js?compiled"></script>');
+ doc.write('<script src="' + base + '__MODULE_NAME__.nocache.js?compiled"></script>');
return;
}
+
+ // Default shell servlet load error function
+ //
+ onLoadErrorFunc = function() {
+ alert('Failed to load module __MODULE_NAME__' +
+ '".\nPlease see the log in the development shell for details.');
+ };
+
+ // Default shell servlet property error function
+ //
+ propertyErrorFunc = function(propName, allowedValues, badValue) {
+ var msg = 'While attempting to load module __MODULE_NAME__, property \"'
+ + propName;
+ if (badValue != null) {
+ msg += '\" was set to the unexpected value \"' + badValue + '\"';
+ } else {
+ msg += '\" was not specified';
+ }
+ msg += 'Allowed values: ' + allowedValues;
+ alert(msg);
+ };
+
// __SHELL_SERVLET_ONLY_END__
processMetas();
var strongName;
if (isHostedMode()) {
- // In hosted mode, inject the script frame directly.
- var iframe = document.createElement('iframe');
- iframe.id = '__MODULE_NAME__';
- iframe.style.width = '0px';
- iframe.style.height = '0px';
- iframe.style.border = '0px';
- document.body.appendChild(iframe);
-
- iframe.src = 'blank.html';
- iframe.onload = function() {
- var frameWnd = iframe.contentWindow;
- frameWnd.$wnd = wnd;
- frameWnd.$doc = wnd.document;
-
- // inject hosted mode property evaluation function
- frameWnd.__gwt_getProperty = function(name) {
- return providers[name]();
- };
-
- // inject gwtOnLoad
- frameWnd.gwtOnLoad = function(errFn, modName) {
- if (!external.gwtOnLoad(frameWnd, modName)) {
- errFn(modName);
- }
- }
-
- // Hook the iframe's onunload, so that the hosted browser has a chance
- // to clean up its ModuleSpaces.
- frameWnd.onunload = function() {
- external.gwtOnLoad(frameWnd, null);
- };
-
- __MODULE_FUNC__.onScriptLoad();
- };
+ strongName = "hosted.html?__MODULE_FUNC__";
} else {
try {
// __PERMUTATIONS_BEGIN__
@@ -263,19 +271,14 @@
return;
}
- // TODO: do we still need this query stuff?
- var query = location.search;
- query = query.substring(0, query.indexOf('&'));
-
- var base = __gwt_base['__MODULE_NAME__'];
- var newUrl = (base ? base + '/' : '') + strongName + '.cache.html' + query;
- document.write('<iframe id="__MODULE_NAME__" style="width:0;height:0;border:0" src="' + newUrl + '"></iframe>');
+ strongName += '.cache.html';
}
+ doc.write('<iframe id="__MODULE_NAME__" style="width:0;height:0;border:0" src="' + base + strongName + '"></iframe>');
// __MODULE_DEPS_BEGIN__
// Module dependencies, such as scripts and css
// __MODULE_DEPS_END__
- document.write('<script>__MODULE_FUNC__.onInjectionDone(\'__MODULE_NAME__\')</script>');
+ doc.write('<script>__MODULE_FUNC__.onInjectionDone(\'__MODULE_NAME__\')</script>');
}
// Called from compiled code to hook the window's resize & load events (the
@@ -290,15 +293,18 @@
// 3) This function will be copied directly into the script frame window!
//
__MODULE_FUNC__.__gwt_initHandlers = function(resize, beforeunload, unload) {
- var wnd = window;
- var oldOnResize = wnd.onresize;
+ var wnd = window
+ , oldOnResize = wnd.onresize
+ , oldOnBeforeUnload = wnd.onbeforeunload
+ , oldOnUnload = wnd.onunload
+ ;
+
wnd.onresize = function() {
resize();
if (oldOnResize)
oldOnResize();
};
- var oldOnBeforeUnload = wnd.onbeforeunload;
wnd.onbeforeunload = function() {
var ret = beforeunload();
@@ -311,7 +317,6 @@
return oldRet;
};
- var oldOnUnload = wnd.onunload;
wnd.onunload = function() {
unload();
if (oldOnUnload)
diff --git a/user/src/com/google/gwt/core/public/blank.html b/user/src/com/google/gwt/core/public/blank.html
deleted file mode 100644
index 8c7fe21..0000000
--- a/user/src/com/google/gwt/core/public/blank.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<html>
-</html>
\ No newline at end of file
diff --git a/user/src/com/google/gwt/core/public/gwt.js b/user/src/com/google/gwt/core/public/gwt.js
index a5468a4..03dc568 100644
--- a/user/src/com/google/gwt/core/public/gwt.js
+++ b/user/src/com/google/gwt/core/public/gwt.js
@@ -12,29 +12,21 @@
// License for the specific language governing permissions and limitations under
// the License.
//
-// This startup script should be included in host pages either just after
-// <body> or inside the <head> after module <meta> tags.
+// This startup script is for legacy support and is now deprecated. Instead of
+// using this script, just include the selection script directly.
//
(function(){
var metas = document.getElementsByTagName("meta");
-
for (var i = 0, n = metas.length; i < n; ++i) {
- var meta = metas[i];
- var name = meta.getAttribute("name");
- if (name) {
- if (name == "gwt:module") {
- var moduleName = meta.getAttribute("content");
- if (moduleName) {
- var eqPos = moduleName.lastIndexOf("=");
- if (eqPos != -1) {
- var base = moduleName.substring(0, eqPos);
- moduleName = moduleName.substring(eqPos + 1);
- window.__gwt_base = { };
- window.__gwt_base[moduleName] = base;
- moduleName = base + '/' + moduleName;
- }
- document.write('<script src="' + moduleName + '.nocache.js"></script>');
+ var meta = metas[i], name = meta.getAttribute("name");
+ if (name == "gwt:module") {
+ var content = meta.getAttribute("content");
+ if (content) {
+ var eqPos = content.lastIndexOf("=");
+ if (eqPos != -1) {
+ content = content.substring(0, eqPos) + '/' + content.substring(eqPos + 1);
}
+ document.write('<script src="' + content + '.nocache.js"></script>');
}
}
}
diff --git a/user/src/com/google/gwt/core/public/hosted.html b/user/src/com/google/gwt/core/public/hosted.html
new file mode 100644
index 0000000..538cff2
--- /dev/null
+++ b/user/src/com/google/gwt/core/public/hosted.html
@@ -0,0 +1,25 @@
+<html>
+<head><script>
+var $wnd = parent;
+var $doc = $wnd.document;
+var $moduleName;
+</script></head>
+<body>
+<font face='arial' size='-1'>This html file is for hosted mode support.</font>
+<script><!--
+function gwtOnLoad(errFn, modName){
+ $moduleName = modName;
+ if (!external.gwtOnLoad(window, modName)) {
+ if (errFn) {
+ errFn(modName);
+ }
+ }
+}
+
+window.onunload = function() {
+ external.gwtOnLoad(window, null);
+};
+
+var query = window.location.search.substr(1);
+if (query && $wnd[query]) $wnd[query].onScriptLoad();
+--></script></body></html>