1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.struts2.dojo.components;
23
24 import java.io.Writer;
25 import java.util.Random;
26
27 import javax.servlet.http.HttpServletRequest;
28 import javax.servlet.http.HttpServletResponse;
29
30 import org.apache.struts2.components.Form;
31 import org.apache.struts2.components.FormButton;
32 import org.apache.struts2.views.annotations.StrutsTag;
33 import org.apache.struts2.views.annotations.StrutsTagAttribute;
34 import org.apache.struts2.views.annotations.StrutsTagSkipInheritance;
35
36 import com.opensymphony.xwork2.util.ValueStack;
37 import com.opensymphony.xwork2.util.logging.Logger;
38 import com.opensymphony.xwork2.util.logging.LoggerFactory;
39
40 /***
41 * <!-- START SNIPPET: javadoc -->
42 * Renders a submit button that can submit a form asynchronously.
43 * The submit can have three different types of rendering:
44 * <ul>
45 * <li>input: renders as html <input type="submit"...></li>
46 * <li>image: renders as html <input type="image"...></li>
47 * <li>button: renders as html <button type="submit"...></li>
48 * </ul>
49 * Please note that the button type has advantages by adding the possibility to seperate the submitted value from the
50 * text shown on the button face, but has issues with Microsoft Internet Explorer at least up to 6.0
51 * <!-- END SNIPPET: javadoc -->
52 *
53 * <p>Examples</p>
54 * <!-- START SNIPPET: example1 -->
55 * <sx:submit value="%{'Submit'}" />
56 * <!-- END SNIPPET: example1 -->
57 *
58 * <!-- START SNIPPET: example2 -->
59 * <sx:submit type="image" value="%{'Submit'}" label="Submit the form" src="submit.gif"/>
60 * <!-- END SNIPPET: example2 -->
61
62 * <!-- START SNIPPET: example3 -->
63 * <sx:submit type="button" value="%{'Submit'}" label="Submit the form"/>
64 * <!-- END SNIPPET: example3 -->
65 *
66 * <!-- START SNIPPET: example4 -->
67 * <div id="div1">Div 1</div>
68 * <s:url id="ajaxTest" value="/AjaxTest.action"/>
69 *
70 * <sx:submit id="link1" href="%{ajaxTest}" target="div1" />
71 * <!-- END SNIPPET: example4 -->
72 *
73 * <!-- START SNIPPET: example5 -->
74 * <s:form id="form" action="AjaxTest">
75 * <input type="textbox" name="data">
76 * <sx:submit />
77 * </s:form>
78 * <!-- END SNIPPET: example5 -->
79 *
80 * <!-- START SNIPPET: example6 -->
81 * <s:form id="form" action="AjaxTest">
82 * <input type="textbox" name="data">
83 * </s:form>
84 *
85 * <sx:submit formId="form" />
86 * <!-- END SNIPPET: example6 -->
87 *
88 * <!-- START SNIPPET: example7 -->
89 * <script type="text/javascript">
90 * dojo.event.topic.subscribe("/before", function(event, widget){
91 * alert('inside a topic event. before request');
92 * //event: set event.cancel = true, to cancel request
93 * //widget: widget that published the topic
94 * });
95 * </script>
96 *
97 * <sx:submit beforeNotifyTopics="/before" />
98 * <!-- END SNIPPET: example7 -->
99 *
100 * <!-- START SNIPPET: example8 -->
101 * <script type="text/javascript">
102 * dojo.event.topic.subscribe("/after", function(data, request, widget){
103 * alert('inside a topic event. after request');
104 * //data : text returned from request(the html)
105 * //request: XMLHttpRequest object
106 * //widget: widget that published the topic
107 * });
108 * </script>
109 *
110 * <sx:submit afterNotifyTopics="/after" highlightColor="red" href="%{#ajaxTest}" />
111 * <!-- END SNIPPET: example8 -->
112 *
113 * <!-- START SNIPPET: example9 -->
114 * <script type="text/javascript">
115 * dojo.event.topic.subscribe("/error", function(error, request, widget){
116 * alert('inside a topic event. on error');
117 * //error : error object (error.message has the error message)
118 * //request: XMLHttpRequest object
119 * //widget: widget that published the topic
120 * });
121 * </script>
122 *
123 * <img id="ind1" src="${pageContext.request.contextPath}/images/indicator.gif" style="display:none"/>
124 * <sx:submit errorNotifyTopics="/error" indicator="ind1" href="%{#ajaxTest}" />
125 * <!-- END SNIPPET: example9 -->
126 */
127 @StrutsTag(name="submit", tldTagClass="org.apache.struts2.dojo.views.jsp.ui.SubmitTag", description="Render a submit button")
128 public class Submit extends FormButton implements RemoteBean {
129
130 private static final Logger LOG = LoggerFactory.getLogger(Submit.class);
131 private final static transient Random RANDOM = new Random();
132
133 final public static String OPEN_TEMPLATE = "submit";
134 final public static String TEMPLATE = "submit-close";
135
136 protected String href;
137 protected String errorText;
138 protected String executeScripts;
139 protected String loadingText;
140 protected String listenTopics;
141 protected String handler;
142 protected String formId;
143 protected String formFilter;
144 protected String src;
145 protected String notifyTopics;
146 protected String showErrorTransportText;
147 protected String indicator;
148 protected String showLoadingText;
149 protected String targets;
150 protected String beforeNotifyTopics;
151 protected String afterNotifyTopics;
152 protected String errorNotifyTopics;
153 protected String highlightColor;
154 protected String highlightDuration;
155 protected String validate;
156 protected String ajaxAfterValidation;
157 protected String separateScripts;
158 protected String transport;
159 protected String parseContent;
160
161 public Submit(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
162 super(stack, request, response);
163 }
164
165 protected String getDefaultTemplate() {
166 return TEMPLATE;
167 }
168
169 @Override
170 public String getDefaultOpenTemplate() {
171 return OPEN_TEMPLATE;
172 }
173
174 public void evaluateParams() {
175 if ((key == null) && (value == null)) {
176 value = "Submit";
177 }
178
179 if (((key != null)) && (value == null)) {
180 this.value = "%{getText('"+key +"')}";
181 }
182
183 super.evaluateParams();
184 }
185
186 public void evaluateExtraParams() {
187 super.evaluateExtraParams();
188
189 if (href != null)
190 addParameter("href", findString(href));
191 if (errorText != null)
192 addParameter("errorText", findString(errorText));
193 if (loadingText != null)
194 addParameter("loadingText", findString(loadingText));
195 if (executeScripts != null)
196 addParameter("executeScripts", findValue(executeScripts, Boolean.class));
197 if (listenTopics != null)
198 addParameter("listenTopics", findString(listenTopics));
199 if (notifyTopics != null)
200 addParameter("notifyTopics", findString(notifyTopics));
201 if (handler != null)
202 addParameter("handler", findString(handler));
203 if (formId != null)
204 addParameter("formId", findString(formId));
205 if (formFilter != null)
206 addParameter("formFilter", findString(formFilter));
207 if (src != null)
208 addParameter("src", findString(src));
209 if (indicator != null)
210 addParameter("indicator", findString(indicator));
211 if (targets != null)
212 addParameter("targets", findString(targets));
213 if (showLoadingText != null)
214 addParameter("showLoadingText", findString(showLoadingText));
215 if (showLoadingText != null)
216 addParameter("showLoadingText", findString(showLoadingText));
217 if (beforeNotifyTopics != null)
218 addParameter("beforeNotifyTopics", findString(beforeNotifyTopics));
219 if (afterNotifyTopics != null)
220 addParameter("afterNotifyTopics", findString(afterNotifyTopics));
221 if (errorNotifyTopics != null)
222 addParameter("errorNotifyTopics", findString(errorNotifyTopics));
223 if (highlightColor != null)
224 addParameter("highlightColor", findString(highlightColor));
225 if (highlightDuration != null)
226 addParameter("highlightDuration", findString(highlightDuration));
227 if (separateScripts != null)
228 addParameter("separateScripts", findValue(separateScripts, Boolean.class));
229 if (transport != null)
230 addParameter("transport", findString(transport));
231 if (parseContent != null)
232 addParameter("parseContent", findValue(parseContent, Boolean.class));
233
234 Boolean validateValue = false;
235 if (validate != null) {
236 validateValue = (Boolean) findValue(validate, Boolean.class);
237 addParameter("validate", validateValue);
238 }
239
240 Form form = (Form) findAncestor(Form.class);
241 if (form != null)
242 addParameter("parentTheme", form.getTheme());
243
244 if (ajaxAfterValidation != null)
245 addParameter("ajaxAfterValidation", findValue(ajaxAfterValidation, Boolean.class));
246
247
248 Boolean parseContent = (Boolean)stack.getContext().get(Head.PARSE_CONTENT);
249 boolean generateId = (parseContent != null ? !parseContent : true);
250
251 addParameter("pushId", generateId);
252 if ((this.id == null || this.id.length() == 0) && generateId) {
253
254
255 int nextInt = RANDOM.nextInt();
256 nextInt = nextInt == Integer.MIN_VALUE ? Integer.MAX_VALUE : Math.abs(nextInt);
257 this.id = "widget_" + String.valueOf(nextInt);
258 addParameter("id", this.id);
259 }
260 }
261
262 @Override
263 @StrutsTagSkipInheritance
264 public void setTheme(String theme) {
265 super.setTheme(theme);
266 }
267
268 @Override
269 public String getTheme() {
270 return "ajax";
271 }
272
273 /***
274 * Indicate whether the concrete button supports the type "image".
275 *
276 * @return <tt>true</tt> to indicate type image is supported.
277 */
278 protected boolean supportsImageType() {
279 return true;
280 }
281
282 /***
283 * Overrides to be able to render body in a template rather than always before the template
284 */
285 public boolean end(Writer writer, String body) {
286 evaluateParams();
287 try {
288 addParameter("body", body);
289
290 mergeTemplate(writer, buildTemplateName(template, getDefaultTemplate()));
291 } catch (Exception e) {
292 LOG.error("error when rendering", e);
293 }
294 finally {
295 popComponentStack();
296 }
297
298 return false;
299 }
300
301 @StrutsTagAttribute(description="Topic that will trigger the remote call")
302 public void setListenTopics(String listenTopics) {
303 this.listenTopics = listenTopics;
304 }
305
306 @StrutsTagAttribute(description="The URL to call to obtain the content. Note: If used with ajax context, the value must be set as an url tag value.")
307 public void setHref(String href) {
308 this.href = href;
309 }
310
311 @StrutsTagAttribute(description="The text to display to the user if the is an error fetching the content")
312 public void setErrorText(String errorText) {
313 this.errorText = errorText;
314 }
315
316 @StrutsTagAttribute(description="Javascript code in the fetched content will be executed", type="Boolean", defaultValue="false")
317 public void setExecuteScripts(String executeScripts) {
318 this.executeScripts = executeScripts;
319 }
320
321 @StrutsTagAttribute(description="Text to be shown while content is being fetched", defaultValue="Loading...")
322 public void setLoadingText(String loadingText) {
323 this.loadingText = loadingText;
324 }
325
326 @StrutsTagAttribute(description="Javascript function name that will make the request")
327 public void setHandler(String handler) {
328 this.handler = handler;
329 }
330
331 @StrutsTagAttribute(description="Function name used to filter the fields of the form.")
332 public void setFormFilter(String formFilter) {
333 this.formFilter = formFilter;
334 }
335
336 @StrutsTagAttribute(description="Form id whose fields will be serialized and passed as parameters")
337 public void setFormId(String formId) {
338 this.formId = formId;
339 }
340
341 @StrutsTagAttribute(description="Supply an image src for <i>image</i> type submit button. Will have no effect for types <i>input</i> and <i>button</i>.")
342 public void setSrc(String src) {
343 this.src = src;
344 }
345
346 @StrutsTagAttribute(description="Comma delimited list of ids of the elements whose content will be updated")
347 public void setTargets(String targets) {
348 this.targets = targets;
349 }
350
351 @StrutsTagAttribute(description="Comma delimmited list of topics that will published before and after the request, and on errors")
352 public void setNotifyTopics(String notifyTopics) {
353 this.notifyTopics = notifyTopics;
354 }
355
356 @StrutsTagAttribute(description="Set whether errors will be shown or not", type="Boolean", defaultValue="true")
357 public void setShowErrorTransportText(String showErrorTransportText) {
358 this.showErrorTransportText = showErrorTransportText;
359 }
360
361 @StrutsTagAttribute(description="Set indicator")
362 public void setIndicator(String indicator) {
363 this.indicator = indicator;
364 }
365
366 @StrutsTagAttribute(description="Show loading text on targets", type="Boolean", defaultValue="false")
367 public void setShowLoadingText(String showLoadingText) {
368 this.showLoadingText = showLoadingText;
369 }
370
371 @StrutsTagAttribute(description="The css class to use for element")
372 public void setCssClass(String cssClass) {
373 super.setCssClass(cssClass);
374 }
375
376 @StrutsTagAttribute(description="The css style to use for element")
377 public void setCssStyle(String cssStyle) {
378 super.setCssStyle(cssStyle);
379 }
380
381 @StrutsTagAttribute(description="The id to use for the element")
382 public void setId(String id) {
383 super.setId(id);
384 }
385
386 @StrutsTagAttribute(description="The name to set for element")
387 public void setName(String name) {
388 super.setName(name);
389 }
390
391 @StrutsTagAttribute(description="The type of submit to use. Valid values are <i>input</i>, " +
392 "<i>button</i> and <i>image</i>.", defaultValue="input")
393 public void setType(String type) {
394 super.setType(type);
395 }
396
397 @StrutsTagAttribute(description="Preset the value of input element.")
398 public void setValue(String value) {
399 super.setValue(value);
400 }
401
402 @StrutsTagAttribute(description="Label expression used for rendering a element specific label")
403 public void setLabel(String label) {
404 super.setLabel(label);
405 }
406
407 @StrutsTagAttribute(description="Comma delimmited list of topics that will published after the request(if the request succeeds)")
408 public void setAfterNotifyTopics(String afterNotifyTopics) {
409 this.afterNotifyTopics = afterNotifyTopics;
410 }
411
412 @StrutsTagAttribute(description="Comma delimmited list of topics that will published before the request")
413 public void setBeforeNotifyTopics(String beforeNotifyTopics) {
414 this.beforeNotifyTopics = beforeNotifyTopics;
415 }
416
417 @StrutsTagAttribute(description="Comma delimmited list of topics that will published after the request(if the request fails)")
418 public void setErrorNotifyTopics(String errorNotifyTopics) {
419 this.errorNotifyTopics = errorNotifyTopics;
420 }
421
422 @StrutsTagAttribute(description = "Color used to perform a highlight effect on the elements specified in the 'targets' attribute",
423 defaultValue = "none")
424 public void setHighlightColor(String highlightColor) {
425 this.highlightColor = highlightColor;
426 }
427
428 @StrutsTagAttribute(description = "Duration of highlight effect in milliseconds. Only valid if 'highlightColor' attribute is set",
429 defaultValue = "1000")
430 public void setHighlightDuration(String highlightDuration) {
431 this.highlightDuration = highlightDuration;
432 }
433
434 @StrutsTagAttribute(description = "Perform Ajax validation. 'ajaxValidation' interceptor must be applied to action", type="Boolean",
435 defaultValue = "false")
436 public void setValidate(String validate) {
437 this.validate = validate;
438 }
439
440 @StrutsTagAttribute(description = "Make an asynchronous request if validation succeeds. Only valid if 'validate' is 'true'", type="Boolean",
441 defaultValue = "false")
442 public void setAjaxAfterValidation(String ajaxAfterValidation) {
443 this.ajaxAfterValidation = ajaxAfterValidation;
444 }
445
446 @StrutsTagSkipInheritance
447 public void setAction(String action) {
448 super.setAction(action);
449 }
450
451 @StrutsTagAttribute(description="Run scripts in a separate scope, unique for each tag", defaultValue="true")
452 public void setSeparateScripts(String separateScripts) {
453 this.separateScripts = separateScripts;
454 }
455
456 @StrutsTagAttribute(description="Transport used by Dojo to make the request", defaultValue="XMLHTTPTransport")
457 public void setTransport(String transport) {
458 this.transport = transport;
459 }
460
461 @StrutsTagAttribute(description="Parse returned HTML for Dojo widgets", defaultValue="true", type="Boolean")
462 public void setParseContent(String parseContent) {
463 this.parseContent = parseContent;
464 }
465 }