Revision: 10210
Author:   [email protected]
Date:     Tue May 24 04:45:28 2011
Log:      SafeHtmlRenderer code gen for UiBinder. Picking up issue 1426803

Review at http://gwt-code-reviews.appspot.com/1442804

Review by: [email protected]
http://code.google.com/p/google-web-toolkit/source/detail?r=10210

Added:
 /trunk/user/test/com/google/gwt/uibinder/test/client/SafeHtmlRendererUi.css
/trunk/user/test/com/google/gwt/uibinder/test/client/SafeHtmlRendererUi.java /trunk/user/test/com/google/gwt/uibinder/test/client/SafeHtmlRendererUi.ui.xml
Modified:
 /trunk/user/src/com/google/gwt/uibinder/UiBinder.gwt.xml
/trunk/user/src/com/google/gwt/uibinder/elementparsers/AttachableHTMLPanelParser.java /trunk/user/src/com/google/gwt/uibinder/elementparsers/CustomButtonParser.java
 /trunk/user/src/com/google/gwt/uibinder/elementparsers/DialogBoxParser.java
/trunk/user/src/com/google/gwt/uibinder/elementparsers/DomElementParser.java
 /trunk/user/src/com/google/gwt/uibinder/elementparsers/GridParser.java
 /trunk/user/src/com/google/gwt/uibinder/elementparsers/HTMLPanelParser.java
 /trunk/user/src/com/google/gwt/uibinder/elementparsers/HasHTMLParser.java
/trunk/user/src/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParser.java /trunk/user/src/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParser.java
 /trunk/user/src/com/google/gwt/uibinder/elementparsers/TabPanelParser.java
 /trunk/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java
 /trunk/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java
 /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
 /trunk/user/src/com/google/gwt/uibinder/rebind/model/HtmlTemplate.java
/trunk/user/test/com/google/gwt/uibinder/elementparsers/DialogBoxParserTest.java
 /trunk/user/test/com/google/gwt/uibinder/elementparsers/GridParserTest.java
/trunk/user/test/com/google/gwt/uibinder/elementparsers/MockUiBinderWriter.java /trunk/user/test/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParserTest.java /trunk/user/test/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParserTest.java /trunk/user/test/com/google/gwt/uibinder/elementparsers/TabPanelParserTest.java
 /trunk/user/test/com/google/gwt/uibinder/test/client/Constants.java
 /trunk/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
 /trunk/user/test/com/google/gwt/uibinder/test/client/UiBinderTestApp.java

=======================================
--- /dev/null
+++ /trunk/user/test/com/google/gwt/uibinder/test/client/SafeHtmlRendererUi.css Tue May 24 04:45:28 2011
@@ -0,0 +1,8 @@
+.bodyColor {
+  color: indigo;
+}
+
+.bodyFont {
+  font-family: Helvetica, Arial, sans-serif;
+  font-size: small;
+}
=======================================
--- /dev/null
+++ /trunk/user/test/com/google/gwt/uibinder/test/client/SafeHtmlRendererUi.java Tue May 24 04:45:28 2011
@@ -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);
+  }
+}
=======================================
--- /dev/null
+++ /trunk/user/test/com/google/gwt/uibinder/test/client/SafeHtmlRendererUi.ui.xml Tue May 24 04:45:28 2011
@@ -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>
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/UiBinder.gwt.xml Fri Apr 22 11:18:50 2011 +++ /trunk/user/src/com/google/gwt/uibinder/UiBinder.gwt.xml Tue May 24 04:45:28 2011
@@ -33,6 +33,10 @@
<define-configuration-property name="UiBinder.useLazyWidgetBuilders" is-multi-valued="false"/> <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>
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/AttachableHTMLPanelParser.java Mon May 23 17:23:56 2011 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/AttachableHTMLPanelParser.java Tue May 24 04:45:28 2011
@@ -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));
   }

   /**
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/CustomButtonParser.java Wed Mar 9 09:01:28 2011 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/CustomButtonParser.java Tue May 24 04:45:28 2011
@@ -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")) {
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/DialogBoxParser.java Wed Mar 9 09:01:28 2011 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/DialogBoxParser.java Tue May 24 04:45:28 2011
@@ -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);
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/DomElementParser.java Wed Mar 9 09:01:28 2011 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/DomElementParser.java Tue May 24 04:45:28 2011
@@ -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)));
   }
 }
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/GridParser.java Tue May 10 08:14:26 2011 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/GridParser.java Tue May 24 04:45:28 2011
@@ -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,
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/HTMLPanelParser.java Fri Apr 22 11:18:50 2011 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/HTMLPanelParser.java Tue May 24 04:45:28 2011
@@ -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));
     }
   }

=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/HasHTMLParser.java Wed Mar 9 09:01:28 2011 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/HasHTMLParser.java Tue May 24 04:45:28 2011
@@ -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));
     }
   }
 }
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParser.java Wed Mar 9 09:01:28 2011 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParser.java Tue May 24 04:45:28 2011
@@ -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");
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParser.java Wed Mar 9 09:01:28 2011 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParser.java Tue May 24 04:45:28 2011
@@ -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();

=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/TabPanelParser.java Thu May 5 09:42:56 2011 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/TabPanelParser.java Tue May 24 04:45:28 2011
@@ -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);
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java Mon May 2 12:52:38 2011 +++ /trunk/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java Tue May 24 04:45:28 2011
@@ -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);
   }
@@ -123,6 +131,10 @@
   public void setBuildPrecedence(int precedence) {
     this.buildPrecedence = precedence;
   }
+
+  public void setHtml(String html) {
+    this.html = html;
+  }

   public void setInitializer(String initializer) {
     this.initializer = initializer;
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java Mon May 2 12:52:38 2011 +++ /trunk/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java Tue May 24 04:45:28 2011
@@ -98,6 +98,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.
    */
