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 TEMPLATE = "submit";
134
135 protected String href;
136 protected String errorText;
137 protected String executeScripts;
138 protected String loadingText;
139 protected String listenTopics;
140 protected String handler;
141 protected String formId;
142 protected String formFilter;
143 protected String src;
144 protected String notifyTopics;
145 protected String showErrorTransportText;
146 protected String indicator;
147 protected String showLoadingText;
148 protected String targets;
149 protected String beforeNotifyTopics;
150 protected String afterNotifyTopics;
151 protected String errorNotifyTopics;
152 protected String highlightColor;
153 protected String highlightDuration;
154 protected String validate;
155 protected String ajaxAfterValidation;
156 protected String separateScripts;
157 protected String transport;
158 protected String parseContent;
159
160 public Submit(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
161 super(stack, request, response);
162 }
163
164 protected String getDefaultTemplate() {
165 return TEMPLATE;
166 }
167
168 public void evaluateParams() {
169 if ((key == null) && (value == null)) {
170 value = "Submit";
171 }
172
173 if (((key != null)) && (value == null)) {
174 this.value = "%{getText('"+key +"')}";
175 }
176
177 super.evaluateParams();
178 }
179
180 public void evaluateExtraParams() {
181 super.evaluateExtraParams();
182
183 if (href != null)
184 addParameter("href", findString(href));
185 if (errorText != null)
186 addParameter("errorText", findString(errorText));
187 if (loadingText != null)
188 addParameter("loadingText", findString(loadingText));
189 if (executeScripts != null)
190 addParameter("executeScripts", findValue(executeScripts, Boolean.class));
191 if (listenTopics != null)
192 addParameter("listenTopics", findString(listenTopics));
193 if (notifyTopics != null)
194 addParameter("notifyTopics", findString(notifyTopics));
195 if (handler != null)
196 addParameter("handler", findString(handler));
197 if (formId != null)
198 addParameter("formId", findString(formId));
199 if (formFilter != null)
200 addParameter("formFilter", findString(formFilter));
201 if (src != null)
202 addParameter("src", findString(src));
203 if (indicator != null)
204 addParameter("indicator", findString(indicator));
205 if (targets != null)
206 addParameter("targets", findString(targets));
207 if (showLoadingText != null)
208 addParameter("showLoadingText", findString(showLoadingText));
209 if (showLoadingText != null)
210 addParameter("showLoadingText", findString(showLoadingText));
211 if (beforeNotifyTopics != null)
212 addParameter("beforeNotifyTopics", findString(beforeNotifyTopics));
213 if (afterNotifyTopics != null)
214 addParameter("afterNotifyTopics", findString(afterNotifyTopics));
215 if (errorNotifyTopics != null)
216 addParameter("errorNotifyTopics", findString(errorNotifyTopics));
217 if (highlightColor != null)
218 addParameter("highlightColor", findString(highlightColor));
219 if (highlightDuration != null)
220 addParameter("highlightDuration", findString(highlightDuration));
221 if (separateScripts != null)
222 addParameter("separateScripts", findValue(separateScripts, Boolean.class));
223 if (transport != null)
224 addParameter("transport", findString(transport));
225 if (parseContent != null)
226 addParameter("parseContent", findValue(parseContent, Boolean.class));
227
228 Boolean validateValue = false;
229 if (validate != null) {
230 validateValue = (Boolean) findValue(validate, Boolean.class);
231 addParameter("validate", validateValue);
232 }
233
234 Form form = (Form) findAncestor(Form.class);
235 if (form != null)
236 addParameter("parentTheme", form.getTheme());
237
238 if (ajaxAfterValidation != null)
239 addParameter("ajaxAfterValidation", findValue(ajaxAfterValidation, Boolean.class));
240
241
242 Boolean parseContent = (Boolean)stack.getContext().get(Head.PARSE_CONTENT);
243 boolean generateId = (parseContent != null ? !parseContent : true);
244
245 addParameter("pushId", generateId);
246 if ((this.id == null || this.id.length() == 0) && generateId) {
247
248
249 int nextInt = RANDOM.nextInt();
250 nextInt = nextInt == Integer.MIN_VALUE ? Integer.MAX_VALUE : Math.abs(nextInt);
251 this.id = "widget_" + String.valueOf(nextInt);
252 addParameter("id", this.id);
253 }
254 }
255
256 @Override
257 @StrutsTagSkipInheritance
258 public void setTheme(String theme) {
259 super.setTheme(theme);
260 }
261
262 @Override
263 public String getTheme() {
264 return "ajax";
265 }
266
267 /***
268 * Indicate whether the concrete button supports the type "image".
269 *
270 * @return <tt>true</tt> to indicate type image is supported.
271 */
272 protected boolean supportsImageType() {
273 return true;
274 }
275
276 /***
277 * Overrides to be able to render body in a template rather than always before the template
278 */
279 public boolean end(Writer writer, String body) {
280 evaluateParams();
281 try {
282 addParameter("body", body);
283
284 mergeTemplate(writer, buildTemplateName(template, getDefaultTemplate()));
285 } catch (Exception e) {
286 LOG.error("error when rendering", e);
287 }
288 finally {
289 popComponentStack();
290 }
291
292 return false;
293 }
294
295 @StrutsTagAttribute(description="Topic that will trigger the remote call")
296 public void setListenTopics(String listenTopics) {
297 this.listenTopics = listenTopics;
298 }
299
300 @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.")
301 public void setHref(String href) {
302 this.href = href;
303 }
304
305 @StrutsTagAttribute(description="The text to display to the user if the is an error fetching the content")
306 public void setErrorText(String errorText) {
307 this.errorText = errorText;
308 }
309
310 @StrutsTagAttribute(description="Javascript code in the fetched content will be executed", type="Boolean", defaultValue="false")
311 public void setExecuteScripts(String executeScripts) {
312 this.executeScripts = executeScripts;
313 }
314
315 @StrutsTagAttribute(description="Text to be shown while content is being fetched", defaultValue="Loading...")
316 public void setLoadingText(String loadingText) {
317 this.loadingText = loadingText;
318 }
319
320 @StrutsTagAttribute(description="Javascript function name that will make the request")
321 public void setHandler(String handler) {
322 this.handler = handler;
323 }
324
325 @StrutsTagAttribute(description="Function name used to filter the fields of the form.")
326 public void setFormFilter(String formFilter) {
327 this.formFilter = formFilter;
328 }
329
330 @StrutsTagAttribute(description="Form id whose fields will be serialized and passed as parameters")
331 public void setFormId(String formId) {
332 this.formId = formId;
333 }
334
335 @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>.")
336 public void setSrc(String src) {
337 this.src = src;
338 }
339
340 @StrutsTagAttribute(description="Comma delimited list of ids of the elements whose content will be updated")
341 public void setTargets(String targets) {
342 this.targets = targets;
343 }
344
345 @StrutsTagAttribute(description="Comma delimmited list of topics that will published before and after the request, and on errors")
346 public void setNotifyTopics(String notifyTopics) {
347 this.notifyTopics = notifyTopics;
348 }
349
350 @StrutsTagAttribute(description="Set whether errors will be shown or not", type="Boolean", defaultValue="true")
351 public void setShowErrorTransportText(String showErrorTransportText) {
352 this.showErrorTransportText = showErrorTransportText;
353 }
354
355 @StrutsTagAttribute(description="Set indicator")
356 public void setIndicator(String indicator) {
357 this.indicator = indicator;
358 }
359
360 @StrutsTagAttribute(description="Show loading text on targets", type="Boolean", defaultValue="false")
361 public void setShowLoadingText(String showLoadingText) {
362 this.showLoadingText = showLoadingText;
363 }
364
365 @StrutsTagAttribute(description="The css class to use for element")
366 public void setCssClass(String cssClass) {
367 super.setCssClass(cssClass);
368 }
369
370 @StrutsTagAttribute(description="The css style to use for element")
371 public void setCssStyle(String cssStyle) {
372 super.setCssStyle(cssStyle);
373 }
374
375 @StrutsTagAttribute(description="The id to use for the element")
376 public void setId(String id) {
377 super.setId(id);
378 }
379
380 @StrutsTagAttribute(description="The name to set for element")
381 public void setName(String name) {
382 super.setName(name);
383 }
384
385 @StrutsTagAttribute(description="The type of submit to use. Valid values are <i>input</i>, " +
386 "<i>button</i> and <i>image</i>.", defaultValue="input")
387 public void setType(String type) {
388 super.setType(type);
389 }
390
391 @StrutsTagAttribute(description="Preset the value of input element.")
392 public void setValue(String value) {
393 super.setValue(value);
394 }
395
396 @StrutsTagAttribute(description="Label expression used for rendering a element specific label")
397 public void setLabel(String label) {
398 super.setLabel(label);
399 }
400
401 @StrutsTagAttribute(description="Comma delimmited list of topics that will published after the request(if the request succeeds)")
402 public void setAfterNotifyTopics(String afterNotifyTopics) {
403 this.afterNotifyTopics = afterNotifyTopics;
404 }
405
406 @StrutsTagAttribute(description="Comma delimmited list of topics that will published before the request")
407 public void setBeforeNotifyTopics(String beforeNotifyTopics) {
408 this.beforeNotifyTopics = beforeNotifyTopics;
409 }
410
411 @StrutsTagAttribute(description="Comma delimmited list of topics that will published after the request(if the request fails)")
412 public void setErrorNotifyTopics(String errorNotifyTopics) {
413 this.errorNotifyTopics = errorNotifyTopics;
414 }
415
416 @StrutsTagAttribute(description = "Color used to perform a highlight effect on the elements specified in the 'targets' attribute",
417 defaultValue = "none")
418 public void setHighlightColor(String highlightColor) {
419 this.highlightColor = highlightColor;
420 }
421
422 @StrutsTagAttribute(description = "Duration of highlight effect in milliseconds. Only valid if 'highlightColor' attribute is set",
423 defaultValue = "1000")
424 public void setHighlightDuration(String highlightDuration) {
425 this.highlightDuration = highlightDuration;
426 }
427
428 @StrutsTagAttribute(description = "Perform Ajax calidation. 'ajaxValidation' interceptor must be applied to action", type="Boolean",
429 defaultValue = "false")
430 public void setValidate(String validate) {
431 this.validate = validate;
432 }
433
434 @StrutsTagAttribute(description = "Make an asynchronous request if validation succeeds. Only valid if 'validate' is 'true'", type="Boolean",
435 defaultValue = "false")
436 public void setAjaxAfterValidation(String ajaxAfterValidation) {
437 this.ajaxAfterValidation = ajaxAfterValidation;
438 }
439
440 @StrutsTagSkipInheritance
441 public void setAction(String action) {
442 super.setAction(action);
443 }
444
445 @StrutsTagAttribute(description="Run scripts in a separate scope, unique for each tag", defaultValue="true")
446 public void setSeparateScripts(String separateScripts) {
447 this.separateScripts = separateScripts;
448 }
449
450 @StrutsTagAttribute(description="Transport used by Dojo to make the request", defaultValue="XMLHTTPTransport")
451 public void setTransport(String transport) {
452 this.transport = transport;
453 }
454
455 @StrutsTagAttribute(description="Parse returned HTML for Dojo widgets", defaultValue="true", type="Boolean")
456 public void setParseContent(String parseContent) {
457 this.parseContent = parseContent;
458 }
459 }