1 /*
2  * Copyright 2010 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 package com.google.gwt.sample.showcase.client.content.i18n;
17 
18 import com.google.gwt.core.client.GWT;
19 import com.google.gwt.core.client.RunAsyncCallback;
20 import com.google.gwt.event.dom.client.ClickEvent;
21 import com.google.gwt.event.dom.client.ClickHandler;
22 import com.google.gwt.event.dom.client.KeyUpEvent;
23 import com.google.gwt.event.dom.client.KeyUpHandler;
24 import com.google.gwt.i18n.client.Constants;
25 import com.google.gwt.i18n.client.LocaleInfo;
26 import com.google.gwt.i18n.shared.BidiFormatter;
27 import com.google.gwt.safehtml.shared.SafeHtmlUtils;
28 import com.google.gwt.sample.showcase.client.ContentWidget;
29 import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
30 import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseRaw;
31 import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
32 import com.google.gwt.user.client.rpc.AsyncCallback;
33 import com.google.gwt.user.client.ui.Anchor;
34 import com.google.gwt.user.client.ui.FlexTable;
35 import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
36 import com.google.gwt.user.client.ui.HTML;
37 import com.google.gwt.user.client.ui.HasVerticalAlignment;
38 import com.google.gwt.user.client.ui.HorizontalPanel;
39 import com.google.gwt.user.client.ui.TextBox;
40 import com.google.gwt.user.client.ui.Widget;
41 
42 /**
43  * Example file.
44  */
45 @ShowcaseRaw({"BlogMessages.java", "BlogMessages.properties"})
46 public class CwBidiFormatting extends ContentWidget {
47   /**
48    * The constants used in this Content Widget.
49    */
50   @ShowcaseSource
51   public static interface CwConstants extends Constants {
cwBidiFormattingArg0Label()52     String cwBidiFormattingArg0Label();
53 
cwBidiFormattingArg1Label()54     String cwBidiFormattingArg1Label();
55 
cwBidiFormattingArg2Label()56     String cwBidiFormattingArg2Label();
57 
cwBidiFormattingBidiFormattedLabel()58     String cwBidiFormattingBidiFormattedLabel();
59 
cwBidiFormattingDescription()60     String cwBidiFormattingDescription();
61 
cwBidiFormattingLinkText()62     String cwBidiFormattingLinkText();
63 
cwBidiFormattingName()64     String cwBidiFormattingName();
65 
cwBidiFormattingNonbidiFormattedLabel()66     String cwBidiFormattingNonbidiFormattedLabel();
67 
cwBidiFormattingTemplateLabel()68     String cwBidiFormattingTemplateLabel();
69   }
70 
71   /**
72    * The {@link TextBox} where the user enters argument 0.
73    */
74   @ShowcaseData
75   private TextBox arg0Box = null;
76 
77   /**
78    * The {@link TextBox} where the user enters argument 1.
79    */
80   @ShowcaseData
81   private TextBox arg1Box = null;
82 
83   /**
84    * The {@link TextBox} where the user enters argument 2.
85    */
86   @ShowcaseData
87   private TextBox arg2Box = null;
88 
89   /**
90    * A {@link com.google.gwt.i18n.shared.BidiFormatter} instance used for
91    * bidi-formatting of user input.
92    */
93   @ShowcaseData
94   private BidiFormatter bidiFormatter =
95       BidiFormatter.getInstanceForCurrentLocale();
96 
97   /**
98    * An instance of the constants.
99    */
100   @ShowcaseData
101   private final CwConstants constants;
102 
103   /**
104    * The blog messages used in this example.
105    */
106   @ShowcaseData
107   private BlogMessages blogMessages = null;
108 
109   /**
110    * The {@link HTML} used to display the message.
111    */
112   @ShowcaseData
113   private HTML message = null;
114 
115   /**
116    * The {@link HTML} used to display the bidi formatted message.
117    */
118   @ShowcaseData
119   private HTML bidiFormattedMessage = null;
120 
121   /**
122    * Constructor.
123    *
124    * @param constants the constants
125    */
CwBidiFormatting(CwConstants constants)126   public CwBidiFormatting(CwConstants constants) {
127     super(constants.cwBidiFormattingName(),
128         constants.cwBidiFormattingDescription(), false, "BlogMessages.java",
129         "BlogMessages.properties");
130     this.constants = constants;
131   }
132 
133   /**
134    * Initialize this example.
135    */
136   @ShowcaseSource
137   @Override
onInitialize()138   public Widget onInitialize() {
139     // Create the internationalized blog messages
140     blogMessages = GWT.create(BlogMessages.class);
141 
142     // Use a FlexTable to layout the content
143     FlexTable layout = new FlexTable();
144     FlexCellFormatter formatter = layout.getFlexCellFormatter();
145     layout.setCellSpacing(5);
146 
147     // Add a link to the source code of the Interface
148     final String rawFile = getSimpleName(BlogMessages.class);
149     Anchor link = new Anchor(rawFile);
150     link.addClickHandler(new ClickHandler() {
151       public void onClick(ClickEvent event) {
152         fireRawSourceRequest(rawFile + ".java");
153       }
154     });
155     HorizontalPanel linkPanel = new HorizontalPanel();
156     linkPanel.setSpacing(3);
157     linkPanel.add(new HTML(constants.cwBidiFormattingLinkText()));
158     linkPanel.add(link);
159     layout.setWidget(0, 0, linkPanel);
160     formatter.setColSpan(0, 0, 2);
161 
162     // Show the template for reference
163     String template = blogMessages.userComment("{0}", "{1}", "{2}");
164     layout.setHTML(1, 0, constants.cwBidiFormattingTemplateLabel());
165     layout.setHTML(1, 1, template);
166 
167     // Add argument 0
168     arg0Box = new TextBox();
169     // Using an initial value whose direction is opposite the locale's direction
170     // demonstrates the need for and effect of bidi formatting.
171     arg0Box.setText(
172         LocaleInfo.getCurrentLocale().isRTL() ? "Tom Bombadil" : "תומר גרין");
173     layout.setHTML(2, 0, constants.cwBidiFormattingArg0Label());
174     layout.setWidget(2, 1, arg0Box);
175 
176     // Add argument 1
177     arg1Box = new TextBox();
178     arg1Box.setText("16");
179     layout.setHTML(3, 0, constants.cwBidiFormattingArg1Label());
180     layout.setWidget(3, 1, arg1Box);
181 
182     // Add argument 2
183     arg2Box = new TextBox();
184     // Using an initial value whose direction is opposite the locale's direction
185     // demonstrates the need for and effect of bidi formatting.
186     arg2Box.setText(LocaleInfo.getCurrentLocale().isRTL()
187         ? "How deep is your love?" : "כמה חול יש בחוף?");
188     layout.setHTML(4, 0, constants.cwBidiFormattingArg2Label());
189     layout.setWidget(4, 1, arg2Box);
190 
191     // Add the unformatted message
192     message = new HTML();
193     layout.setHTML(5, 0, constants.cwBidiFormattingNonbidiFormattedLabel());
194     layout.setWidget(5, 1, message);
195     formatter.setVerticalAlignment(5, 0, HasVerticalAlignment.ALIGN_TOP);
196 
197     // Add the bidi formatted message
198     bidiFormattedMessage = new HTML();
199     layout.setHTML(6, 0, constants.cwBidiFormattingBidiFormattedLabel());
200     layout.setWidget(6, 1, bidiFormattedMessage);
201     formatter.setVerticalAlignment(6, 0, HasVerticalAlignment.ALIGN_TOP);
202 
203     // Add handlers to all of the argument boxes
204     KeyUpHandler keyUpHandler = new KeyUpHandler() {
205       public void onKeyUp(KeyUpEvent event) {
206         updateMessages();
207       }
208     };
209     arg0Box.addKeyUpHandler(keyUpHandler);
210     arg1Box.addKeyUpHandler(keyUpHandler);
211     arg2Box.addKeyUpHandler(keyUpHandler);
212 
213     // Return the layout Widget
214     updateMessages();
215 
216     return layout;
217   }
218 
219   @Override
asyncOnInitialize(final AsyncCallback<Widget> callback)220   protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
221     GWT.runAsync(CwBidiFormatting.class, new RunAsyncCallback() {
222 
223       public void onFailure(Throwable caught) {
224         callback.onFailure(caught);
225       }
226 
227       public void onSuccess() {
228         callback.onSuccess(onInitialize());
229       }
230     });
231   }
232 
233   /**
234    * Update the formatted message.
235    */
236   @ShowcaseSource
updateMessages()237   private void updateMessages() {
238     String arg0 = arg0Box.getText().trim();
239     String arg1 = arg1Box.getText().trim();
240     String arg2 = arg2Box.getText().trim();
241     message.setText(blogMessages.userComment(arg0, arg1, arg2));
242 
243     bidiFormattedMessage.setHTML(
244         blogMessages.userComment(bidiFormatter.spanWrap(arg0),
245         // arg1 is intended to be an unsigned number, so bidi formatting is not
246         // needed. However, HTML escaping is a must to avoid an XSS attack hole!
247             SafeHtmlUtils.htmlEscape(arg1), bidiFormatter.spanWrap(arg2)));
248   }
249 }
250