Revision: 6100
Author: [email protected]
Date: Tue Sep  8 22:07:33 2009
Log: We were double escaping the contents of placeholders inside HTML
messages. E.g.,

   <p><ui:msg>I would 'like' a <span ui:field='foo'>'single'</span> quote</ui

rendered as:

   I would 'like' a ''single'' quote

There was already a mechanism in place for this kind of thing, written for t
widgets-in-HTML-messages case (WidgetPlaceholderInterpreter), but I forgot
to use it in HtmlPlaceholderInterpreter.

Added tests and touched up docs while there, hoping to regain my
bearings more quickly next time.

http://code.google.com/p/google-web-toolkit/source/detail?r=6100

Modified:
  /trunk/user/src/com/google/gwt/uibinder/parsers/HTMLPanelParser.java
  /trunk/user/src/com/google/gwt/uibinder/parsers/HtmlMessageInterpreter.java
   
/trunk/user/src/com/google/gwt/uibinder/parsers/HtmlPlaceholderInterpreter.java
   
/trunk/user/src/com/google/gwt/uibinder/rebind/messages/PlaceholderInterpreter.java
  /trunk/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.java
  /trunk/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.ui.xml
  /trunk/user/test/com/google/gwt/uibinder/sample/client/UiBinderTest.java

=======================================
--- /trunk/user/src/com/google/gwt/uibinder/parsers/HTMLPanelParser.java        
 
Wed Aug  5 20:27:52 2009
+++ /trunk/user/src/com/google/gwt/uibinder/parsers/HTMLPanelParser.java        
 
