KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > user > client > ui > FormPanel


1 /*
2  * Copyright 2006 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.user.client.ui;
17
18 import com.google.gwt.core.client.GWT;
19 import com.google.gwt.user.client.Command;
20 import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
21 import com.google.gwt.user.client.DOM;
22 import com.google.gwt.user.client.DeferredCommand;
23 import com.google.gwt.user.client.Element;
24 import com.google.gwt.user.client.Event;
25 import com.google.gwt.user.client.ui.impl.FormPanelImpl;
26 import com.google.gwt.user.client.ui.impl.FormPanelImplHost;
27
28 /**
29  * A panel that wraps its contents in an HTML <FORM> element.
30  *
31  * <p>
32  * This panel can be used to achieve interoperability with servers that accept
33  * traditional HTML form encoding. The following widgets (those that implement
34  * {@link com.google.gwt.user.client.ui.HasName}) will be submitted to the
35  * server if they are contained within this panel:
36  * <ul>
37  * <li>{@link com.google.gwt.user.client.ui.TextBox}</li>
38  * <li>{@link com.google.gwt.user.client.ui.PasswordTextBox}</li>
39  * <li>{@link com.google.gwt.user.client.ui.RadioButton}</li>
40  * <li>{@link com.google.gwt.user.client.ui.CheckBox}</li>
41  * <li>{@link com.google.gwt.user.client.ui.TextArea}</li>
42  * <li>{@link com.google.gwt.user.client.ui.ListBox}</li>
43  * <li>{@link com.google.gwt.user.client.ui.FileUpload}</li>
44  * <li>{@link com.google.gwt.user.client.ui.Hidden}</li>
45  * </ul>
46  * In particular, {@link com.google.gwt.user.client.ui.FileUpload} is <i>only</i>
47  * useful when used within a FormPanel, because the browser will only upload
48  * files using form submission.
49  * </p>
50  *
51  * <p>
52  * <h3>Example</h3>
53  * {@example com.google.gwt.examples.FormPanelExample}
54  * </p>
55  */

