Adds a ui:safehtml tag to UiBinder
Review at http://gwt-code-reviews.appspot.com/1422812
Review by: rjrjr@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10217 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/ComputedAttributeInterpreter.java b/user/src/com/google/gwt/uibinder/elementparsers/ComputedAttributeInterpreter.java
index 0f4c117..2246e27 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/ComputedAttributeInterpreter.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/ComputedAttributeInterpreter.java
@@ -32,10 +32,29 @@
*/
class ComputedAttributeInterpreter implements XMLElement.Interpreter<String> {
+ interface Delegate {
+ String getAttributeToken(XMLAttribute attribute)
+ throws UnableToCompleteException;
+ }
+
+ class DefaultDelegate implements Delegate {
+ public String getAttributeToken(XMLAttribute attribute)
+ throws UnableToCompleteException {
+ return writer.tokenForStringExpression(attribute.consumeStringValue());
+ }
+ }
+
private final UiBinderWriter writer;
+ private final Delegate delegate;
public ComputedAttributeInterpreter(UiBinderWriter writer) {
this.writer = writer;
+ this.delegate = new DefaultDelegate();
+ }
+
+ public ComputedAttributeInterpreter(UiBinderWriter writer, Delegate delegate) {
+ this.delegate = delegate;
+ this.writer = writer;
}
@SuppressWarnings("deprecation")
@@ -58,7 +77,7 @@
}
if (att.hasComputedValue()) {
- String attToken = writer.tokenForStringExpression(att.consumeStringValue());
+ String attToken = delegate.getAttributeToken(att);
attNameToToken.put(att.getName(), attToken);
} else {
/*
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/HtmlInterpreter.java b/user/src/com/google/gwt/uibinder/elementparsers/HtmlInterpreter.java
index 4e74f03..88ca481 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/HtmlInterpreter.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/HtmlInterpreter.java
@@ -74,9 +74,13 @@
this.pipe = new InterpreterPipe<String>();
pipe.add(new FieldInterpreter(writer, ancestorExpression));
+ /* UiTextInterpreter and UiSafeHtmlInterpreter must be invoked before
+ * ComputedAttributeInterpreter to function properly
+ */
+ pipe.add(new UiTextInterpreter(writer));
+ pipe.add(new UiSafeHtmlInterpreter(writer));
pipe.add(new ComputedAttributeInterpreter(writer));
pipe.add(new AttributeMessageInterpreter(writer));
- pipe.add(new UiTextInterpreter(writer.getLogger()));
pipe.add(messageInterpreter);
}
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/TextInterpreter.java b/user/src/com/google/gwt/uibinder/elementparsers/TextInterpreter.java
index 50fb377..0cc7d23 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/TextInterpreter.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/TextInterpreter.java
@@ -46,7 +46,7 @@
return writer.tokenForStringExpression(messageInvocation);
}
- return new UiTextInterpreter(writer.getLogger()).interpretElement(elem);
+ return new UiTextInterpreter(writer).interpretElement(elem);
}
private String consumeAsTextMessage(XMLElement elem, MessagesWriter messages)
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/UiSafeHtmlInterpreter.java b/user/src/com/google/gwt/uibinder/elementparsers/UiSafeHtmlInterpreter.java
new file mode 100644
index 0000000..4bb1fbd
--- /dev/null
+++ b/user/src/com/google/gwt/uibinder/elementparsers/UiSafeHtmlInterpreter.java
@@ -0,0 +1,49 @@
+/*
+ * 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.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.uibinder.rebind.UiBinderWriter;
+import com.google.gwt.uibinder.rebind.XMLAttribute;
+
+/**
+ * Interprets generic message tags like:
+ * <b><ui:safehtml from="{myMsg.message}" /></b>. It's called in HTML contexts.
+ */
+public class UiSafeHtmlInterpreter extends UiTextInterpreter {
+ /**
+ * Used in {@link #interpretElement} to invoke the {@link ComputedAttributeInterpreter}.
+ */
+ private class Delegate extends UiTextInterpreter.Delegate {
+ public String getAttributeToken(XMLAttribute attribute)
+ throws UnableToCompleteException {
+ return writer.tokenForSafeHtmlExpression(attribute.consumeSafeHtmlValue());
+ }
+ }
+
+ public UiSafeHtmlInterpreter(UiBinderWriter writer) {
+ super(writer);
+ }
+
+ protected ComputedAttributeInterpreter createComputedAttributeInterpreter() {
+ return new ComputedAttributeInterpreter(writer, new Delegate());
+ }
+
+ @Override
+ protected String getLocalName() {
+ return "safehtml";
+ }
+}
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/UiTextInterpreter.java b/user/src/com/google/gwt/uibinder/elementparsers/UiTextInterpreter.java
index 3630bda..d2abb21 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/UiTextInterpreter.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/UiTextInterpreter.java
@@ -17,35 +17,62 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.uibinder.rebind.MortalLogger;
+import com.google.gwt.uibinder.rebind.UiBinderWriter;
+import com.google.gwt.uibinder.rebind.XMLAttribute;
import com.google.gwt.uibinder.rebind.XMLElement;
/**
* Interprets generic message tags like:
- * <b><ui:text from="{myMsg.message}" /></b>. It's called in both hasText
- * and hasHTML context.
+ * <b><ui:text from="{myMsg.message}" /></b>. It's called in both text
+ * and HTML contexts.
*/
public class UiTextInterpreter implements XMLElement.Interpreter<String> {
-
- private static final String BINDER_URI = "urn:ui:com.google.gwt.uibinder";
- private static final String LOCAL_NAME = "text";
-
+ /**
+ * Used in {@link #interpretElement} to invoke the {@link ComputedAttributeInterpreter}.
+ */
+ protected class Delegate implements ComputedAttributeInterpreter.Delegate {
+ public String getAttributeToken(XMLAttribute attribute)
+ throws UnableToCompleteException {
+ return writer.tokenForStringExpression(attribute.consumeStringValue());
+ }
+ }
+
+ protected final UiBinderWriter writer;
+ protected final ComputedAttributeInterpreter computedAttributeInterpreter;
private final MortalLogger logger;
- public UiTextInterpreter(MortalLogger logger) {
- this.logger = logger;
+ public UiTextInterpreter(UiBinderWriter writer) {
+ this.writer = writer;
+ this.logger = writer.getLogger();
+ this.computedAttributeInterpreter = createComputedAttributeInterpreter();
}
-
+
public String interpretElement(XMLElement elem)
throws UnableToCompleteException {
// Must be in the format: <ui:string from="{myMsg.message}" />
- if (BINDER_URI.equals(elem.getNamespaceUri())
- && LOCAL_NAME.equals(elem.getLocalName())) {
- String fieldRef = elem.consumeStringAttribute("from");
- if (fieldRef == null) {
- logger.die(elem, "Attribute 'from' not found.");
- }
- return "\" + " + fieldRef + " + \"";
- }
- return null;
+ if (writer.isBinderElement(elem) && getLocalName().equals(elem.getLocalName())) {
+ if (!elem.hasAttribute("from")) {
+ logger.die(elem, "Attribute 'from' not found.");
+ }
+ if (!elem.getAttribute("from").hasComputedValue()) {
+ logger.die(elem, "Attribute 'from' does not have a computed value");
+ }
+ // Make sure all computed attributes are interpreted first
+ computedAttributeInterpreter.interpretElement(elem);
+
+ String fieldRef = elem.consumeStringAttribute("from");
+ // Make sure that "from" was the only attribute
+ elem.assertNoAttributes();
+ return "\" + " + fieldRef + " + \"";
+ }
+ return null;
+ }
+
+ protected ComputedAttributeInterpreter createComputedAttributeInterpreter() {
+ return new ComputedAttributeInterpreter(writer);
+ }
+
+ protected String getLocalName() {
+ return "text";
}
}
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderGenerator.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderGenerator.java
index ee3fa88..710d7a5 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderGenerator.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderGenerator.java
@@ -43,7 +43,7 @@
*/
public class UiBinderGenerator extends Generator {
- static final String BINDER_URI = "urn:ui:com.google.gwt.uibinder";
+ private static final String BINDER_URI = "urn:ui:com.google.gwt.uibinder";
private static final String TEMPLATE_SUFFIX = ".ui.xml";
@@ -166,7 +166,7 @@
UiBinderWriter uiBinderWriter = new UiBinderWriter(interfaceType, implName,
templatePath, oracle, logger, fieldManager, messages, designTime, uiBinderCtx,
- useSafeHtmlTemplates(logger, propertyOracle), useLazyWidgetBuilders);
+ useSafeHtmlTemplates(logger, propertyOracle), useLazyWidgetBuilders, BINDER_URI);
Document doc = getW3cDoc(logger, designTime, resourceOracle, templatePath);
designTime.rememberPathForElements(doc);
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
index ab6b5ad..0960b06 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
@@ -103,10 +103,11 @@
private final JClassType imageResourceType;
private final JClassType dataResourceType;
+ private final String binderUri;
public UiBinderParser(UiBinderWriter writer, MessagesWriter messagesWriter,
FieldManager fieldManager, TypeOracle oracle,
- ImplicitClientBundle bundleClass) {
+ ImplicitClientBundle bundleClass, String binderUri) {
this.writer = writer;
this.oracle = oracle;
this.messagesWriter = messagesWriter;
@@ -115,6 +116,7 @@
this.cssResourceType = oracle.findType(CssResource.class.getCanonicalName());
this.imageResourceType = oracle.findType(ImageResource.class.getCanonicalName());
this.dataResourceType = oracle.findType(DataResource.class.getCanonicalName());
+ this.binderUri = binderUri;
}
/**
@@ -126,7 +128,7 @@
writer.die(elem, "Bad prefix on <%s:%s>? The root element must be in "
+ "xml namespace \"%s\" (usually with prefix \"ui:\"), "
+ "but this has prefix \"%s\"", elem.getPrefix(),
- elem.getLocalName(), UiBinderGenerator.BINDER_URI, elem.getPrefix());
+ elem.getLocalName(), binderUri, elem.getPrefix());
}
if (!TAG.equals(elem.getLocalName())) {
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
index 4a66155..d572241 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
@@ -241,11 +241,14 @@
private final UiBinderContext uiBinderCtx;
+ private final String binderUri;
+
public UiBinderWriter(JClassType baseClass, String implClassName,
String templatePath, TypeOracle oracle, MortalLogger logger,
FieldManager fieldManager, MessagesWriter messagesWriter,
DesignTimeUtils designTime, UiBinderContext uiBinderCtx,
- boolean useSafeHtmlTemplates, boolean useLazyWidgetBuilders)
+ boolean useSafeHtmlTemplates, boolean useLazyWidgetBuilders,
+ String binderUri)
throws UnableToCompleteException {
this.baseClass = baseClass;
this.implClassName = implClassName;
@@ -258,6 +261,7 @@
this.uiBinderCtx = uiBinderCtx;
this.useSafeHtmlTemplates = useSafeHtmlTemplates;
this.useLazyWidgetBuilders = useLazyWidgetBuilders;
+ this.binderUri = binderUri;
// Check for possible misuse 'GWT.create(UiBinder.class)'
JClassType uibinderItself = oracle.findType(UiBinder.class.getCanonicalName());
@@ -693,7 +697,7 @@
public boolean isBinderElement(XMLElement elem) {
String uri = elem.getNamespaceUri();
- return uri != null && UiBinderGenerator.BINDER_URI.equals(uri);
+ return uri != null && binderUri.equals(uri);
}
public boolean isElementAssignableTo(XMLElement elem, Class<?> possibleSuperclass)
@@ -942,7 +946,7 @@
}
Element documentElement = doc.getDocumentElement();
- gwtPrefix = documentElement.lookupPrefix(UiBinderGenerator.BINDER_URI);
+ gwtPrefix = documentElement.lookupPrefix(binderUri);
XMLElement elem = new XMLElementProviderImpl(attributeParsers,
bundleParsers, oracle, logger, designTime).get(documentElement);
@@ -1169,7 +1173,7 @@
// Allow GWT.create() to init the field, the default behavior
String rootField = new UiBinderParser(this, messages, fieldManager, oracle,
- bundleClass).parse(elem);
+ bundleClass, binderUri).parse(elem);
fieldManager.validate();
diff --git a/user/src/com/google/gwt/uibinder/rebind/XMLAttribute.java b/user/src/com/google/gwt/uibinder/rebind/XMLAttribute.java
index fd095dd..e584ac2 100644
--- a/user/src/com/google/gwt/uibinder/rebind/XMLAttribute.java
+++ b/user/src/com/google/gwt/uibinder/rebind/XMLAttribute.java
@@ -37,6 +37,10 @@
return xmlElem.consumeRawAttribute(w3cAttr.getName());
}
+ public String consumeSafeHtmlValue() throws UnableToCompleteException {
+ return xmlElem.consumeSafeHtmlAttribute(w3cAttr.getName());
+ }
+
public String consumeStringValue() throws UnableToCompleteException {
return xmlElem.consumeStringAttribute(w3cAttr.getName());
}
diff --git a/user/src/com/google/gwt/uibinder/rebind/XMLElement.java b/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
index 912e221..f3a4a8b 100644
--- a/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
+++ b/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
@@ -22,6 +22,7 @@
import com.google.gwt.core.ext.typeinfo.TypeOracleException;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.uibinder.attributeparsers.AttributeParser;
import com.google.gwt.uibinder.attributeparsers.AttributeParsers;
@@ -145,7 +146,8 @@
private JType doubleType;
private JType intType;
private JType stringType;
-
+ private JType safeHtmlType;
+
{
// from com/google/gxp/compiler/schema/html.xml
NO_END_TAG.add("area");
@@ -647,7 +649,20 @@
}
return value;
}
-
+
+ /**
+ * Convenience method for parsing the named attribute as a
+ * {@link com.google.gwt.safehtml.shared.SafeHtml SafeHtml} value or reference.
+ *
+ * @return an expression that will evaluate to a
+ * {@link com.google.gwt.safehtml.shared.SafeHtml SafeHtml} value in
+ * the generated code, or null if there is no such attribute
+ * @throws UnableToCompleteException on unparseable value
+ */
+ public String consumeSafeHtmlAttribute(String name)
+ throws UnableToCompleteException {
+ return consumeAttribute(name, getSafeHtmlType());
+ }
/**
* Consumes a single child element, ignoring any text nodes and throwing an
* exception if no child is found, or more than one child element is found.
@@ -933,6 +948,13 @@
return rtn;
}
+ private JType getSafeHtmlType() {
+ if (safeHtmlType == null) {
+ safeHtmlType = oracle.findType(SafeHtml.class.getName());
+ }
+ return safeHtmlType;
+ }
+
private JType getStringType() {
if (stringType == null) {
stringType = oracle.findType(String.class.getCanonicalName());
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/ElementParserTester.java b/user/test/com/google/gwt/uibinder/elementparsers/ElementParserTester.java
index 6db69b9..32e8d90 100644
--- a/user/test/com/google/gwt/uibinder/elementparsers/ElementParserTester.java
+++ b/user/test/com/google/gwt/uibinder/elementparsers/ElementParserTester.java
@@ -114,7 +114,7 @@
templatePath, baseType.getPackage().getName(), implName);
writer = new MockUiBinderWriter(baseType, implName, templatePath, types,
- logger, fieldManager, messages);
+ logger, fieldManager, messages, BINDER_URI);
fieldManager.registerField(types.findType(parsedTypeName), FIELD_NAME);
parsedType = types.findType(parsedTypeName);
}
@@ -133,11 +133,7 @@
public FieldWriter parse(String xml) throws UnableToCompleteException,
SAXParseException {
- StringBuffer b = new StringBuffer();
- b.append("<ui:UiBinder xmlns:ui='" + BINDER_URI + "'");
- b.append(" xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
- b.append(xml);
- b.append("</ui:UiBinder>");
+ StringBuffer b = wrapXML(xml);
// CHECKSTYLE_OFF
String tag = "g:" + parsedType.getName();
@@ -151,4 +147,13 @@
rtn.add(BINDER_OWNER_JAVA);
return rtn;
}
+
+ public StringBuffer wrapXML(String xml) {
+ StringBuffer b = new StringBuffer();
+ b.append("<ui:UiBinder xmlns:ui='" + BINDER_URI + "'");
+ b.append(" xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+ b.append(xml);
+ b.append("</ui:UiBinder>");
+ return b;
+ }
}
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/MockUiBinderWriter.java b/user/test/com/google/gwt/uibinder/elementparsers/MockUiBinderWriter.java
index ad145ca..bcdd90b 100644
--- a/user/test/com/google/gwt/uibinder/elementparsers/MockUiBinderWriter.java
+++ b/user/test/com/google/gwt/uibinder/elementparsers/MockUiBinderWriter.java
@@ -34,9 +34,9 @@
public MockUiBinderWriter(JClassType baseClass, String implClassName, String templatePath,
TypeOracle oracle, MortalLogger logger, FieldManager fieldManager,
- MessagesWriter messagesWriter) throws UnableToCompleteException {
+ MessagesWriter messagesWriter, String binderUri) throws UnableToCompleteException {
super(baseClass, implClassName, templatePath, oracle, logger, fieldManager, messagesWriter,
- DesignTimeUtilsStub.EMPTY, new UiBinderContext(), true, false);
+ DesignTimeUtilsStub.EMPTY, new UiBinderContext(), true, false, binderUri);
}
@Override
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/UiSafeHtmlInterpreterTest.java b/user/test/com/google/gwt/uibinder/elementparsers/UiSafeHtmlInterpreterTest.java
new file mode 100644
index 0000000..fe44b3c
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/elementparsers/UiSafeHtmlInterpreterTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2010 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.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+
+import junit.framework.TestCase;
+
+import org.xml.sax.SAXException;
+
+/**
+ * Test for {@link UiSafeHtmlInterpreter}.
+ */
+public class UiSafeHtmlInterpreterTest extends TestCase {
+
+ private static final String PARSED_TYPE = "com.google.gwt.user.client.ui.HTMLPanel";
+
+ private ElementParserTester tester;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ tester = new ElementParserTester(PARSED_TYPE, new HTMLPanelParser());
+ }
+
+ public void testNoFromAttribute() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:HTMLPanel><ui:safehtml/>");
+ b.append("</g:HTMLPanel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue("Expect no 'from' attribute error",
+ tester.logger.died.contains("Attribute 'from' not found."));
+ }
+ }
+
+ public void testNoComputedValue() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:HTMLPanel><ui:safehtml from='nope'/>");
+ b.append("</g:HTMLPanel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue("Expect no computed value error",
+ tester.logger.died.contains("Attribute 'from' does not have a computed value"));
+ }
+ }
+
+ public void testTooManyAttributes() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:HTMLPanel><ui:safehtml from='{foo}' foo='' bar='' />");
+ b.append("</g:HTMLPanel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue("Expect too many attributes attribute error",
+ tester.logger.died.contains("Unexpected attributes"));
+ }
+ }
+
+ public void testHappy() throws Exception {
+ String s = "<g:HTMLPanel>\n <ui:safehtml from='{foo}'/>\n </g:HTMLPanel>\n";
+
+ String interpretedValue = new UiSafeHtmlInterpreter(tester.writer)
+ .interpretElement(tester.getElem(tester.wrapXML(s).toString(), "ui:safehtml"));
+
+ assertEquals(interpretedValue, "\" + \"--token--1--token--\" + \"");
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/UiTextInterpreterTest.java b/user/test/com/google/gwt/uibinder/elementparsers/UiTextInterpreterTest.java
new file mode 100644
index 0000000..4d3aa67
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/elementparsers/UiTextInterpreterTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2010 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.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+
+import junit.framework.TestCase;
+
+import org.xml.sax.SAXException;
+
+/**
+ * Test for {@link UiTextInterpreter}.
+ */
+public class UiTextInterpreterTest extends TestCase {
+
+ private static final String PARSED_TYPE = "com.google.gwt.user.client.ui.HTMLPanel";
+
+ private ElementParserTester tester;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ tester = new ElementParserTester(PARSED_TYPE, new HTMLPanelParser());
+ }
+
+ public void testNoFromAttribute() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:HTMLPanel><ui:text/>");
+ b.append("</g:HTMLPanel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue("Expect no 'from' attribute error",
+ tester.logger.died.contains("Attribute 'from' not found."));
+ }
+ }
+
+ public void testNoComputedValue() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:HTMLPanel><ui:text from='nope'/>");
+ b.append("</g:HTMLPanel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue("Expect no computed value error",
+ tester.logger.died.contains("Attribute 'from' does not have a computed value"));
+ }
+ }
+
+ public void testTooManyAttributes() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:HTMLPanel><ui:text from='{foo}' foo='' bar='' />");
+ b.append("</g:HTMLPanel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue("Expect too many attributes attribute error",
+ tester.logger.died.contains("Unexpected attributes"));
+ }
+ }
+
+ public void testHappy() throws Exception {
+ String s = "<g:HTMLPanel>\n <ui:text from='{foo}'/>\n </g:HTMLPanel>\n";
+
+ String interpretedValue = new UiTextInterpreter(tester.writer)
+ .interpretElement(tester.getElem(tester.wrapXML(s).toString(), "ui:text"));
+
+ assertEquals(interpretedValue, "\" + \"--token--1--token--\" + \"");
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/test/UiJavaResources.java b/user/test/com/google/gwt/uibinder/test/UiJavaResources.java
index 761b457..65ac2c8 100644
--- a/user/test/com/google/gwt/uibinder/test/UiJavaResources.java
+++ b/user/test/com/google/gwt/uibinder/test/UiJavaResources.java
@@ -294,6 +294,17 @@
return code;
}
};
+ public static final MockJavaResource HTML_PANEL = new MockJavaResource(
+ "com.google.gwt.user.client.ui.HTMLPanel") {
+ @Override
+ public CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package com.google.gwt.user.client.ui;\n");
+ code.append("public class HTMLPanel extends Widget {\n");
+ code.append("}\n");
+ return code;
+ }
+ };
public static final MockJavaResource IMAGE = new MockJavaResource(
"com.google.gwt.user.client.ui.Image") {
@Override
@@ -470,6 +481,17 @@
return code;
}
};
+ public static final MockJavaResource SAFEHTML = new MockJavaResource(
+ "com.google.gwt.safehtml.shared.SafeHtml") {
+ @Override
+ public CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package com.google.gwt.safehtml.shared;\n");
+ code.append("public interface SafeHtml {\n");
+ code.append("}\n");
+ return code;
+ }
+ };
public static final MockJavaResource SPLIT_LAYOUT_PANEL = new MockJavaResource(
"com.google.gwt.user.client.ui.SplitLayoutPanel") {
@Override
@@ -685,6 +707,7 @@
rtn.add(HAS_CLICK_HANDLERS);
rtn.add(HAS_HORIZONTAL_ALIGNMENT);
rtn.add(HAS_VERTICAL_ALIGNMENT);
+ rtn.add(HTML_PANEL);
rtn.add(LABEL);
rtn.add(LAYOUT_PANEL);
rtn.add(LIST_BOX);
@@ -696,6 +719,7 @@
rtn.add(NUMBER_LABEL);
rtn.add(NUMBER_FORMAT);
rtn.add(RENDERER);
+ rtn.add(SAFEHTML);
rtn.add(SPLIT_LAYOUT_PANEL);
rtn.add(STACK_LAYOUT_PANEL);
rtn.add(STACK_PANEL);
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..4d3f017 100644
--- a/user/test/com/google/gwt/uibinder/test/client/Constants.java
+++ b/user/test/com/google/gwt/uibinder/test/client/Constants.java
@@ -15,6 +15,9 @@
*/
package com.google.gwt.uibinder.test.client;
+import com.google.gwt.safehtml.shared.SafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
+
/**
* Used to test static imports in UiBinder templates.
*/
@@ -39,4 +42,16 @@
}
public static String CONST_FOO = "Foo";
+
+ public SafeHtml getSafeHtml() {
+ return SafeHtmlUtils.fromSafeConstant("<b>This text should be bold!</b>");
+ }
+
+ public String getText() {
+ return "<b>This text won't be bold!</b>";
+ }
+
+ public String getRendererText() {
+ return "<b>Here's the text!</b>";
+ }
}
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..e1d2b20 100644
--- a/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
+++ b/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
@@ -628,6 +628,15 @@
assertEquals(new FakeBundle().aUrl(), widgetUi.myImage.getSrc());
}
+ public void testUiTextWithSafeHtml() {
+ assertEquals(widgetUi.htmlWithComputedSafeHtml.getHTML().toLowerCase(),
+ "<b>this text should be bold!</b>");
+ assertEquals(widgetUi.htmlWithComputedText.getHTML().toLowerCase(),
+ "<b>this text won't be bold!</b>");
+ assertEquals(widgetUi.labelWithComputedText.getText().toLowerCase(),
+ "<b>this text won't be bold!</b>");
+ }
+
/**
* Assert that the expect strings are found in body, and in the order given.
* WARNING: both body and expected are normalized to lower case, to get around
diff --git a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java
index 9a914f5..0ceb549 100644
--- a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java
+++ b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java
@@ -198,6 +198,9 @@
Renderer doubleRenderer = DoubleRenderer.instance();
@UiField ValueLabel<Double> myValueLabel;
@UiField ImageElement myImage;
+ @UiField HTML htmlWithComputedSafeHtml;
+ @UiField HTML htmlWithComputedText;
+ @UiField Label labelWithComputedText;
public WidgetBasedUi() {
external.style().ensureInjected();
diff --git a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
index 6402452..1af6c05 100644
--- a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
+++ b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
@@ -79,6 +79,10 @@
Used to test ValueLabel's @UiConstructor
</ui:with>
+<ui:with field="constants" type="com.google.gwt.uibinder.test.client.Constants">
+ Used to test SafeHtml return type in ui:text context.
+</ui:with>
+
<ui:import field='com.google.gwt.uibinder.test.client.Constants.CONST_FOO'>
Tests the static import of a single constant into the local namespace.
</ui:import>
@@ -678,6 +682,10 @@
<gwt3:google.gwt.user.client.ui.ValueLabel ui:field='myValueLabel' renderer='{doubleRenderer}' />
<img src="{values.aUrl}" ui:field='myImage'/>
+
+ <gwt:HTML ui:field='htmlWithComputedSafeHtml'><ui:safehtml from="{constants.getSafeHtml}" /></gwt:HTML>
+ <gwt:HTML ui:field='htmlWithComputedText'><ui:text from="{constants.getText}" /></gwt:HTML>
+ <gwt:Label ui:field='labelWithComputedText'><ui:text from="{constants.getText}"/></gwt:Label>
</gwt:HTMLPanel>
</gwt:Dock>