Export user.agent and locale more reliably.
Introduces the js.embedded.properties configuration
parameter. This is a list of binding properties to
include in each permutation's initial fragment (in the
$permProps variable).
When using a CrossSiteIframeLinker, export these properties
in __gwt_activeModules so that Super Dev Mode can pick them
up.
Rationale: The Super Dev Mode bookmarklet calls
__gwt_activeModules[(module name)].bindings() to find out
which bindings it should compile with. However, this isn't
reliable when the developer restricts permutations by
setting these variables to a fixed value. This causes Super
Dev Mode to compile more permutations than necessary.
Bug: issue 7458
Change-Id: I2c7bf4635139eef3d938c4bd8aaaa19499c43bc3
Review-Link: https://gwt-review.googlesource.com/#/c/7702/
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 79e9eaa..60b08d5 100644
--- a/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeLinker.java
+++ b/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeLinker.java
@@ -481,6 +481,8 @@
+ "__gwtModuleFunction.__computePropValue);");
out.newlineOpt();
out.print("$sendStats('moduleStartup', 'end');");
+ out.newlineOpt();
+ out.print("__gwtModuleFunction.__moduleStartupDone($permProps);");
writeMagicComments(out, context, 0, strongName);
return out.toString();
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 25b85f6..b5af74c 100644
--- a/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeTemplate.js
+++ b/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeTemplate.js
@@ -86,6 +86,21 @@
($wnd.__gwt_activeModules = ($wnd.__gwt_activeModules || {}));
activeModules["__MODULE_NAME__"] = {moduleName: "__MODULE_NAME__"};
+ __MODULE_FUNC__.__moduleStartupDone = function(permProps) {
+ // Make embedded properties available to Super Dev Mode.
+ // (They override any properties already exported.)
+ var oldBindings = activeModules["__MODULE_NAME__"].bindings;
+ activeModules["__MODULE_NAME__"].bindings = function() {
+ var props = oldBindings ? oldBindings() : {};
+ var embeddedProps = permProps[__MODULE_FUNC__.__softPermutationId];
+ for (var i = 0; i < embeddedProps.length; i++) {
+ var pair = embeddedProps[i];
+ props[pair[0]] = pair[1];
+ }
+ return props;
+ };
+ };
+
/****************************************************************************
* Internal Helper functions that have been broken out into their own .js
* files for readability and for easy sharing between linkers. The linker
diff --git a/dev/core/src/com/google/gwt/dev/cfg/PermProps.java b/dev/core/src/com/google/gwt/dev/cfg/PermProps.java
index 167a3c0..4ce3f15 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/PermProps.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/PermProps.java
@@ -15,8 +15,17 @@
*/
package com.google.gwt.dev.cfg;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.thirdparty.guava.common.base.Objects;
import com.google.gwt.thirdparty.guava.common.collect.ImmutableList;
+import com.google.gwt.thirdparty.guava.common.collect.ImmutableMap;
+import com.google.gwt.thirdparty.guava.common.collect.Lists;
+import com.google.gwt.thirdparty.guava.common.collect.Sets;
+
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
/**
* The properties for one hard permutation.
@@ -44,6 +53,14 @@
}
/**
+ * Returns the binding properties in dependency order (permutation-independent).
+ */
+ public ImmutableList<BindingProperty> getBindingProperties() {
+ // Just take the first one.
+ return ImmutableList.copyOf(props.get(0).getOrderedProps());
+ }
+
+ /**
* Returns the properties for each soft permutation, ordered by soft permutation id.
*
* <p>If soft permutations aren't turned on, the list will contain one item.
@@ -97,6 +114,46 @@
}
/**
+ * Returns the binding property values to be embedded into the initial JavaScript fragment
+ * for this permutation. (There will be one map for each soft permutation.)
+ */
+ public ImmutableList<ImmutableMap<String, String>> findEmbeddedProperties(TreeLogger logger) {
+
+ Set<String> propsWanted = Sets.newTreeSet(getConfigProps().getStrings(
+ "js.embedded.properties"));
+
+ // Filter out any binding properties that don't exist.
+ SortedSet<String> propsToSave = Sets.newTreeSet();
+ for (BindingProperty prop : getBindingProperties()) {
+ String name = prop.getName();
+ if (propsWanted.remove(name)) {
+ propsToSave.add(name);
+ }
+ }
+
+ // Warn about binding properties that don't exist.
+ if (!propsWanted.isEmpty()) {
+ TreeLogger branch = logger.branch(Type.WARN,
+ propsWanted.size() + "properties listed in js.embedded.properties are undefined");
+ for (String prop : propsWanted) {
+ branch.log(Type.WARN, "undefined property: '" + prop + "'");
+ }
+ }
+
+ // Find the values.
+ List<ImmutableMap<String, String>> result = Lists.newArrayList();
+ for (BindingProps softProps : getSoftProps()) {
+ ImmutableMap.Builder<String, String> values = ImmutableMap.builder();
+ for (String key : propsToSave) {
+ values.put(key, softProps.getString(key, null));
+ }
+ result.add(values.build());
+ }
+
+ return ImmutableList.copyOf(result);
+ }
+
+ /**
* Dumps the properties for this hard permuation, for logging and soyc.
*/
public String prettyPrint() {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index eae6151..cdd6e94 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -110,6 +110,7 @@
import com.google.gwt.dev.js.JsSymbolResolver;
import com.google.gwt.dev.js.JsUnusedFunctionRemover;
import com.google.gwt.dev.js.SizeBreakdown;
+import com.google.gwt.dev.js.ast.JsArrayLiteral;
import com.google.gwt.dev.js.ast.JsContext;
import com.google.gwt.dev.js.ast.JsForIn;
import com.google.gwt.dev.js.ast.JsFunction;
@@ -121,7 +122,9 @@
import com.google.gwt.dev.js.ast.JsNode;
import com.google.gwt.dev.js.ast.JsParameter;
import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.js.ast.JsStringLiteral;
import com.google.gwt.dev.js.ast.JsVars;
+import com.google.gwt.dev.js.ast.JsVars.JsVar;
import com.google.gwt.dev.js.ast.JsVisitor;
import com.google.gwt.dev.util.DefaultTextOutput;
import com.google.gwt.dev.util.Empty;
@@ -137,6 +140,7 @@
import com.google.gwt.soyc.SoycDashboard;
import com.google.gwt.soyc.io.ArtifactsOutputDirectory;
import com.google.gwt.thirdparty.guava.common.annotations.VisibleForTesting;
+import com.google.gwt.thirdparty.guava.common.collect.ImmutableMap;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import com.google.gwt.thirdparty.guava.common.collect.Multimap;
@@ -153,6 +157,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
@@ -304,6 +309,8 @@
// TODO(stalcup): move to normalization
JsBreakUpLargeVarStatements.exec(jsProgram, props.getConfigProps());
+ embedBindingProperties(jsProgram, props);
+
// (8) Generate Js source
List<JsSourceMap> sourceInfoMaps = new ArrayList<JsSourceMap>();
boolean isSourceMapsEnabled = props.isTrueInAnyPermutation("compiler.useSourceMaps");
@@ -441,6 +448,38 @@
}
/**
+ * Embeds properties into $permProps for easy access from JavaScript.
+ */
+ private void embedBindingProperties(JsProgram jsProgram, PermProps props) {
+
+ // Generates a list of lists of pairs: [[["key", "value"], ...], ...]
+ // The outermost list is indexed by soft permutation id. Each item represents
+ // a map from binding properties to their values, but is stored as a list of pairs
+ // for easy iteration.
+ JsArrayLiteral permProps = new JsArrayLiteral(SourceOrigin.UNKNOWN);
+ for (ImmutableMap<String, String> propMap : props.findEmbeddedProperties(logger)) {
+ JsArrayLiteral entryList = new JsArrayLiteral(SourceOrigin.UNKNOWN);
+ for (Entry<String, String> entry : propMap.entrySet()) {
+ JsArrayLiteral pair = new JsArrayLiteral(SourceOrigin.UNKNOWN);
+ pair.getExpressions().add(new JsStringLiteral(SourceOrigin.UNKNOWN, entry.getKey()));
+ pair.getExpressions().add(new JsStringLiteral(SourceOrigin.UNKNOWN, entry.getValue()));
+ entryList.getExpressions().add(pair);
+ }
+ permProps.getExpressions().add(entryList);
+ }
+
+ // Generate: var $permProps = ...;
+ JsVar var = new JsVar(SourceOrigin.UNKNOWN,
+ jsProgram.getScope().findExistingUnobfuscatableName("$permProps"));
+ var.setInitExpr(permProps);
+ JsVars vars = new JsVars(SourceOrigin.UNKNOWN);
+ vars.add(var);
+
+ // Put it at the beginning for easy reference.
+ jsProgram.getGlobalBlock().getStatements().add(0, vars);
+ }
+
+ /**
* Generate Js code from the given Js ASTs. Also produces information about that transformation.
*/
private void generateJavaScriptCode(JavaToJavaScriptMap jjsMap, String[] jsFragments,
@@ -746,7 +785,7 @@
}
private Map<JsName, JsLiteral> renameJsSymbols(PermProps props) {
- Map<JsName, JsLiteral> internedLiteralByVariableName = null;
+ Map<JsName, JsLiteral> internedLiteralByVariableName;
switch (options.getOutput()) {
case OBFUSCATED:
internedLiteralByVariableName = runObfuscateNamer(props);
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsRootScope.java b/dev/core/src/com/google/gwt/dev/js/ast/JsRootScope.java
index 3850b37..f785d61 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsRootScope.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsRootScope.java
@@ -329,6 +329,7 @@
// GWT-defined identifiers
"$wnd", "$doc", "$moduleName", "$moduleBase", "$gwt_version", "$sessionId", "gwtOnLoad",
+ "$permProps",
// typeMarker 'tM' field will break JSO detection on window object if nullMethod is called 'tM'
"tM",
diff --git a/user/src/com/google/gwt/core/CompilerParameters.gwt.xml b/user/src/com/google/gwt/core/CompilerParameters.gwt.xml
index 8820488..654a175 100644
--- a/user/src/com/google/gwt/core/CompilerParameters.gwt.xml
+++ b/user/src/com/google/gwt/core/CompilerParameters.gwt.xml
@@ -119,4 +119,13 @@
is-multi-valued="false"/>
<set-configuration-property name="js.export.closurestyle.fullyqualified"
value="false" />
+
+ <!--
+ Specifies that a binding property should be included in the $permProps variable
+ in the generated JavaScript. This will allow Super Dev Mode to pick it up
+ regardless of how many permutations are generated.
+ -->
+ <define-configuration-property name="js.embedded.properties" is-multi-valued="true"/>
+ <set-configuration-property name="js.embedded.properties" value="locale"/>
+ <set-configuration-property name="js.embedded.properties" value="user.agent"/>
</module>