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>