Tue Sep  8 22:07:33 2009
@@ -32,14 +32,14 @@
        final UiBinderWriter writer) throws UnableToCompleteException {
      String customTag =
         
UiBinderWriter.escapeTextForJavaStringLiteral(elem.consumeAttribute("tag"));
-
+
      /*
       * Gathers up elements that indicate nested widgets (but only those
       * that are not inside msg elements).
       */
      WidgetInterpreter widgetInterpreter = new WidgetInterpreter(fieldName,  
writer);

-    /*
+    /*
       * Handles non-widget elements like msg, and dom elements with ui:field
       * attributes. There may be widgets inside a msg, which is why
       * the construction in makeHtmlInterpreter is so complicated.
@@ -65,7 +65,7 @@

    /**
     * Creates an HtmlInterpreter with our specialized placeholder  
interpreter,
-   * which will allow widget instances to be declared inside of m:msg  
elements.
+   * which will allow widget instances to be declared inside of ui:msg  
elements.
     */
    private HtmlInterpreter makeHtmlInterpreter(final String fieldName,
        final UiBinderWriter uiWriter) {
=======================================
---  
/trunk/user/src/com/google/gwt/uibinder/parsers/HtmlMessageInterpreter.java     
 
Wed Aug  5 20:27:52 2009
+++  
/trunk/user/src/com/google/gwt/uibinder/parsers/HtmlMessageInterpreter.java     
 
Tue Sep  8 22:07:33 2009
@@ -23,7 +23,7 @@
  import com.google.gwt.uibinder.rebind.messages.PlaceholderInterpreter;

  /**
- * Processes <m:msg> elements inside HTML values, which themselves
+ * Processes <ui:msg> elements inside HTML values, which themselves
   * are allowed to contain HTML. That HTML may hold elements with
   * ui:field attributes and computed attributes, which must be
   * replaced by placeholders in the generated message.
@@ -52,7 +52,7 @@

    /**
     * Build a normally configured HtmlMessageInterpreter, able to handle
-   * put placeholders around dom elements with m:ph attributes and computed
+   * put placeholders around dom elements with ui:ph attributes and  
computed
     * attributes.
     */
    public HtmlMessageInterpreter(final UiBinderWriter uiWriter,
=======================================
---  
/trunk/user/src/com/google/gwt/uibinder/parsers/HtmlPlaceholderInterpreter.java 
 
Wed Aug  5 20:27:52 2009
+++  
/trunk/user/src/com/google/gwt/uibinder/parsers/HtmlPlaceholderInterpreter.java 
 
Tue Sep  8 22:07:33 2009
@@ -60,7 +60,11 @@
            nextPlaceholder(name + "Begin", stripTokens(openTag),
                uiWriter.detokenate(openTag));

-      String body = elem.consumeInnerHtml(this);
+      /*
+       * This recursive innerHtml call has already been escaped. Hide it  
in a
+       * token to avoid double escaping
+       */
+      String body = tokenator.nextToken(elem.consumeInnerHtml(this));

        String closeTag = elem.getClosingTag();
        String closePlaceholder =
@@ -79,7 +83,13 @@
    }

    /**
-   * @return true if it has an m:ph attribute, or has a token in any  
attribute
+   * An element will require a placeholder if the user has called it out  
with a
+   * ui:ph attribute, or if it will require run time swizzling (e.g. has a
+   * ui:field). These latter we can identify easily because they'll have an
+   * attribute that holds a tokenator token that was vended by
+   * {...@link UiBinderWriter}, typically in id.
+   *
+   * @return true if it has an ui:ph attribute, or has a token in any  
attribute
     */
    private boolean isDomPlaceholder(XMLElement elem) {
      MessagesWriter mw = uiWriter.getMessages();
=======================================
---  
/trunk/user/src/com/google/gwt/uibinder/rebind/messages/PlaceholderInterpreter.java
      
Tue Sep  1 15:14:29 2009
+++  
/trunk/user/src/com/google/gwt/uibinder/rebind/messages/PlaceholderInterpreter.java
      
Tue Sep  8 22:07:33 2009
@@ -40,15 +40,14 @@

    public String interpretElement(XMLElement elem)
        throws UnableToCompleteException {
-
      if (isPlaceholderElement(elem)) {
        /*
-       * The innerHTML or innerText of the <m:ph> will be provided as the  
value
+       * The innerHTML or innerText of the <ui:ph> will be provided as the  
value
         * of the appropriate parameter when the Messages method is called.
         *
         * E.g.
         *
-       *   <m:msg>Able <m:ph name="foo" example"baz">baker</m:ph>  
charlie</m:msg>
+       *   <ui:msg>Able <ui:ph name="foo" example"baz">baker</ui:ph>  
charlie</ui:msg>
         *
         * becomes
         *
@@ -78,11 +77,10 @@
        }

        /*
-       * Again, if there are TemplateWriter tokens in the value string, we  
need
-       * it to have it replace them with the real expresions.
+       * Likewise, if there are tokens from the UiWriter in the value  
string, we
+       * need it to replace them with the real expresions.
         */
        value = uiWriter.detokenate(value);
-
        return nextPlaceholder(name, example, value);
      }

@@ -94,9 +92,10 @@

    /**
     * Called by various {...@link XMLElement} consumeInner*() methods after all
-   * elements have been handed to {...@link #interpretElement}. Performs  
escaping
-   * on the consumed text to make it safe for use as a Messages {...@literal  
@}Default
-   * value.
+   * elements have been handed to {...@link #interpretElement}.
+   * <p>
+   * Performs escaping on the consumed text to make it safe for use as a
+   * Messages {...@literal @}Default value
     */
    public String postProcess(String consumed) throws  
UnableToCompleteException {
      return  
tokenator.detokenate(MessageWriter.escapeMessageFormat(consumed));
@@ -105,10 +104,29 @@
    protected abstract String consumePlaceholderInnards(XMLElement elem)
        throws UnableToCompleteException;

+  /**
+   * To be called from {...@link #interpretElement(XMLElement)}. Creates the  
next
+   * placeholder in the {...@link MessageWriter} we're building, and returns  
the
+   * text to stand in its place.
+   *
+   * @param name
+   * @param example
+   * @param value
+   * @return
+   */
    protected String nextPlaceholder(String name, String example, String  
value) {
      message.addPlaceholder(new PlaceholderWriter(name, example, value));
-    return tokenator.nextToken(String.format("{%d}",
-        message.getPlaceholderCount() - 1));
+
+    /*
+     * We can't just return the {0} placeholder text, because it will be
+     * clobbered by the escaping performed in postProcess. We use a  
tokenator to
+     * hide the placeholder from the escaping step, and postProcess  
resolves the
+     * tokens when the escaping is done.
+     */
+    String placeholder = String.format("{%d}",
+        message.getPlaceholderCount() - 1);
+
+    return tokenator.nextToken(placeholder);
    }

    protected String stripTokens(String value) {
=======================================
---  
/trunk/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.java        
 
Thu Sep  3 16:03:13 2009
+++  
/trunk/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.java        
 
Tue Sep  8 22:07:33 2009
@@ -74,7 +74,9 @@
    @UiField ClickyLink funnyCharsMessageAttributeWidget;
    @UiField ParagraphElement funnyCharsMessageDomAttributeParagraph;
    @UiField ParagraphElement funnyCharsMessageParagraph;
+  @UiField SpanElement funnyCharsMessageChildSpan;
    @UiField ParagraphElement funnyCharsParagraph;
+  @UiField ParagraphElement funnyCharsProtectedMessageParagraph;
    @UiField Label gwtFieldLabel;
    @UiField ParagraphElement main;
    @UiField Button myButton;
=======================================
---  
/trunk/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.ui.xml      
 
Thu Sep  3 16:03:13 2009
+++  
/trunk/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.ui.xml      
 
Tue Sep  8 22:07:33 2009
@@ -99,7 +99,7 @@
    </gwt:Dock>
    <gwt:Dock direction='CENTER'>
      <gwt:HTMLPanel>
-      <p><ui:msg>This is a demonstration and test bed of GWT's UiBinder
+      <p><ui:msg>This is a demonstration and test bed of GWT's shiny  
UiBinder
        package. At the moment it works mainly as described in
        <a  
href="http://code.google.com/p/google-web-toolkit-incubator/wiki/DeclarativeUi";
          ui:ph="oldBlogLink">
@@ -279,6 +279,8 @@
        untranslated paragraph.</p>
        <p ui:field="funnyCharsMessageParagraph"><ui:msg>They might show up
        in body text that has been <b>marked for translation</b>: funny  
characters " &quot; ' &#39; &amp; &lt; &gt; > { }</ui:msg></p>
+      <p><ui:msg>Or perhaps in a subelement with a ui:field: <span  
ui:field='funnyCharsMessageChildSpan'>funny characters " &quot; ' &#39;  
&amp; &lt; &gt; > { }</span></ui:msg></p>
+      <p ui:field="funnyCharsProtectedMessageParagraph"><ui:msg>Don't  
forget about protected untranslatable blocks: <ui:ph name='francine'>funny  
characters " &quot; ' &#39; &amp; &lt; &gt; > { }</ui:ph></ui:msg></p>
        <p ui:field="funnyCharsMessageDomAttributeParagraph" title="funny  
characters &quot; ' &#39; &amp; &lt; &gt; > { }">
          <ui:attribute name="title"/>
          Attributes of dom elements can be translated too, like the
=======================================
---  
/trunk/user/test/com/google/gwt/uibinder/sample/client/UiBinderTest.java        
 
Thu Sep  3 16:03:13 2009
+++  
/trunk/user/test/com/google/gwt/uibinder/sample/client/UiBinderTest.java        
 
Tue Sep  8 22:07:33 2009
@@ -165,6 +165,17 @@
          + "translation: funny characters \" \" ' ' & < > > { }",
          t);
    }
+
+  public void testProtectedDomTextMessageWithFunnyChars() {
+    String t = widgetUi.funnyCharsProtectedMessageParagraph.getInnerText();
+    assertEquals("Don't forget about protected untranslatable blocks: "
+        + "funny characters \" \" ' ' & < > > { }", t);
+  }
+
+  public void testDomTextInNamedElementMessageWithFunnyChars() {
+    String t = widgetUi.funnyCharsMessageChildSpan.getInnerText();
+    assertEquals("funny characters \" \" ' ' & < > > { }", t);
+  }

    public void  
suppressedForSafari3Fail_testDomTextNoMessageWithFunnyChars() {
      ParagraphElement p = widgetUi.funnyCharsParagraph;

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

Reply via email to