@@ -126,6 +131,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.
    */
@@ -139,6 +149,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
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java Tue May 24 04:00:30 2011 +++ /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java Tue May 24 04:45:28 2011
@@ -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());
-    }
-    uiRootType = typeArgs[0];
-    uiOwnerType = typeArgs[1];
+
+    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();
+    }

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.uibinder.client.UiBinder;");
-    w.write("import com.google.gwt.uibinder.client.UiBinderUtil;");
-    w.write("import %s.%s;", uiRootType.getPackage().getName(),
-        uiRootType.getName());
+      w.write("import com.google.gwt.safehtml.shared.SafeHtmlBuilder;");
+      w.write("import com.google.gwt.uibinder.client.UiBinderUtil;");
+    }
+
+    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;");
+    }
   }

   /**
@@ -1512,6 +1548,41 @@
       w.newline();
     }
   }
+
+  /**
+   * 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
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/model/HtmlTemplate.java Wed Mar 9 09:01:28 2011 +++ /trunk/user/src/com/google/gwt/uibinder/rebind/model/HtmlTemplate.java Tue May 24 04:45:28 2011
@@ -77,7 +77,7 @@
    */
   public String writeTemplateCall() {
     return "template." + methodName + "(" + getSafeHtmlArgs()
-      + ").asString()";
+      + ")";
   }

   /**
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/elementparsers/DialogBoxParserTest.java Thu Apr 21 07:48:58 2011 +++ /trunk/user/test/com/google/gwt/uibinder/elementparsers/DialogBoxParserTest.java Tue May 24 04:45:28 2011
@@ -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",
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/elementparsers/GridParserTest.java Tue May 10 08:14:26 2011 +++ /trunk/user/test/com/google/gwt/uibinder/elementparsers/GridParserTest.java Tue May 24 04:45:28 2011
@@ -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>);"};

=======================================
--- /trunk/user/test/com/google/gwt/uibinder/elementparsers/MockUiBinderWriter.java Fri Apr 22 11:18:50 2011 +++ /trunk/user/test/com/google/gwt/uibinder/elementparsers/MockUiBinderWriter.java Tue May 24 04:45:28 2011
@@ -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
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParserTest.java Wed Mar 9 09:01:28 2011 +++ /trunk/user/test/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParserTest.java Tue May 24 04:45:28 2011
@@ -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);");
   }

=======================================
--- /trunk/user/test/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParserTest.java Wed Mar 9 09:01:28 2011 +++ /trunk/user/test/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParserTest.java Tue May 24 04:45:28 2011
@@ -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());
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/elementparsers/TabPanelParserTest.java Wed Mar 9 09:01:28 2011 +++ /trunk/user/test/com/google/gwt/uibinder/elementparsers/TabPanelParserTest.java Tue May 24 04:45:28 2011
@@ -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) {
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/test/client/Constants.java Fri Aug 20 04:44:06 2010 +++ /trunk/user/test/com/google/gwt/uibinder/test/client/Constants.java Tue May 24 04:45:28 2011
@@ -39,4 +39,8 @@
   }

   public static String CONST_FOO = "Foo";
-}
+
+  public String getText() {
+    return "<b>Here's the text!</b>";
+  }
+}
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java Wed May 4 09:28:35 2011 +++ /trunk/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java Tue May 24 04:45:28 2011
@@ -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() {
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/test/client/UiBinderTestApp.java Tue Jul 13 09:51:15 2010 +++ /trunk/user/test/com/google/gwt/uibinder/test/client/UiBinderTestApp.java Tue May 24 04:45:28 2011
@@ -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() {
@@ -55,6 +59,10 @@
   public DomBasedUi getDomUi() {
     return domUi;
   }
+
+  public SafeHtmlRendererUi getSafeHtmlUi() {
+    return safeHtmlUi;
+  }

   public WidgetBasedUi getWidgetUi() {
     return widgetUi;

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to