Allowing support to field references inside html elements and GWT
widgets: <span><ui:text from="{m.message}" /></span>.
http://gwt-code-reviews.appspot.com/153813
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7640 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/HtmlInterpreter.java b/user/src/com/google/gwt/uibinder/elementparsers/HtmlInterpreter.java
index f7c1317..c127a47 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/HtmlInterpreter.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/HtmlInterpreter.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -40,7 +40,7 @@
* {@link com.google.gwt.user.client.ui.UIObject} (or really, any object that
* responds to <code>getElement()</code>). Uses an instance of
* {@link HtmlMessageInterpreter} to process message elements.
- *
+ *
* @param uiExpression An expression that can be evaluated at runtime to find
* an object whose getElement() method can be called to get an
* ancestor of all Elements generated from the interpreted HTML.
@@ -50,7 +50,7 @@
String ancestorExpression = uiExpression + ".getElement()";
return new HtmlInterpreter(writer, ancestorExpression,
new HtmlMessageInterpreter(writer, ancestorExpression));
- }
+ }
private final UiBinderWriter writer;
private final InterpreterPipe<String> pipe;
@@ -58,7 +58,7 @@
/**
* Rather than using this constructor, you probably want to use the
* {@link #newInterpreterForUiObject} factory method.
- *
+ *
* @param ancestorExpression An expression that can be evaluated at runtime to
* find an Element that will be an ancestor of all Elements generated
* from the interpreted HTML.
@@ -74,6 +74,7 @@
pipe.add(new FieldInterpreter(writer, ancestorExpression));
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 d007bd8..187ea61 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.tokenForExpression(messageInvocation);
}
- return null;
+ return new UiTextInterpreter(writer.getLogger()).interpretElement(elem);
}
private String consumeAsTextMessage(XMLElement elem, MessagesWriter messages)
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/UiTextInterpreter.java b/user/src/com/google/gwt/uibinder/elementparsers/UiTextInterpreter.java
new file mode 100644
index 0000000..6043326
--- /dev/null
+++ b/user/src/com/google/gwt/uibinder/elementparsers/UiTextInterpreter.java
@@ -0,0 +1,51 @@
+/*
+ * 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 com.google.gwt.uibinder.rebind.MortalLogger;
+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.
+ */
+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";
+
+ private final MortalLogger logger;
+
+ public UiTextInterpreter(MortalLogger logger) {
+ this.logger = logger;
+ }
+
+ 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("Attribute 'from' not found in '%s'.", elem);
+ }
+ return "\" + " + fieldRef + " + \"";
+ }
+ return null;
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/test/client/I18nMessageTest.java b/user/test/com/google/gwt/uibinder/test/client/I18nMessageTest.java
new file mode 100644
index 0000000..0ba1b85
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/test/client/I18nMessageTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.test.client;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.Messages;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * A simple widget for i18n tests.
+ */
+public class I18nMessageTest extends Composite {
+
+ /**
+ * The UiBinder interface.
+ */
+ interface Binder extends UiBinder<Widget, I18nMessageTest> { }
+ private static final Binder BINDER = GWT.create(Binder.class);
+
+ /**
+ * The message holder to use in the template.
+ */
+ public interface TestMessages extends Messages {
+ @DefaultMessage("Message from Brazil")
+ String messageBrazil();
+
+ @DefaultMessage("Message from USA")
+ String messageUsa();
+ }
+
+ public I18nMessageTest() {
+ initWidget(BINDER.createAndBindUi(this));
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/test/client/I18nMessageTest.ui.xml b/user/test/com/google/gwt/uibinder/test/client/I18nMessageTest.ui.xml
new file mode 100644
index 0000000..f38554e
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/test/client/I18nMessageTest.ui.xml
@@ -0,0 +1,51 @@
+<!--
+ 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
+ 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:gwt="urn:import:com.google.gwt.user.client.ui">
+
+ <ui:with field="msg"
+ type="com.google.gwt.uibinder.test.client.I18nMessageTest.TestMessages" />
+
+ <gwt:HTMLPanel>
+
+ <hr />
+ <h1>Test</h1>
+ <h2><ui:text from="{msg.messageBrazil}" /></h2>
+ <h2 /><ui:text from="{msg.messageUsa}" />
+
+ <hr />
+
+ <gwt:Label>Brazil</gwt:Label>
+ <gwt:Label><ui:text from="{msg.messageBrazil}" /></gwt:Label>
+ <gwt:Label>
+ Label =
+ <ui:text from="{msg.messageBrazil}" />
+ <ui:text from="{msg.messageUsa}" />
+ </gwt:Label>
+
+ <gwt:HTML text="{msg.messageUsa}"/>
+ <gwt:HTML>USA</gwt:HTML>
+ <gwt:HTML>
+ HTML =
+ <ui:text from="{msg.messageBrazil}" />
+ <ui:text from="{msg.messageUsa}" />
+ </gwt:HTML>
+ <gwt:HTML><ui:text from="{msg.messageBrazil}" /></gwt:HTML>
+
+ </gwt:HTMLPanel>
+
+</ui:UiBinder>
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 476437b..40e8dba 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
@@ -13,25 +13,25 @@
limitations under the License.
-->
-<!DOCTYPE ui:UiBinder
+<!DOCTYPE ui:UiBinder
SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent"
[
<!ENTITY % MyEntities SYSTEM "MyEntities.ent">
%MyEntities;
]
>
-<!--
- This scary DOCTYPE section is not required. It's here to demonstrate two
+<!--
+ This scary DOCTYPE section is not required. It's here to demonstrate two
things.
-
+
First, this bit:
-
+
SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent"
-
- allows you to use familiar HTML entities like and •,
- which are not part of XML. (The file is also available as
+
+ allows you to use familiar HTML entities like and •,
+ which are not part of XML. (The file is also available as
https://dl-ssl.google.com/gwt/DTD/xhtml.ent.)
-
+
Next, the bit in square brackets is even more optional. It shows how
to add your own entities, in this case pulling in additional
definitions for &point-left; and &point-right; from local file
@@ -39,16 +39,16 @@
You don't have to be so verbose to include a local file! For
example, you might instead grab your own copy of xhtml.ent
- and add your custom entity definitions to it, and use this
+ and add your custom entity definitions to it, and use this
for your DOCTYPE:
-
+
<!DOCTYPE ui:UiBinder SYSTEM "my-xhtml.ent">
-->
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:gwt='urn:import:com.google.gwt.user.client.ui'
xmlns:demo='urn:import:com.google.gwt.uibinder.test.client'
-
+
xmlns:legacyValuesForBeans='urn:with:com.google.gwt.uibinder.test.client.WidgetBasedUi.FakeBundle2'
xmlns:legacyValuesForHtml='urn:with:com.google.gwt.uibinder.test.client.WidgetBasedUi.FakeBundle3'
@@ -61,7 +61,7 @@
<ui:with field='external' type='com.google.gwt.uibinder.test.client.WidgetBasedUiExternalResources'>
(This text is ignored, but it's a handy place to document a resource.)
-
+
external is used to test receiving a resource from the owner via
@UiField(provided = true), particularly useful for dependency
injection via Gin and the like
@@ -72,20 +72,20 @@
for a resource to provide arbitrary objects to arbitrary attributes (look for FooLabel)
</ui:with>
-<!--
+<!--
Tests creating a CssResource from an external file.
-->
-<ui:style field='myStyle' src='WidgetBasedUi.css Menu.css'
+<ui:style field='myStyle' src='WidgetBasedUi.css Menu.css'
type='com.google.gwt.uibinder.test.client.WidgetBasedUi.Style'>
- .menuBar {
+ .menuBar {
font-family: sans-serif;
}
</ui:style>
-
+
<ui:style field='myOtherStyle' type='com.google.gwt.uibinder.test.client.WidgetBasedUi.Style'>
- /* because we extend WidgetBasedUi.Style and it's tagged @Shared, we can refine the menubar
+ /* because we extend WidgetBasedUi.Style and it's tagged @Shared, we can refine the menubar
style defined in other files */
-
+
.menuBar.psychedelic {
background-color: Yellow;
}
@@ -98,7 +98,7 @@
<ui:style field='myTotallyPrivateStyle'>
/* An inline style tied to no public type */
-
+
.super-private-color {
background-color: Gold;
}
@@ -113,14 +113,14 @@
<ui:data field='heartCursorResource' src='heart.cur'/>
<ui:style field='mySpritelyStyle'>
- @sprite .simpleSprite {
- gwt-image: "prettyImage";
+ @sprite .simpleSprite {
+ gwt-image: "prettyImage";
}
- @sprite .tilingSprite {
- gwt-image: "prettyTilingImage";
+ @sprite .tilingSprite {
+ gwt-image: "prettyTilingImage";
}
-
+
.garish {
color: Purple;
font-weight: bold;
@@ -129,7 +129,7 @@
}
.garish.tilingSprite {
- font-size: 1.5em;
+ font-size: 1.5em;
}
</ui:style>
<ui:image field='prettyImage' />
@@ -174,9 +174,9 @@
adopters should recognize themselves as such, and be prepared to have the
api rug yanked out from under them.</ui:msg></p>
<p ui:field="main">
- &point-right; <span ui:field="messageInMain"><ui:msg>This is the main area.
- It's an <b>HTMLPanel</b>, which allows you to mix
- &point-right; • XHTML • &point-left; and regular GWT widgets, more or less with
+ &point-right; <span ui:field="messageInMain"><ui:msg>This is the main area.
+ It's an <b>HTMLPanel</b>, which allows you to mix
+ &point-right; • XHTML • &point-left; and regular GWT widgets, more or less with
impunity. Take the following button for example.</ui:msg></span> &point-left;
</p>
<gwt:Button ui:field='myButton'>
@@ -200,7 +200,7 @@
/>
</div>
- <p ui:field='simpleSpriteParagraph'
+ <p ui:field='simpleSpriteParagraph'
class='{mySpritelyStyle.simpleSprite} {mySpritelyStyle.garish}
{cursorifficStyle.cursor}' >
And sprites too
@@ -210,7 +210,7 @@
{cursorifficStyle.cursor}'>
Well how do you like <br/>
tiled sprited images...of babies!! <br/>
- Well of course you do. Who wouldn't?
+ Well of course you do. Who wouldn't?
</p>
<p>
@@ -248,7 +248,7 @@
<div id="pop-can-has-submenu">
<ui:msg description="Last 7 Day Period">Pop</ui:msg>
</div>
- <gwt:MenuBar vertical="true" ui:field="dropdownMenuBar"
+ <gwt:MenuBar vertical="true" ui:field="dropdownMenuBar"
styleName="{myStyle.menuBar}">
<gwt:MenuItem ui:field='menuItemCustomDateRange'>
<ui:msg description="Custom date range">
@@ -271,7 +271,7 @@
<gwt:Tree ui:field='myTree' width="100px" />
<p>...TextBoxes...</p>
-
+
<gwt:TextBox maxLength="21">21 chars only, please</gwt:TextBox>
<p>...or perhaps a handful of RadioButtons:</p>
@@ -285,11 +285,11 @@
text="Charlie (this one is a subclass of RadioButton)">
<ui:attribute name="text" description="radio button name"/>
</demo:PointlessRadioButtonSubclass>
-
- <gwt:HorizontalPanel horizontalAlignment="ALIGN_LEFT">
- <gwt:Cell><gwt:HTMLPanel>
+
+ <gwt:HorizontalPanel horizontalAlignment="ALIGN_LEFT">
+ <gwt:Cell><gwt:HTMLPanel>
<p> ... a StackPanel ... </p>
-
+
<gwt:StackPanel stylePrimaryName="myStyle" width="280px" ui:field='myStackPanel'>
<gwt:Label text="Stack One Text" gwt:StackPanel-text="Stack One"
ui:field='myStackPanelItem'>
@@ -303,10 +303,10 @@
<gwt:Label text="Stack Three Text" gwt:StackPanel-text="Stack Three" />
</gwt:StackPanel>
</gwt:HTMLPanel></gwt:Cell>
-
+
<gwt:cell><gwt:HTMLPanel>
<p> ... a TabPanel </p>
-
+
<gwt:TabPanel>
<gwt:Tab text='Able'><gwt:Label>Able Widget</gwt:Label></gwt:Tab>
<gwt:Tab><gwt:TabHTML><b>B</b>aker</gwt:TabHTML>
@@ -314,12 +314,12 @@
</gwt:Tab>
</gwt:TabPanel>
</gwt:HTMLPanel></gwt:cell>
-
+
</gwt:HorizontalPanel>
-
-
+
+
<p> ... a DisclosurePanel with a text header ... </p>
-
+
<gwt:DisclosurePanel ui:field='myDisclosurePanel' animationEnabled='true'>
<gwt:header>
<ui:msg description="Label for Disclosure One">I just have a text header</ui:msg>
@@ -331,9 +331,9 @@
</gwt:Label>
</gwt:DisclosurePanel>
-
+
<p> ... a DisclosurePanel with a widget header ... </p>
-
+
<gwt:DisclosurePanel animationEnabled='true'>
<gwt:customHeader>
<gwt:Label>
@@ -391,9 +391,9 @@
<gwt:DisclosurePanel>
<gwt:header><ui:msg>"I just have a text header"</ui:msg></gwt:header>
</gwt:DisclosurePanel>
-
+
<p> ... a DisclosurePanel with custom images ... </p>
-
+
<gwt:DisclosurePanel open='false' animationEnabled='true'>
<gwt:header openImage='{down}' closedImage='{right}'>
<ui:msg description="Content for Disclosure Two Text">Custom images header</ui:msg>
@@ -404,7 +404,7 @@
</gwt:Label>
</gwt:DisclosurePanel>
-
+
<h2>Stylish</h2>
<p>
Templates work with ClientBundle. For example,
@@ -422,7 +422,7 @@
This one is has a private style, defined out in WidgetBaseUi.css and used only by this ui.xml file.
</p>
<p ui:field='reallyPrivateStyleParagraph' class='{myOtherStyle.privateColor}'>
- And this style is defined right here inside the ui.xml file.
+ And this style is defined right here inside the ui.xml file.
<span ui:field='totallyPrivateStyleSpan' class='{myTotallyPrivateStyle.super-private-color}'>
(This one too, but even more so.)
</span>
@@ -487,8 +487,8 @@
<p><ui:msg>Of course you'll want to be able to do this kind of thing
with widgets <demo:MyDatePicker/> as well, whether they <gwt:Label>HasText<ui:ph name="tm">*TM*</ui:ph></gwt:Label>
or <gwt:HTML>HasHTML<ui:ph name="TM2"><sup ui:field="tmElementJr"
- class="{external.style.tmText}">TM</sup></ui:ph></gwt:HTML></ui:msg></p>
-
+ class="{external.style.tmText}">TM</sup></ui:ph></gwt:HTML></ui:msg></p>
+
<p><ui:msg>
You can mix both widgets and named dom fields within a
<gwt:HTML ui:field='mixedMessageWidget'>single translatable message</gwt:HTML>, another source
@@ -509,12 +509,12 @@
text="Sometimes people do things they don't need to do. Don't punish them."/></p>
<demo:FooLabel ui:field='theFoo' pojo="{values.pojo}"/>
-
+
<demo:FooLabel ui:field='primitiveIntoObject' objectInteger='{values.anInt}'/>
<demo:FooLabel ui:field='objectIntoPrimitive' rawInt='{values.anIntegerObject}' />
<demo:FooLabel ui:field='allObject' objectInteger='{values.anIntegerObject}' />
<demo:FooLabel ui:field='allPrimitive' rawInt='{values.anInt}' />
-
+
<demo:FooLabel ui:field='mismatchPrimitiveIntoObject' objectInteger='{values.aDouble}'/>
<demo:FooLabel ui:field='allMismatchPrimitive' rawInt='{values.aDouble}' />
@@ -522,7 +522,7 @@
<demo:FooLabel ui:field='objectBooleanIntoPrimitive' rawBoolean='{values.aBooleanObject}' />
<demo:FooLabel ui:field='allObjectBoolean' objectBoolean='{values.aBooleanObject}' />
<demo:FooLabel ui:field='allPrimitiveBoolean' rawBoolean='{values.aBoolean}' />
-
+
<demo:EnumeratedLabel ui:field='enumLabel' suffix='tail'>This label uses an enum for its</demo:EnumeratedLabel>
<gwt:PushButton ui:field='pushButton' enabled='true'>
@@ -534,7 +534,7 @@
<gwt:downDisabledFace image='{prettyImage}'/>
</gwt:PushButton>
- <gwt:ToggleButton ui:field='toggle'>Hi mom</gwt:ToggleButton>
+ <gwt:ToggleButton ui:field='toggle'>Hi mom</gwt:ToggleButton>
<demo:FooDialog ui:field='fooDialog'>
<gwt:caption>Custom dialog am I</gwt:caption>
@@ -542,9 +542,9 @@
</demo:FooDialog>
<gwt:FlowPanel>
- <gwt:Label ui:field="lblDebugId" debugId="joe"
+ <gwt:Label ui:field="lblDebugId" debugId="joe"
styleName="styleName"
- addStyleNames="newStyle, anotherStyle {external.style.prettyText}"
+ addStyleNames="newStyle, anotherStyle {external.style.prettyText}"
addStyleDependentNames="dependentStyle anotherDependentStyle, {external.style.prettyText}">
A label with a debug id
</gwt:Label>
@@ -552,6 +552,7 @@
</gwt:FlowPanel>
<demo:HandlerDemo />
+ <demo:I18nMessageTest />
<h2>People write the darndest markup</h2>
<table border="1" bcolor="yellow" cellpadding="3" ui:field="widgetCrazyTable">
@@ -587,7 +588,7 @@
<tr><td>Even HTMLPanel gets in on the game</td></tr>
<tr><td>Lately, anyway.</td></tr>
</gwt:HTMLPanel>
-
+
<gwt:DialogBox autoHide="true" modal="true">
<gwt:caption>Hello, I <b>caption</b> you.</gwt:caption>
<gwt:HTMLPanel>
@@ -596,7 +597,7 @@
<gwt:Button ui:field='ok'>Okay</gwt:Button>
</gwt:HTMLPanel>
</gwt:DialogBox>
-
+
<gwt:ListBox ui:field='fooListBox'>
<gwt:item>bar</gwt:item>
<gwt:item value='bar2'>bar 2</gwt:item>