Re-roll issue 1442804: SafeHtmlRenderer code gen for UiBinder
Review at http://gwt-code-reviews.appspot.com/1453812
Review by: rjrjr@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10345 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/text/shared/UiRenderer.java b/user/src/com/google/gwt/text/shared/UiRenderer.java
new file mode 100644
index 0000000..c2064b8
--- /dev/null
+++ b/user/src/com/google/gwt/text/shared/UiRenderer.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.text.shared;
+
+/**
+ * Marker interface for SafeHtmlRenderer implementations to be code generated
+ * from ui.xml files.
+ *
+ * @param <T> the type to render
+ */
+public interface UiRenderer<T> extends SafeHtmlRenderer<T> {
+}
diff --git a/user/src/com/google/gwt/uibinder/UiBinder.gwt.xml b/user/src/com/google/gwt/uibinder/UiBinder.gwt.xml
index 50cbc5b..3e2b6db 100644
--- a/user/src/com/google/gwt/uibinder/UiBinder.gwt.xml
+++ b/user/src/com/google/gwt/uibinder/UiBinder.gwt.xml
@@ -34,6 +34,10 @@
<set-configuration-property name="UiBinder.useLazyWidgetBuilders" value="false"/>
<generate-with class="com.google.gwt.uibinder.rebind.UiBinderGenerator">
+ <when-type-assignable class="com.google.gwt.text.shared.UiRenderer"/>
+ </generate-with>
+
+ <generate-with class="com.google.gwt.uibinder.rebind.UiBinderGenerator">
<when-type-assignable class="com.google.gwt.uibinder.client.UiBinder"/>
</generate-with>
</module>
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/CustomButtonParser.java b/user/src/com/google/gwt/uibinder/elementparsers/CustomButtonParser.java
index bb7d54b..7dfe858 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/CustomButtonParser.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/CustomButtonParser.java
@@ -69,7 +69,8 @@
String innerHtml = child.consumeInnerHtml(interpreter);
if (innerHtml.length() > 0) {
writer.addStatement("%s.%s().setHTML(%s);", fieldName,
- faceNameGetter(faceName), writer.declareTemplateCall(innerHtml));
+ faceNameGetter(faceName), writer.declareTemplateCall(innerHtml,
+ fieldName));
}
if (child.hasAttribute("image")) {
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/DialogBoxParser.java b/user/src/com/google/gwt/uibinder/elementparsers/DialogBoxParser.java
index 7f764de..211aa80 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/DialogBoxParser.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/DialogBoxParser.java
@@ -77,7 +77,8 @@
handleConstructorArgs(elem, fieldName, type, writer, customCaption);
if (caption != null) {
- writer.addStatement("%s.setHTML(%s);", fieldName, writer.declareTemplateCall(caption));
+ writer.addStatement("%s.setHTML(%s);", fieldName,
+ writer.declareTemplateCall(caption, fieldName));
}
if (body != null) {
writer.addStatement("%s.setWidget(%s);", fieldName, body);
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/DomElementParser.java b/user/src/com/google/gwt/uibinder/elementparsers/DomElementParser.java
index ee40b47..3428485 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/DomElementParser.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/DomElementParser.java
@@ -42,6 +42,6 @@
writer.setFieldInitializer(fieldName, String.format(
"(%1$s) UiBinderUtil.fromHtml(%2$s)",
- type.getQualifiedSourceName(), writer.declareTemplateCall(html)));
+ type.getQualifiedSourceName(), writer.declareTemplateCall(html, fieldName)));
}
}
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/GridParser.java b/user/src/com/google/gwt/uibinder/elementparsers/GridParser.java
index ae4c658..37d94ba 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/GridParser.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/GridParser.java
@@ -128,7 +128,7 @@
writer.addStatement("%s.setHTML(%s, %s, %s);", fieldName,
Integer.toString(matrix.indexOf(row)),
Integer.toString(row.getColumns().indexOf(column)),
- writer.declareTemplateCall(column.getContent()));
+ writer.declareTemplateCall(column.getContent(), fieldName));
}
if (column.getTagName().equals(CUSTOMCELL_TAG)) {
writer.addStatement("%s.setWidget(%s, %s, %s);", fieldName,
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/HTMLPanelParser.java b/user/src/com/google/gwt/uibinder/elementparsers/HTMLPanelParser.java
index 0aca4c1..7ab49b0 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/HTMLPanelParser.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/HTMLPanelParser.java
@@ -67,10 +67,11 @@
String customTag = elem.consumeStringAttribute("tag", null);
if (null == customTag) {
- writer.setFieldInitializerAsConstructor(fieldName, type, writer.declareTemplateCall(html));
+ writer.setFieldInitializerAsConstructor(fieldName, type,
+ writer.declareTemplateCall(html, fieldName));
} else {
writer.setFieldInitializerAsConstructor(fieldName, type, customTag,
- writer.declareTemplateCall(html));
+ writer.declareTemplateCall(html, fieldName));
}
}
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/HasHTMLParser.java b/user/src/com/google/gwt/uibinder/elementparsers/HasHTMLParser.java
index bcc24bf..cfdf40f 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/HasHTMLParser.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/HasHTMLParser.java
@@ -35,7 +35,8 @@
writer.endAttachedSection();
// TODO(jgw): throw an error if there's a conflicting 'html' attribute.
if (html.trim().length() > 0) {
- writer.genPropertySet(fieldName, "HTML", writer.declareTemplateCall(html));
+ writer.genPropertySet(fieldName, "HTML", writer.declareTemplateCall(html,
+ fieldName));
}
}
}
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/RenderablePanelParser.java b/user/src/com/google/gwt/uibinder/elementparsers/RenderablePanelParser.java
index 7dc6ee6..4b1b258 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/RenderablePanelParser.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/RenderablePanelParser.java
@@ -85,7 +85,8 @@
"RenderablePanel does not support custom root elements yet.");
}
- writer.setFieldInitializerAsConstructor(fieldName, type, writer.declareTemplateCall(html));
+ writer.setFieldInitializerAsConstructor(fieldName, type, writer.declareTemplateCall(html,
+ fieldName));
}
/**
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParser.java b/user/src/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParser.java
index c4bbd2e..00f3ffb 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParser.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParser.java
@@ -76,7 +76,7 @@
String size = children.header.consumeRequiredDoubleAttribute("size");
String html = children.header.consumeInnerHtml(htmlInt);
writer.addStatement("%s.add(%s, %s, true, %s);", fieldName,
- childFieldName, writer.declareTemplateCall(html), size);
+ childFieldName, writer.declareTemplateCall(html, fieldName), size);
} else if (children.customHeader != null) {
XMLElement headerElement = children.customHeader.consumeSingleChildElement();
String size = children.customHeader.consumeRequiredDoubleAttribute("size");
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParser.java b/user/src/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParser.java
index e5447df..0eceec0 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParser.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParser.java
@@ -79,7 +79,7 @@
writer, fieldName);
String html = children.header.consumeInnerHtml(htmlInt);
writer.addStatement("%s.add(%s, %s, true);", fieldName,
- childFieldName, writer.declareTemplateCall(html));
+ childFieldName, writer.declareTemplateCall(html, fieldName));
} else if (children.customHeader != null) {
XMLElement headerElement = children.customHeader.consumeSingleChildElement();
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/TabPanelParser.java b/user/src/com/google/gwt/uibinder/elementparsers/TabPanelParser.java
index c7e45f6..a1736b0 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/TabPanelParser.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/TabPanelParser.java
@@ -70,7 +70,7 @@
}
if (tabHTML != null) {
writer.addStatement("%1$s.add(%2$s, %3$s, true);", fieldName,
- childFieldName, writer.declareTemplateCall(tabHTML));
+ childFieldName, writer.declareTemplateCall(tabHTML, fieldName));
} else if (tabCaption != null) {
writer.addStatement("%1$s.add(%2$s, %3$s);", fieldName, childFieldName,
tabCaption);
diff --git a/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java b/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java
index 507305c..b89a0f5 100644
--- a/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java
@@ -60,6 +60,7 @@
private int buildPrecedence;
private final MortalLogger logger;
private final FieldWriterType fieldType;
+ private String html;
public AbstractFieldWriter(String name, FieldWriterType fieldType, MortalLogger logger) {
if (name == null) {
@@ -96,6 +97,10 @@
return fieldType;
}
+ public String getHtml() {
+ return html + ".asString()";
+ }
+
public String getInitializer() {
return initializer;
}
@@ -115,6 +120,10 @@
return getReturnType(getAssignableType(), pathList, logger);
}
+ public String getSafeHtml() {
+ return html;
+ }
+
public void needs(FieldWriter f) {
needs.add(f);
}
@@ -124,6 +133,10 @@
this.buildPrecedence = precedence;
}
+ public void setHtml(String html) {
+ this.html = html;
+ }
+
public void setInitializer(String initializer) {
this.initializer = initializer;
}
diff --git a/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java b/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java
index 6ed3527..dd9851d 100644
--- a/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java
@@ -99,6 +99,11 @@
FieldWriterType getFieldType();
/**
+ * Returns the string html representation of the field.
+ */
+ String getHtml();
+
+ /**
* Returns the custom initializer for this field, or null if it is not set.
*/
String getInitializer();
@@ -127,6 +132,11 @@
JType getReturnType(String[] path, MonitoredLogger logger);
/**
+ * Returns the string SafeHtml representation of the field.
+ */
+ String getSafeHtml();
+
+ /**
* Declares that the receiver depends upon the given field.
*/
void needs(FieldWriter f);
@@ -140,6 +150,11 @@
void setBuildPrecedence(int precedence);
/**
+ * Sets the html representation of the field for applicable field types.
+ */
+ void setHtml(String html);
+
+ /**
* Used to provide an initializer string to use instead of a
* {@link com.google.gwt.core.client.GWT#create} call. Note that this is an
* RHS expression. Don't include the leading '=', and don't end it with ';'.
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
index 791aba1..2d5f550 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
@@ -23,6 +23,7 @@
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dom.client.TagName;
import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.text.shared.UiRenderer;
import com.google.gwt.uibinder.attributeparsers.AttributeParser;
import com.google.gwt.uibinder.attributeparsers.AttributeParsers;
import com.google.gwt.uibinder.attributeparsers.BundleAttributeParser;
@@ -242,6 +243,7 @@
private final UiBinderContext uiBinderCtx;
private final String binderUri;
+ private final boolean isRenderer;
public UiBinderWriter(JClassType baseClass, String implClassName,
String templatePath, TypeOracle oracle, MortalLogger logger,
@@ -279,13 +281,42 @@
JClassType uiBinderType = uiBinderTypes[0];
JClassType[] typeArgs = uiBinderType.isParameterized().getTypeArgs();
- if (typeArgs.length < 2) {
- throw new RuntimeException(
- "Root and owner type parameters are required for type %s"
- + uiBinderType.getName());
+
+ String binderType = uiBinderType.getName();
+
+ JClassType uiRendererClass = getOracle().findType(UiRenderer.class.getName());
+ if (uiBinderType.isAssignableTo(uibinderItself)) {
+ if (typeArgs.length < 2) {
+ throw new RuntimeException(
+ "Root and owner type parameters are required for type %s"
+ + binderType);
+ }
+ uiRootType = typeArgs[0];
+ uiOwnerType = typeArgs[1];
+ isRenderer = false;
+ } else if (uiBinderType.isAssignableTo(uiRendererClass)) {
+ if (typeArgs.length < 1) {
+ throw new RuntimeException(
+ "Owner type parameter is required for type %s"
+ + binderType);
+ }
+ if (!useSafeHtmlTemplates) {
+ die("Configuration property UiBinder.useSafeHtmlTemplates\n"
+ + " must be set to true to generate a UiRenderer");
+ }
+ if (!useLazyWidgetBuilders) {
+ die("Configuration property UiBinder.useLazyWidgetBuilders\n"
+ + " must be set to true to generate a UiRenderer");
+ }
+
+ uiOwnerType = typeArgs[0];
+ uiRootType = null;
+ isRenderer = true;
+ } else {
+ die(baseClass.getName() + " must implement UiBinder or UiRenderer");
+ // This is unreachable in practice, but silences not initialized errors
+ throw new UnableToCompleteException();
}
- uiRootType = typeArgs[0];
- uiOwnerType = typeArgs[1];
isRenderableClassType = oracle.findType(IsRenderable.class.getCanonicalName());
lazyDomElementClass = oracle.findType(LazyDomElement.class.getCanonicalName());
@@ -485,13 +516,14 @@
* @return The invocation of the SafeHtml template function with the arguments
* filled in
*/
- public String declareTemplateCall(String html)
+ public String declareTemplateCall(String html, String fieldName)
throws IllegalArgumentException {
if (!useSafeHtmlTemplates) {
return '"' + html + '"';
}
-
- return htmlTemplates.addSafeHtmlTemplate(html, tokenator);
+ FieldWriter w = fieldManager.lookup(fieldName);
+ w.setHtml(htmlTemplates.addSafeHtmlTemplate(html, tokenator));
+ return w.getHtml();
}
/**
@@ -940,11 +972,6 @@
*/
void parseDocument(Document doc, PrintWriter printWriter)
throws UnableToCompleteException {
- JClassType uiBinderClass = getOracle().findType(UiBinder.class.getName());
- if (!baseClass.isAssignableTo(uiBinderClass)) {
- die(baseClass.getName() + " must implement UiBinder");
- }
-
Element documentElement = doc.getDocumentElement();
gwtPrefix = documentElement.lookupPrefix(binderUri);
@@ -1201,7 +1228,9 @@
IndentedWriter niceWriter = new IndentedWriter(
new PrintWriter(stringWriter));
- if (useLazyWidgetBuilders) {
+ if (isRenderer) {
+ writeRenderer(niceWriter, rootField);
+ } else if (useLazyWidgetBuilders) {
for (ImplicitCssResource css : bundleClass.getCssMethods()) {
String fieldName = css.getName();
FieldWriter cssField = fieldManager.require(fieldName);
@@ -1211,7 +1240,6 @@
} else {
writeBinder(niceWriter, rootField);
}
-
ensureAttachmentCleanedUp();
return stringWriter.toString();
}
@@ -1408,10 +1436,16 @@
}
private void writeClassOpen(IndentedWriter w) {
- w.write("public class %s implements UiBinder<%s, %s>, %s {", implClassName,
- uiRootType.getParameterizedQualifiedSourceName(),
- uiOwnerType.getParameterizedQualifiedSourceName(),
- baseClass.getParameterizedQualifiedSourceName());
+ if (!isRenderer) {
+ w.write("public class %s implements UiBinder<%s, %s>, %s {", implClassName,
+ uiRootType.getParameterizedQualifiedSourceName(),
+ uiOwnerType.getParameterizedQualifiedSourceName(),
+ baseClass.getParameterizedQualifiedSourceName());
+ } else {
+ w.write("public class %s extends AbstractSafeHtmlRenderer<%s> implements %s {", implClassName,
+ uiOwnerType.getParameterizedQualifiedSourceName(),
+ baseClass.getParameterizedQualifiedSourceName());
+ }
w.indent();
}
@@ -1455,7 +1489,6 @@
}
}
- // Write gwt field declarations.
fieldManager.writeGwtFieldsDeclaration(niceWriter, uiOwnerType.getName());
}
@@ -1473,11 +1506,18 @@
w.write("import com.google.gwt.safehtml.client.SafeHtmlTemplates;");
w.write("import com.google.gwt.safehtml.shared.SafeHtml;");
w.write("import com.google.gwt.safehtml.shared.SafeHtmlUtils;");
+ w.write("import com.google.gwt.safehtml.shared.SafeHtmlBuilder;");
+ w.write("import com.google.gwt.uibinder.client.UiBinderUtil;");
}
- w.write("import com.google.gwt.uibinder.client.UiBinder;");
- w.write("import com.google.gwt.uibinder.client.UiBinderUtil;");
- w.write("import %s.%s;", uiRootType.getPackage().getName(),
- uiRootType.getName());
+
+ if (!isRenderer) {
+ w.write("import com.google.gwt.uibinder.client.UiBinder;");
+ w.write("import com.google.gwt.uibinder.client.UiBinderUtil;");
+ w.write("import %s.%s;", uiRootType.getPackage().getName(),
+ uiRootType.getName());
+ } else {
+ w.write("import com.google.gwt.text.shared.AbstractSafeHtmlRenderer;");
+ }
}
/**
@@ -1540,6 +1580,76 @@
}
/**
+ * Writes the SafeHtmlRenderer's source for the renderable
+ * strategy.
+ */
+ private void writeRenderer(
+ IndentedWriter w, String rootField) throws UnableToCompleteException {
+ writePackage(w);
+
+ writeImports(w);
+ w.newline();
+
+ writeClassOpen(w);
+ writeStatics(w);
+ w.newline();
+
+ // Create SafeHtml Template
+ writeSafeHtmlTemplates(w);
+
+ w.newline();
+
+ w.write("public SafeHtml render(final %s owner) {",
+ uiOwnerType.getParameterizedQualifiedSourceName());
+ w.indent();
+ w.newline();
+
+ w.write("return new Widgets(owner).getSafeHtml();");
+ w.outdent();
+
+ w.write("}");
+ w.newline();
+
+ // Writes the inner class Widgets.
+ w.newline();
+ w.write("/**");
+ w.write(" * Encapsulates the access to all inner widgets");
+ w.write(" */");
+ w.write("class Widgets {");
+ w.indent();
+
+ String ownerClassType = uiOwnerType.getParameterizedQualifiedSourceName();
+ w.write("private final %s owner;", ownerClassType);
+ w.newline();
+
+ w.write("public Widgets(final %s owner) {", ownerClassType);
+ w.indent();
+ w.write("this.owner = owner;");
+ fieldManager.initializeWidgetsInnerClass(w, getOwnerClass());
+ w.outdent();
+ w.write("}");
+ w.newline();
+
+ w.write("public SafeHtml getSafeHtml() {");
+ w.indent();
+ // TODO Find a better way to get the root field name
+ String safeHtml = fieldManager.lookup(rootField.substring(4, rootField.length() - 2)).getSafeHtml();
+ w.write("return %s;", safeHtml);
+ w.outdent();
+ w.write("}");
+
+ fieldManager.writeFieldDefinitions(
+ w, getOracle(), getOwnerClass(), getDesignTime());
+
+ w.outdent();
+ w.write("}");
+
+ // Close class
+ w.outdent();
+ w.write("}");
+ }
+
+ /**
* Write statements created by {@link HtmlTemplates#addSafeHtmlTemplate}. This
* code must be placed after all instantiation code.
*/
diff --git a/user/src/com/google/gwt/uibinder/rebind/model/HtmlTemplate.java b/user/src/com/google/gwt/uibinder/rebind/model/HtmlTemplate.java
index f8dd711..f8c4994 100644
--- a/user/src/com/google/gwt/uibinder/rebind/model/HtmlTemplate.java
+++ b/user/src/com/google/gwt/uibinder/rebind/model/HtmlTemplate.java
@@ -77,7 +77,7 @@
*/
public String writeTemplateCall() {
return "template." + methodName + "(" + getSafeHtmlArgs()
- + ").asString()";
+ + ")";
}
/**
diff --git a/user/test/com/google/gwt/uibinder/LazyWidgetBuilderSuite.java b/user/test/com/google/gwt/uibinder/LazyWidgetBuilderSuite.java
index 6c69e98..a5f1303 100644
--- a/user/test/com/google/gwt/uibinder/LazyWidgetBuilderSuite.java
+++ b/user/test/com/google/gwt/uibinder/LazyWidgetBuilderSuite.java
@@ -17,6 +17,7 @@
import com.google.gwt.junit.tools.GWTTestSuite;
import com.google.gwt.uibinder.test.client.SafeHtmlAsComponentsTest;
+import com.google.gwt.uibinder.test.client.UiRendererTest;
import junit.framework.Test;
@@ -29,6 +30,7 @@
"Tests that rely on the useLazyWidgetBuilders switch");
suite.addTestSuite(SafeHtmlAsComponentsTest.class);
+ suite.addTestSuite(UiRendererTest.class);
return suite;
}
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/DialogBoxParserTest.java b/user/test/com/google/gwt/uibinder/elementparsers/DialogBoxParserTest.java
index 4dce3fa..2cdc6af 100644
--- a/user/test/com/google/gwt/uibinder/elementparsers/DialogBoxParserTest.java
+++ b/user/test/com/google/gwt/uibinder/elementparsers/DialogBoxParserTest.java
@@ -77,7 +77,8 @@
b.append("</g:DialogBox> ");
String[] expected = {
- "fieldName.setHTML(\"@mockToken-Hello, I <b>caption</b>you.\");",
+ "fieldName.setHTML(\"@mockToken-" + ElementParserTester.FIELD_NAME
+ + "-Hello, I <b>caption</b>you.\");",
"fieldName.setWidget(<g:Label>);",};
FieldWriter w = tester.parse(b.toString());
@@ -342,7 +343,8 @@
b.append("</ui:UiBinder>");
String[] expected = {
- "fieldName.setHTML(\"@mockToken-Hello, I <b>caption</b>you.\");",
+ "fieldName.setHTML(\"@mockToken-" + ElementParserTester.FIELD_NAME
+ + "-Hello, I <b>caption</b>you.\");",
"fieldName.setWidget(<g:Label>);",};
parser.parse(tester.getElem(b.toString(), "my:MyDialogBox"), "fieldName",
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/GridParserTest.java b/user/test/com/google/gwt/uibinder/elementparsers/GridParserTest.java
index 5a55684..ea11f9e 100644
--- a/user/test/com/google/gwt/uibinder/elementparsers/GridParserTest.java
+++ b/user/test/com/google/gwt/uibinder/elementparsers/GridParserTest.java
@@ -132,12 +132,16 @@
String[] expected = {"fieldName.resize(2, 2);",
"fieldName.getRowFormatter().setStyleName(0, \"rowHeaderStyle\");",
- "fieldName.setHTML(0, 0, \"@mockToken-foo\");",
+ "fieldName.setHTML(0, 0, \"@mockToken-" + ElementParserTester.FIELD_NAME
+ + "-foo\");",
"fieldName.getCellFormatter().setStyleName(0, 0, \"headerStyle\");",
- "fieldName.setHTML(0, 1, \"@mockToken-bar\");",
+ "fieldName.setHTML(0, 1, \"@mockToken-" + ElementParserTester.FIELD_NAME
+ + "-bar\");",
"fieldName.getCellFormatter().setStyleName(0, 1, \"headerStyle\");",
- "fieldName.setHTML(1, 0, \"@mockToken-foo\");",
- "fieldName.setHTML(1, 1, \"@mockToken-bar\");"};
+ "fieldName.setHTML(1, 0, \"@mockToken-" + ElementParserTester.FIELD_NAME
+ + "-foo\");",
+ "fieldName.setHTML(1, 1, \"@mockToken-" + ElementParserTester.FIELD_NAME
+ + "-bar\");"};
FieldWriter w = tester.parse(b.toString());
@@ -172,8 +176,10 @@
String[] expected = {
"fieldName.resize(2, 2);",
- "fieldName.setHTML(0, 0, \"@mockToken-<div>foo HTML element</div>\");",
- "fieldName.setHTML(0, 1, \"@mockToken-<div>bar HTML element</div>\");",
+ "fieldName.setHTML(0, 0, \"@mockToken-" + ElementParserTester.FIELD_NAME
+ + "-<div>foo HTML element</div>\");",
+ "fieldName.setHTML(0, 1, \"@mockToken-" + ElementParserTester.FIELD_NAME
+ + "-<div>bar HTML element</div>\");",
"fieldName.setWidget(1, 0, <g:Label>);",
"fieldName.setWidget(1, 1, <g:Label>);"};
@@ -209,7 +215,8 @@
String[] expected = {
"fieldName.resize(2, 2);",
- "fieldName.setHTML(0, 0, \"@mockToken-<div>foo HTML element</div>\");",
+ "fieldName.setHTML(0, 0, \"@mockToken-" + ElementParserTester.FIELD_NAME
+ + "-<div>foo HTML element</div>\");",
"fieldName.setWidget(1, 0, <g:Label>);",
"fieldName.setWidget(1, 1, <g:Label>);"};
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/MockUiBinderWriter.java b/user/test/com/google/gwt/uibinder/elementparsers/MockUiBinderWriter.java
index bcdd90b..2bbe7cf 100644
--- a/user/test/com/google/gwt/uibinder/elementparsers/MockUiBinderWriter.java
+++ b/user/test/com/google/gwt/uibinder/elementparsers/MockUiBinderWriter.java
@@ -45,11 +45,12 @@
}
/**
- * Mocked out version of the template declaration. Returns the template
- * prefixed with "@mockToken-"
+ * Mocked out version of the template declaration. Returns the fieldName and
+ * template separated with a dash, all prefixed with "@mockToken-"
*/
- public String declareTemplateCall(String html) {
- return "\"@mockToken-" + html + "\"";
+ @Override
+ public String declareTemplateCall(String html, String fieldName) {
+ return "\"@mockToken-" + fieldName + "-" + html + "\"";
}
@Override
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParserTest.java b/user/test/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParserTest.java
index 6987761..6f41f5e 100644
--- a/user/test/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParserTest.java
+++ b/user/test/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParserTest.java
@@ -165,7 +165,8 @@
+ "(com.google.gwt.dom.client.Style.Unit.PX)", w.getInitializer());
assertStatements(
- "fieldName.add(<g:Label id='able'>, \"@mockToken-Re<b>mark</b>able\", true, 3);",
+ "fieldName.add(<g:Label id='able'>, \"@mockToken-" + ElementParserTester.FIELD_NAME
+ + "-Re<b>mark</b>able\", true, 3);",
"fieldName.add(<g:Label id='baker'>, " + "<g:Label id='custom'>, 3);");
}
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParserTest.java b/user/test/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParserTest.java
index 4bc18ec..1b49860 100644
--- a/user/test/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParserTest.java
+++ b/user/test/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParserTest.java
@@ -168,7 +168,8 @@
b.append("</g:TabLayoutPanel>");
String[] expected = {
- "fieldName.add(<g:Label id='able'>, \"@mockToken-Re<b>mark</b>able\", true);",
+ "fieldName.add(<g:Label id='able'>, \"@mockToken-" + ElementParserTester.FIELD_NAME
+ + "-Re<b>mark</b>able\", true);",
"fieldName.add(<g:Label id='baker'>, " + "<g:Label id='custom'>);",};
FieldWriter w = tester.parse(b.toString());
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/TabPanelParserTest.java b/user/test/com/google/gwt/uibinder/elementparsers/TabPanelParserTest.java
index 2fc5ed7..1117c95 100644
--- a/user/test/com/google/gwt/uibinder/elementparsers/TabPanelParserTest.java
+++ b/user/test/com/google/gwt/uibinder/elementparsers/TabPanelParserTest.java
@@ -146,7 +146,8 @@
tester.parse(b.toString());
assertStatements("fieldName.add(<g:Label id='0'>, \"Foo\");",
- "fieldName.add(<g:Label id='1'>, \"@mockToken-B<b>a</b>r\", true);");
+ "fieldName.add(<g:Label id='1'>, \"@mockToken-" + ElementParserTester.FIELD_NAME
+ + "-B<b>a</b>r\", true);");
}
private void assertStatements(String... expected) {
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java b/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
index f0a063f..8748ecd 100644
--- a/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
+++ b/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
@@ -22,8 +22,8 @@
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.resources.client.ClientBundle;
-import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.resources.client.CssResource.NotStrict;
+import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.uibinder.test.client.EnumeratedLabel.Suffix;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.AbsolutePanel;
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiRendererTest.java b/user/test/com/google/gwt/uibinder/test/client/UiRendererTest.java
new file mode 100644
index 0000000..15eabe0
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/test/client/UiRendererTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.uibinder.test.client;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.LabelElement;
+import com.google.gwt.dom.client.Node;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtml;
+
+/**
+ * Functional test of UiBinder.
+ */
+public class UiRendererTest extends GWTTestCase {
+ private UiRendererUi safeHtmlUi;
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.uibinder.test.LazyWidgetBuilderSuite";
+ }
+
+ @Override
+ public void gwtSetUp() throws Exception {
+ super.gwtSetUp();
+ UiRendererTestApp app = UiRendererTestApp.getInstance();
+ safeHtmlUi = app.getSafeHtmlUi();
+ }
+
+ public void testSafeHtmlRendererText() {
+ SafeHtml render = safeHtmlUi.render();
+
+ LabelElement renderedHtml = Document.get().createLabelElement();
+ renderedHtml.setInnerHTML(render.asString());
+
+ Node innerDiv = renderedHtml.getFirstChild();
+
+ // Was the first span rendered as a "HTML-safe" text string?
+ Node spanWithConstantTextNode = innerDiv.getChild(0);
+ assertEquals("span", spanWithConstantTextNode.getNodeName().toLowerCase());
+ assertEquals(Node.TEXT_NODE, spanWithConstantTextNode.getFirstChild().getNodeType());
+ assertEquals("<b>This text won't be bold!</b>",
+ spanWithConstantTextNode.getFirstChild().getNodeValue());
+
+ Node firstRawTextNode = innerDiv.getChild(1);
+ assertEquals(Node.TEXT_NODE, firstRawTextNode.getNodeType());
+ assertEquals(" Hello, ", firstRawTextNode.getNodeValue());
+
+ // Fields not present in owning class produce no content
+ Node firstFieldNode = innerDiv.getChild(2);
+ assertEquals(Node.ELEMENT_NODE, firstFieldNode.getNodeType());
+ assertEquals("span", firstFieldNode.getNodeName().toLowerCase());
+ assertFalse(firstFieldNode.hasChildNodes());
+
+ // ui:msg tags get rendered but the "<ui:msg>" tag is not
+ Node secondRawTextNode = innerDiv.getChild(3);
+ assertEquals(Node.TEXT_NODE, secondRawTextNode.getNodeType());
+ assertEquals(". How goes it? ", secondRawTextNode.getNodeValue());
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiRendererTestApp.java b/user/test/com/google/gwt/uibinder/test/client/UiRendererTestApp.java
new file mode 100644
index 0000000..5c9de7a
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/test/client/UiRendererTestApp.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.uibinder.test.client;
+
+import com.google.gwt.core.client.EntryPoint;
+
+/**
+ * Demonstration of templated UI. Used by UiRendererTest
+ */
+public class UiRendererTestApp implements EntryPoint {
+ private static UiRendererTestApp instance;
+
+ /**
+ * Ensure the singleton instance has installed its UI, and return it.
+ */
+ public static UiRendererTestApp getInstance() {
+ if (instance == null) {
+ setAndInitInstance(new UiRendererTestApp());
+ }
+
+ return instance;
+ }
+
+ private static void setAndInitInstance(UiRendererTestApp newInstance) {
+ instance = newInstance;
+ instance.safeHtmlUi = new UiRendererUi();
+ }
+
+ private UiRendererUi safeHtmlUi;
+
+ private UiRendererTestApp() {
+ }
+
+ public UiRendererUi getSafeHtmlUi() {
+ return safeHtmlUi;
+ }
+
+ /**
+ * Entry point method, called only when this is run as an application.
+ */
+ public void onModuleLoad() {
+ setAndInitInstance(this);
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.css b/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.css
new file mode 100644
index 0000000..d277a99
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.css
@@ -0,0 +1,8 @@
+.bodyColor {
+ color: indigo;
+}
+
+.bodyFont {
+ font-family: Helvetica, Arial, sans-serif;
+ font-size: small;
+}
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.java b/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.java
new file mode 100644
index 0000000..0b26d06
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.uibinder.test.client;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.CssResource;
+import com.google.gwt.safehtml.shared.SafeHtml;
+import com.google.gwt.text.shared.UiRenderer;
+
+/**
+ * Sample use of a {@code SafeHtmlRenderer} with no dependency on
+ * com.google.gwt.user.
+ */
+public class UiRendererUi {
+ /**
+ * Resources for this template.
+ */
+ public interface Resources extends ClientBundle {
+ @Source("UiRendererUi.css")
+ Style style();
+ }
+
+ /**
+ * CSS for this template.
+ */
+ public interface Style extends CssResource {
+ String bodyColor();
+ String bodyFont();
+ }
+
+ interface HtmlRenderer extends UiRenderer<String> { }
+ private static final HtmlRenderer renderer = GWT.create(HtmlRenderer.class);
+
+ public UiRendererUi() {
+ }
+
+ public SafeHtml render() {
+ return renderer.render(null);
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.ui.xml b/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.ui.xml
new file mode 100644
index 0000000..2dea655
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.ui.xml
@@ -0,0 +1,47 @@
+<!-- -->
+<!-- Copyright 2011 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+<ui:UiBinder
+ xmlns:ui='urn:ui:com.google.gwt.uibinder'
+ xmlns:res='urn:with:com.google.gwt.uibinder.test.client.DomBasedUi.Resources'
+ >
+ <ui:with field="constants" type="com.google.gwt.uibinder.test.client.Constants"/>
+ <div ui:field='root' res:class="style.bodyColor style.bodyFont"
+ title="The title of this div is localizable">
+ <ui:attribute name='title'/>
+ <span><ui:text from="{constants.getText}" /></span>
+ Hello, <span ui:field="nameSpan" />.
+ <ui:msg>How goes it?</ui:msg>
+ <h2 res:class="style.bodyColor style.bodyFont">Placeholders in localizables</h2>
+ <p><ui:msg>When you mark up your text for translation, there will be bits
+ that you don't want the translators to mess with. You can protect
+ these with <span style="font-weight:bold"
+ ui:ph="boldSpan">placeholders</span><ui:ph name="tm"><sup ui:field="tmElement">TM</sup></ui:ph>.</ui:msg></p>
+ <table>
+ <col ui:field='narrowColumn' width='0%'></col>
+ <col width='100%'></col>
+ <tr ui:field='tr'>
+ <th ui:field='th1'>Tables with col elements</th>
+ <th ui:field='th2' align='left'>are</th>
+ <th ui:field='th3' align='left'>tricky</th>
+ </tr>
+ </table>
+ <table>
+ <tbody ui:field='tbody'>
+ <tr ui:field='tr2'>
+ <th ui:field='th4'>Tables with tbody elements too</th>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+</ui:UiBinder>