SafeHtmlRenderer code gen for UiBinder. Picking up issue 1426803 Review at http://gwt-code-reviews.appspot.com/1442804 Review by: rjrjr@google.com git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10210 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/uibinder/UiBinder.gwt.xml b/user/src/com/google/gwt/uibinder/UiBinder.gwt.xml index 50cbc5b..3559f99 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.SafeHtmlRenderer"/> + </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/AttachableHTMLPanelParser.java b/user/src/com/google/gwt/uibinder/elementparsers/AttachableHTMLPanelParser.java index 4a640d8..aaef6a0 100644 --- a/user/src/com/google/gwt/uibinder/elementparsers/AttachableHTMLPanelParser.java +++ b/user/src/com/google/gwt/uibinder/elementparsers/AttachableHTMLPanelParser.java
@@ -77,7 +77,7 @@ "AttachableHTMLPanel 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/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 83d5d40..c093680 100644 --- a/user/src/com/google/gwt/uibinder/elementparsers/HTMLPanelParser.java +++ b/user/src/com/google/gwt/uibinder/elementparsers/HTMLPanelParser.java
@@ -59,10 +59,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/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 8eb5814..04b4ccf 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) { @@ -95,6 +96,9 @@ public FieldWriterType getFieldType() { return fieldType; } + public String getHtml() { + return html + ".asString()"; + } public String getInitializer() { return initializer; @@ -115,6 +119,10 @@ return getReturnType(getAssignableType(), pathList, logger); } + public String getSafeHtml() { + return html; + } + public void needs(FieldWriter f) { needs.add(f); } @@ -124,6 +132,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 4a66155..2dcc917 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.SafeHtmlRenderer; import com.google.gwt.uibinder.attributeparsers.AttributeParser; import com.google.gwt.uibinder.attributeparsers.AttributeParsers; import com.google.gwt.uibinder.attributeparsers.BundleAttributeParser; @@ -241,6 +242,8 @@ private final UiBinderContext uiBinderCtx; + private final boolean isRenderer; + public UiBinderWriter(JClassType baseClass, String implClassName, String templatePath, TypeOracle oracle, MortalLogger logger, FieldManager fieldManager, MessagesWriter messagesWriter, @@ -275,13 +278,38 @@ 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 safeHtmlRendererClass = getOracle().findType(SafeHtmlRenderer.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(safeHtmlRendererClass)) { + 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 SafeHtmlRenderer"); + } + + uiOwnerType = typeArgs[0]; + uiRootType = null; + isRenderer = true; + } else { + die(baseClass.getName() + " must implement UiBinder or SafeHtmlRenderer"); + // 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()); @@ -481,13 +509,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(); } /** @@ -753,9 +782,8 @@ return lazyDomElementClass.isAssignableFrom(ownerField.getType().getRawType()); } - public boolean isRenderableElement(XMLElement elem) - throws UnableToCompleteException { - return findFieldType(elem).isAssignableTo(isRenderableClassType); + public boolean isRenderableElement(XMLElement elem) throws UnableToCompleteException { + return findFieldType(elem).isAssignableTo(isRenderableClassType); } public boolean isWidgetElement(XMLElement elem) throws UnableToCompleteException { @@ -936,11 +964,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(UiBinderGenerator.BINDER_URI); @@ -1177,7 +1200,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); @@ -1187,7 +1212,6 @@ } else { writeBinder(niceWriter, rootField); } - ensureAttachmentCleanedUp(); return stringWriter.toString(); } @@ -1382,10 +1406,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(); } @@ -1429,7 +1459,6 @@ } } - // Write gwt field declarations. fieldManager.writeGwtFieldsDeclaration(niceWriter, uiOwnerType.getName()); } @@ -1447,11 +1476,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;"); + } } /** @@ -1514,6 +1550,41 @@ } /** + * Writes the SafeHtmlRenderer's source. + */ + 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.write("public SafeHtml render(final %s owner) {", + uiOwnerType.getParameterizedQualifiedSourceName()); + w.indent(); + w.newline(); + + writeGwtFields(w); + w.newline(); + + String safeHtml = fieldManager.lookup(rootField).getSafeHtml(); + w.write("return %s;", safeHtml); + w.outdent(); + w.write("}\n"); + + // 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/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 ad145ca..12d59da 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/Constants.java b/user/test/com/google/gwt/uibinder/test/client/Constants.java index e387a7a..5e9b536 100644 --- a/user/test/com/google/gwt/uibinder/test/client/Constants.java +++ b/user/test/com/google/gwt/uibinder/test/client/Constants.java
@@ -39,4 +39,8 @@ } public static String CONST_FOO = "Foo"; + + public String getText() { + return "<b>Here's the text!</b>"; + } }
diff --git a/user/test/com/google/gwt/uibinder/test/client/SafeHtmlRendererUi.css b/user/test/com/google/gwt/uibinder/test/client/SafeHtmlRendererUi.css new file mode 100644 index 0000000..d277a99 --- /dev/null +++ b/user/test/com/google/gwt/uibinder/test/client/SafeHtmlRendererUi.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/SafeHtmlRendererUi.java b/user/test/com/google/gwt/uibinder/test/client/SafeHtmlRendererUi.java new file mode 100644 index 0000000..a4d4348 --- /dev/null +++ b/user/test/com/google/gwt/uibinder/test/client/SafeHtmlRendererUi.java
@@ -0,0 +1,54 @@ +/* + * Copyright 2008 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.SafeHtmlRenderer; + +/** + * Sample use of a {@code SafeHtmlRenderer} with no dependency on + * com.google.gwt.user. + */ +public class SafeHtmlRendererUi { + /** + * Resources for this template. + */ + public interface Resources extends ClientBundle { + @Source("SafeHtmlRendererUi.css") + Style style(); + } + + /** + * CSS for this template. + */ + public interface Style extends CssResource { + String bodyColor(); + String bodyFont(); + } + + interface HtmlRenderer extends SafeHtmlRenderer<String> { } + private static final HtmlRenderer renderer = GWT.create(HtmlRenderer.class); + + public SafeHtmlRendererUi() { + } + + public SafeHtml render() { + return renderer.render(null); + } +}
diff --git a/user/test/com/google/gwt/uibinder/test/client/SafeHtmlRendererUi.ui.xml b/user/test/com/google/gwt/uibinder/test/client/SafeHtmlRendererUi.ui.xml new file mode 100644 index 0000000..6a31cb4 --- /dev/null +++ b/user/test/com/google/gwt/uibinder/test/client/SafeHtmlRendererUi.ui.xml
@@ -0,0 +1,47 @@ +<!-- --> +<!-- Copyright 2008 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>
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 91a5203..3a8c3e9 100644 --- a/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java +++ b/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
@@ -18,12 +18,15 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.LabelElement; +import com.google.gwt.dom.client.Node; import com.google.gwt.dom.client.ParagraphElement; 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.safehtml.shared.SafeHtml; import com.google.gwt.uibinder.test.client.EnumeratedLabel.Suffix; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.ui.AbsolutePanel; @@ -50,6 +53,7 @@ private WidgetBasedUi widgetUi; private DomBasedUi domUi; private com.google.gwt.user.client.ui.DockPanel root; + private SafeHtmlRendererUi safeHtmlUi; @Override public String getModuleName() { @@ -63,6 +67,28 @@ widgetUi = app.getWidgetUi(); domUi = app.getDomUi(); root = widgetUi.root; + safeHtmlUi = app.getSafeHtmlUi(); + } + + public void testSafeHtmlRendererText() { + SafeHtml render = safeHtmlUi.render(); + + LabelElement renderedHtml = domUi.root.getOwnerDocument().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>Here's the text!</b>", + spanWithConstantTextNode.getFirstChild().getNodeValue()); + + Node firstRawTextNode = innerDiv.getChild(1); + assertEquals(Node.TEXT_NODE, firstRawTextNode.getNodeType()); + assertEquals(" Hello, ", + firstRawTextNode.getNodeValue()); } public void testTableWithColumns() {
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiBinderTestApp.java b/user/test/com/google/gwt/uibinder/test/client/UiBinderTestApp.java index c998f65..a2c3269 100644 --- a/user/test/com/google/gwt/uibinder/test/client/UiBinderTestApp.java +++ b/user/test/com/google/gwt/uibinder/test/client/UiBinderTestApp.java
@@ -41,12 +41,16 @@ instance.domUi = new DomBasedUi("Mr. User Man"); Document.get().getBody().appendChild(instance.domUi.root); + instance.safeHtmlUi = new SafeHtmlRendererUi(); + instance.widgetUi = new WidgetBasedUi(); RootPanel.get().add(instance.widgetUi); } private DomBasedUi domUi; + private SafeHtmlRendererUi safeHtmlUi; + private WidgetBasedUi widgetUi; private UiBinderTestApp() { @@ -56,6 +60,10 @@ return domUi; } + public SafeHtmlRendererUi getSafeHtmlUi() { + return safeHtmlUi; + } + public WidgetBasedUi getWidgetUi() { return widgetUi; }