56 public class FormPanel extends SimplePanel implements FiresFormEvents,
57     FormPanelImplHost {
58
59   /**
60    * Used with {@link #setEncoding(String)} to specify that the form will be
61    * submitted using MIME encoding (necessary for {@link FileUpload} to work
62    * properly).
63    */

64   public static final String JavaDoc ENCODING_MULTIPART = "multipart/form-data";
65
66   /**
67    * Used with {@link #setEncoding(String)} to specify that the form will be
68    * submitted using traditional URL encoding.
69    */

70   public static final String JavaDoc ENCODING_URLENCODED = "application/x-www-form-urlencoded";
71
72   /**
73    * Used with {@link #setMethod(String)} to specify that the form will be
74    * submitted using an HTTP GET request.
75    */

76   public static final String JavaDoc METHOD_GET = "get";
77
78   /**
79    * Used with {@link #setMethod(String)} to specify that the form will be
80    * submitted using an HTTP POST request (necessary for {@link FileUpload} to
81    * work properly).
82    */

83   public static final String JavaDoc METHOD_POST = "post";
84
85   private static int formId = 0;
86   private static FormPanelImpl impl = (FormPanelImpl) GWT.create(FormPanelImpl.class);
87
88   private FormHandlerCollection formHandlers;
89   private String JavaDoc frameName;
90   private Element iframe;
91
92   /**
93    * Creates a new FormPanel. When created using this constructor, it will be
94    * submitted to a hidden &lt;iframe&gt; element, and the results of the
95    * submission made available via {@link FormHandler}.
96    *
97    * <p>
98    * The back-end server is expected to respond with a content-type of
99    * 'text/html', meaning that the text returned will be treated as HTML. If any
100    * other content-type is specified by the server, then the result html sent in
101    * the onFormSubmit event will be unpredictable across browsers, and the
102    * {@link FormHandler#onSubmitComplete(FormSubmitCompleteEvent)} event may not
103    * fire at all.
104    * </p>
105    *
106    * @tip The initial implementation of FormPanel specified that the server
107    * respond with a content-type of 'text/plain'. This has been
108    * intentionally changed to specify 'text/html' because 'text/plain'
109    * cannot be made to work properly on all browsers.
110    */

111   public FormPanel() {
112     super(DOM.createForm());
113
114     frameName = "FormPanel_" + (++formId);
115     setTarget(frameName);
116
117     sinkEvents(Event.ONLOAD);
118   }
119
120   /**
121    * Creates a FormPanel that targets a {@link NamedFrame}. The target frame is
122    * not physically attached to the form, and must therefore still be added to a
123    * panel elsewhere.
124    *
125    * <p>
126    * When the FormPanel targets an external frame in this way, it will not fire
127    * the onFormSubmit event.
128    * </p>
129    *
130    * @param frameTarget the {@link NamedFrame} to be targetted
131    */

132   public FormPanel(NamedFrame frameTarget) {
133     this(frameTarget.getName());
134   }
135
136   /**
137    * Creates a new FormPanel. When created using this constructor, it will be
138    * submitted either by replacing the current page, or to the named
139    * &lt;iframe&gt;.
140    *
141    * <p>
142    * When the FormPanel targets an external frame in this way, it will not fire
143    * the onFormSubmit event.
144    * </p>
145    *
146    * @param target the name of the &lt;iframe&gt; to receive the results of the
147    * submission, or <code>null</code> to specify that the current
148    * page be replaced
149    */

150   public FormPanel(String JavaDoc target) {
151     super(DOM.createForm());
152     setTarget(target);
153   }
154
155   public void addFormHandler(FormHandler handler) {
156     if (formHandlers == null) {
157       formHandlers = new FormHandlerCollection();
158     }
159     formHandlers.add(handler);
160   }
161
162   /**
163    * Gets the 'action' associated with this form. This is the URL to which it
164    * will be submitted.
165    *
166    * @return the form's action
167    */

168   public String JavaDoc getAction() {
169     return DOM.getElementProperty(getElement(), "action");
170   }
171
172   /**
173    * Gets the encoding used for submitting this form. This should be either
174    * {@link #ENCODING_MULTIPART} or {@link #ENCODING_URLENCODED}.
175    *
176    * @return the form's encoding
177    */

178   public String JavaDoc getEncoding() {
179     return impl.getEncoding(getElement());
180   }
181
182   /**
183    * Gets the HTTP method used for submitting this form. This should be either
184    * {@link #METHOD_GET} or {@link #METHOD_POST}.
185    *
186    * @return the form's method
187    */

188   public String JavaDoc getMethod() {
189     return DOM.getElementProperty(getElement(), "method");
190   }
191
192   /**
193    * Gets the form's 'target'. This is the name of the {@link NamedFrame} that
194    * will receive the results of submission, or <code>null</code> if none has
195    * been specified.
196    *
197    * @return the form's target.
198    */

199   public String JavaDoc getTarget() {
200     return DOM.getElementProperty(getElement(), "target");
201   }
202
203   public boolean onFormSubmit() {
204     UncaughtExceptionHandler handler = GWT.getUncaughtExceptionHandler();
205     if (handler != null) {
206       return onFormSubmitAndCatch(handler);
207     } else {
208       return onFormSubmitImpl();
209     }
210   }
211
212   public void onFrameLoad() {
213     UncaughtExceptionHandler handler = GWT.getUncaughtExceptionHandler();
214     if (handler != null) {
215       onFrameLoadAndCatch(handler);
216     } else {
217       onFrameLoadImpl();
218     }
219   }
220
221   public void removeFormHandler(FormHandler handler) {
222     if (formHandlers != null) {
223       formHandlers.remove(handler);
224     }
225   }
226
227   /**
228    * Sets the 'action' associated with this form. This is the URL to which it
229    * will be submitted.
230    *
231    * @param url the form's action
232    */

233   public void setAction(String JavaDoc url) {
234     DOM.setElementProperty(getElement(), "action", url);
235   }
236
237   /**
238    * Sets the encoding used for submitting this form. This should be either
239    * {@link #ENCODING_MULTIPART} or {@link #ENCODING_URLENCODED}.
240    *
241    * @param encodingType the form's encoding
242    */

243   public void setEncoding(String JavaDoc encodingType) {
244     impl.setEncoding(getElement(), encodingType);
245   }
246
247   /**
248    * Sets the HTTP method used for submitting this form. This should be either
249    * {@link #METHOD_GET} or {@link #METHOD_POST}.
250    *
251    * @param method the form's method
252    */

253   public void setMethod(String JavaDoc method) {
254     DOM.setElementProperty(getElement(), "method", method);
255   }
256
257   /**
258    * Submits the form.
259    *
260    * <p>
261    * The FormPanel must <em>not</em> be detached (i.e. removed from its parent
262    * or otherwise disconnected from a {@link RootPanel}) until the submission
263    * is complete. Otherwise, notification of submission will fail.
264    * </p>
265    */

266   public void submit() {
267     // Fire the onSubmit event, because javascript's form.submit() does not
268
// fire the built-in onsubmit event.
269
if (formHandlers != null) {
270       if (formHandlers.fireOnSubmit(this)) {
271         return;
272       }
273     }
274
275     impl.submit(getElement(), iframe);
276   }
277
278   protected void onAttach() {
279     super.onAttach();
280
281     // Create and attach a hidden iframe to the body element.
282
createFrame();
283     DOM.appendChild(RootPanel.getBodyElement(), iframe);
284
285     // Hook up the underlying iframe's onLoad event when attached to the DOM.
286
// Making this connection only when attached avoids memory-leak issues.
287
// The FormPanel cannot use the built-in GWT event-handling mechanism
288
// because there is no standard onLoad event on iframes that works across
289
// browsers.
290
impl.hookEvents(iframe, getElement(), this);
291   }
292
293   protected void onDetach() {
294     super.onDetach();
295
296     // Unhook the iframe's onLoad when detached.
297
impl.unhookEvents(iframe, getElement());
298
299     DOM.removeChild(RootPanel.getBodyElement(), iframe);
300     iframe = null;
301   }
302
303   private void createFrame() {
304     // Attach a hidden IFrame to the form. This is the target iframe to which
305
// the form will be submitted. We have to create the iframe using innerHTML,
306
// because setting an iframe's 'name' property dynamically doesn't work on
307
// most browsers.
308
Element dummy = DOM.createDiv();
309     DOM.setInnerHTML(dummy, "<iframe name='" + frameName
310         + "' style='width:0;height:0;border:0'>");
311
312     iframe = DOM.getFirstChild(dummy);
313   }
314
315   private boolean onFormSubmitAndCatch(UncaughtExceptionHandler handler) {
316     try {
317       return onFormSubmitImpl();
318     } catch (Throwable JavaDoc e) {
319       handler.onUncaughtException(e);
320       return false;
321     }
322   }
323
324   private boolean onFormSubmitImpl() {
325     if (formHandlers != null) {
326       // fireOnSubmit() returns true if the submit should be cancelled
327
return !formHandlers.fireOnSubmit(this);
328     }
329
330     return true;
331   }
332
333   private void onFrameLoadAndCatch(UncaughtExceptionHandler handler) {
334     try {
335       onFrameLoadImpl();
336     } catch (Throwable JavaDoc e) {
337       handler.onUncaughtException(e);
338     }
339   }
340
341   private void onFrameLoadImpl() {
342     if (formHandlers != null) {
343       // Fire onComplete events in a deferred command. This is necessary
344
// because clients that detach the form panel when submission is
345
// complete can cause some browsers (i.e. Mozilla) to go into an
346
// 'infinite loading' state. See issue 916.
347
DeferredCommand.addCommand(new Command() {
348         public void execute() {
349           formHandlers.fireOnComplete(this, impl.getContents(iframe));
350         }
351       });
352     }
353   }
354
355   private void setTarget(String JavaDoc target) {
356     DOM.setElementProperty(getElement(), "target", target);
357   }
358 }
359
Popular Tags