KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > tags > html > Button


1 /*
2  * Copyright 2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * $Header:$
17  */

18 package org.apache.beehive.netui.tags.html;
19
20 import org.apache.beehive.netui.util.internal.InternalStringBuilder;
21
22 import org.apache.beehive.netui.core.urls.URLRewriterService;
23 import org.apache.beehive.netui.pageflow.PageFlowUtils;
24 import org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils;
25 import org.apache.beehive.netui.tags.HtmlUtils;
26 import org.apache.beehive.netui.tags.IHtmlAccessable;
27 import org.apache.beehive.netui.tags.internal.PageFlowTagUtils;
28 import org.apache.beehive.netui.tags.javascript.CoreScriptFeature;
29 import org.apache.beehive.netui.tags.javascript.IScriptReporter;
30 import org.apache.beehive.netui.tags.javascript.ScriptRequestState;
31 import org.apache.beehive.netui.tags.rendering.*;
32 import org.apache.beehive.netui.util.Bundle;
33 import org.apache.beehive.netui.util.ParamHelper;
34 import org.apache.beehive.netui.util.logging.Logger;
35 import org.apache.struts.taglib.html.Constants;
36
37 import javax.servlet.ServletContext JavaDoc;
38 import javax.servlet.http.HttpServletRequest JavaDoc;
39 import javax.servlet.http.HttpServletResponse JavaDoc;
40 import javax.servlet.jsp.JspException JavaDoc;
41 import java.net.URISyntaxException JavaDoc;
42 import java.util.HashMap JavaDoc;
43 import java.util.Map JavaDoc;
44
45 /**
46  * Generates a button on the page with the specified attributes. The
47  * <netui:button> tag must be enclosed in <netui:form...> ...
48  * </netui:form> tags. You can specify the action that the form will
49  * raise on the <netui:form> tag.
50  * @jsptagref.tagdescription Renders an <input type="button"> tag with the specified attributes.
51  * To submit data or invoke a method on the Controller file, the
52  * <netui:button> tag must have a parent {@link Form} tag.
53  * The action attribute on the <netui:button> is for the purpose
54  * of overriding the action attribute on the enclosing <netui:form> tag.
55  * If no action attribute is specified on the <netui:button> tag,
56  * the action attribute
57  * on the <netui:form> tag will determine which action method is invoked.
58  * @example In this sample, the <netui:button> submits data to
59  * the Controller file's <code>processData</code> action method (specified on the &lt;netui:form>'s action
60  * attribute).
61  * <pre>
62  * &lt;netui:form action="processData">
63  * &lt;!--
64  * input elements here
65  * -->
66  * &lt;netui:button value="Submit" type="submit"/>
67  * &lt;/netui:form></pre>
68  * @netui:tag name="button" description="Create a button on your JSP page."
69  */

70 public class Button
71         extends HtmlFocusBaseTag
72         implements IUrlParams, IHtmlAccessable, IHasPopupSupport
73 {
74     private static final Logger logger = Logger.getInstance(Button.class);
75
76     public static final String JavaDoc ACTION_OVERRIDE = "actionOverride:";
77
78     private InputSubmitTag.State _state = new InputSubmitTag.State();
79
80     private String JavaDoc _action; // The action which will override the action on the form
81
private String JavaDoc _value; // The text of the button (this will override any body text).
82
private Map JavaDoc _params; // Any parameters to the submit
83
private String JavaDoc _targetScope; // Target page flow scope; see comments on setTargetScope()
84
private PopupSupport _popupSupport = null; // popup support, if the popup attribute is set to true
85
private boolean _disableSecondClick = false; // When clicked, this button will disable itself before submitting.
86

87     /**
88      * Return the name of the Tag.
89      */

90     public String JavaDoc getTagName()
91     {
92         return "Button";
93     }
94
95     /**
96      * This method will return the state associated with the tag. This is used by this
97      * base class to access the individual state objects created by the tags.
98      * @return a subclass of the <code>AbstractHtmlState</code> class.
99      */

100     protected AbstractHtmlState getState()
101     {
102         return _state;
103     }
104
105     /**
106      * Base support for the attribute tag. This is overridden to prevent setting the <code>type</code>
107      * and <code>value</code> attributes.
108      * @param name The name of the attribute. This value may not be null or the empty string.
109      * @param value The value of the attribute.
110      * @param facet The name of a facet to which the attribute will be applied. This is optional.
111      * @throws JspException A JspException may be thrown if there is an error setting the attribute.
112      */

113     public void setAttribute(String JavaDoc name, String JavaDoc value, String JavaDoc facet)
114             throws JspException JavaDoc
115     {
116         if (name != null && (name.equals(TYPE) || name.equals(VALUE))) {
117             String JavaDoc s = Bundle.getString("Tags_AttributeMayNotBeSet", new Object JavaDoc[]{name});
118             registerTagError(s, null);
119         }
120         super.setAttribute(name, value, facet);
121     }
122
123     /**
124      * Set the name of the action for the Button.
125      * @param action the name of the action to set for the Button.
126      * @jsptagref.attributedescription The action method invoked. The value of this attribute will override
127      * the <code>action</code>
128      * attribute of the parent &lt;netui:form> tag.
129      * @jsptagref.databindable false
130      * @jsptagref.attributesyntaxvalue <i>string_action</i>
131      * @netui:attribute required="false" rtexprvalue="true"
132      * description="The action method invoked. The value of this attribute will override
133      * the action attribute of the parent <netui:form> tag."
134      */

135     public void setAction(String JavaDoc action)
136             throws JspException JavaDoc
137     {
138         _action = setRequiredValueAttribute(action, "action");
139     }
140
141     /**
142      * Set the target "scope" for the button's action. Multiple active page flows may exist concurrently within named
143      * scopes. This attribute selects which named scope to use. If omitted, the default scope is assumed.
144      * @param targetScope the name of the target scope in which the associated action's page flow resides.
145      * @jsptagref.attributedescription The target scope in which the associated action's page flow resides.
146      * @jsptagref.databindable true
147      * @jsptagref.attributesyntaxvalue <i>string_targetScope</i>
148      * @netui:attribute required="false" rtexprvalue="true"
149      * description="The target scope in which the associated action's page flow resides"
150      */

151     public void setTargetScope(String JavaDoc targetScope)
152     {
153         _targetScope = targetScope;
154     }
155
156     /**
157      * Set the type of the Button (submit, button, or reset).
158      * @param type the type of the Button.
159      * @jsptagref.attributedescription The type of the button. Possible values are <code>submit</code>, <code>button</code>, or <code>reset</code>.
160      * The default value is <code>submit</code>.
161      * @jsptagref.databindable false
162      * @jsptagref.attributesyntaxvalue <i>string_type</i>
163      * @netui:attribute required="false" rtexprvalue="true"
164      * description="The type of the button. Possible values are submit, button, or reset.
165      * The default value is submit."
166      */

167     public void setType(String JavaDoc type)
168             throws JspException JavaDoc
169     {
170         if (INPUT_SUBMIT.equals(type) || INPUT_BUTTON.equals(type) || INPUT_RESET.equals(type)) {
171             _state.type = type;
172             return;
173         }
174         String JavaDoc s = Bundle.getString("Tags_ButtonTypeError", new Object JavaDoc[]{type});
175         registerTagError(s, null);
176     }
177
178     /**
179      * Set the value of the Button's text.
180      * @param value the value of the Button's text.
181      * @jsptagref.attributedescription The text displayed by the rendered HTML button.
182      * @jsptagref.databindable Read Only
183      * @jsptagref.attributesyntaxvalue <i>string_value</i>
184      * @netui:attribute required="false" rtexprvalue="true"
185      * description="The text displayed by the rendered HTML button."
186      */

187     public void setValue(String JavaDoc value)
188             throws JspException JavaDoc
189     {
190         _value = setNonEmptyValueAttribute(value);
191     }
192
193     /**
194      * Sets the popup indicator.
195      * @param popup whether or not the button should open a popup window.
196      * @jsptagref.attributedescription Boolean. If <code>popup</code> is set to true,
197      * the button will open a popup window.
198      * @jsptagref.databindable true
199      * @jsptagref.attributesyntaxvalue <i>boolean_popup</i>
200      * @netui:attribute required="false" rtexprvalue="true" type="boolean"
201      * description="If popup is set to true, the button will open a popup window."
202      */

203     public void setPopup(boolean popup)
204     {
205         _popupSupport = (popup ? new PopupSupport() : null);
206     }
207
208     /**
209      * When true, this button will disable itself before submitting.
210      * @param disableSecondClick when true, this button will disable itself before submitting.
211      * @jsptagref.attributedescription Boolean. If <code>disableSecondClick</code> is set to true,
212      * the button will disable itself before submitting.
213      * @jsptagref.databindable true
214      * @jsptagref.attributesyntaxvalue <i>boolean_disableSecondClick</i>
215      * @netui:attribute required="false" rtexprvalue="true" type="boolean"
216      * description="When true, this button will disable itself before submitting."
217      */

218     public void setDisableSecondClick(boolean disableSecondClick)
219     {
220         _disableSecondClick = disableSecondClick;
221     }
222
223     /**
224      * Adds a URL parameter to the generated hyperlink.
225      * @param name the name of the parameter to be added.
226      * @param value the value of the parameter to be added (a String or String[]).
227      * @param facet
228      */

229     public void addParameter(String JavaDoc name, Object JavaDoc value, String JavaDoc facet)
230             throws JspException JavaDoc
231     {
232         assert(name != null) : "Parameter 'name' must not be null";
233
234         if (_params == null) {
235             _params = new HashMap JavaDoc();
236         }
237         ParamHelper.addParam(_params, name, value);
238     }
239
240     /**
241      * Process the start of the Button.
242      * @throws JspException if a JSP exception has occurred
243      */

244     public int doStartTag()
245             throws JspException JavaDoc
246     {
247         return EVAL_BODY_BUFFERED;
248     }
249
250     /**
251      * Save the associated button label from the body content (if any).
252      * @throws JspException if a JSP exception has occurred
253      */

254     public int doAfterBody()
255             throws JspException JavaDoc
256     {
257         if (bodyContent != null) {
258             if (_value == null) {
259                 String JavaDoc text = bodyContent.getString().trim();
260                 if (text.length() <= 0)
261                     text = null;
262                 _value = text;
263             }
264             bodyContent.clearBody();
265         }
266         return SKIP_BODY;
267     }
268
269     /**
270      * Render the button.
271      * @throws JspException if a JSP exception has occurred
272      */

273     public int doEndTag()
274             throws JspException JavaDoc
275     {
276         String JavaDoc idScript = null;
277
278         HttpServletRequest JavaDoc request = (HttpServletRequest JavaDoc) pageContext.getRequest();
279         HttpServletResponse JavaDoc response = (HttpServletResponse JavaDoc) pageContext.getResponse();
280
281         // Acquire the label value we will be generating
282
if (_value == null)
283             _value = Bundle.getString("Tags_ButtonText", null);
284         _state.value = _value;
285
286         // Generate an HTML element
287
_state.disabled = isDisabled();
288
289         // Add parameters for popup window support.
290
if (_popupSupport != null) {
291             _popupSupport.addParams(this, request);
292         }
293
294         // targetScope implies an extra parameter. If there's no action on this button, get the action from the
295
// nearest form, so we can construct an action url with our extra parameter.
296
if (_targetScope != null && _action == null) {
297             Form parentForm = getNearestForm();
298             if (parentForm != null) {
299                 _action = parentForm.getAction();
300             }
301         }
302
303         if (_action == null && _params != null && _popupSupport == null) {
304             Form parentForm = getNearestForm();
305             if (parentForm != null) {
306                 _action = parentForm.getAction();
307             }
308         }
309
310         if (_action != null) {
311             boolean isAction = PageFlowTagUtils.isAction(request, _action);
312             if (isAction) {
313
314                 // If the action we're submitting to is checking for double-submits, save a token in the session.
315
// This will be written out as a param (below), and will be checked in PageFlowRequestProcessor.
316
String JavaDoc token = PageFlowTagUtils.getToken(request, _action);
317                 if (token != null) {
318                     if (_params == null) {
319                         _params = new HashMap JavaDoc();
320                     }
321                     _params.put(Constants.TOKEN_KEY, token);
322                 }
323
324                 // Add the scope ID parameter if there's one on the tag, or if there's one in the request.
325
if (_targetScope != null) {
326                     if (_params == null) {
327                         _params = new HashMap JavaDoc();
328                     }
329                     _params.put(ScopedServletUtils.SCOPE_ID_PARAM, _targetScope);
330                 }
331
332                 String JavaDoc overrideAction = ACTION_OVERRIDE + _action;
333                 overrideAction = HtmlUtils.addParams(overrideAction, _params, response.getCharacterEncoding());
334                 String JavaDoc buttonOutput = URLRewriterService.getNamePrefix(pageContext.getServletContext(),
335                         pageContext.getRequest(), overrideAction) + overrideAction;
336                 if (buttonOutput.indexOf(";") > -1) {
337                     buttonOutput = buttonOutput.substring(0, buttonOutput.indexOf(";"));
338                 }
339                 _state.name = buttonOutput;
340
341                 // don't write the id attribute
342
Form parentForm = getNearestForm();
343                 idScript = renderNameAndId(request, _state, parentForm);
344             }
345             else {
346                 // set the error because the action is invalid
347
registerTagError(Bundle.getString("Tags_BadAction", _action), null);
348             }
349         }
350         else {
351             Form parentForm = getNearestForm();
352             idScript = renderNameAndId(request, _state, parentForm);
353         }
354
355         boolean buttonDisableAndSubmit = false;
356         boolean buttonDisable = false;
357         
358         // if the user overrides the onclick we will ignore this
359
if (getOnClick() == null) {
360             if (_disableSecondClick) {
361                 Form parentForm = getNearestForm();
362                 String JavaDoc href = getActionUrl(request, response);
363                 String JavaDoc entry;
364                 if (parentForm != null && href != null && (_state.type == null || _state.type == INPUT_SUBMIT)) {
365                     entry = ScriptRequestState.getString("buttonDisableAndSubmitFormAction",
366                             new Object JavaDoc[]{parentForm.getRealFormId(), href});
367                     buttonDisableAndSubmit = true;
368                 }
369                 else {
370                     entry = ScriptRequestState.getString("buttonDisableAction", null);
371                     buttonDisable = true;
372                 }
373                 _state.registerAttribute(AbstractHtmlState.ATTR_JAVASCRIPT, ONCLICK, entry);
374                 if (parentForm != null)
375                     parentForm.insureRealId();
376             }
377             else if (_popupSupport != null) {
378                 String JavaDoc href = getActionUrl(request, response);
379
380                 if (href != null) {
381                     href = response.encodeURL(href);
382                     setOnClick(_popupSupport.getOnClick(request,href));
383                 }
384             }
385         }
386         
387         // report any errors that may have been generated.
388
if (hasErrors())
389             return reportAndExit(EVAL_PAGE);
390
391         WriteRenderAppender writer = new WriteRenderAppender(pageContext);
392         TagRenderingBase br = TagRenderingBase.Factory.getRendering(TagRenderingBase.INPUT_SUBMIT_TAG, request);
393         br.doStartTag(writer, _state);
394         br.doEndTag(writer);
395
396         //Emit javascript if this button needs to sumbit the form or open a popup window
397
if (idScript != null || _popupSupport != null || buttonDisable || buttonDisableAndSubmit) {
398             ScriptRequestState srs = ScriptRequestState.getScriptRequestState(request);
399             InternalStringBuilder script = new InternalStringBuilder(32);
400             StringBuilderRenderAppender scriptWriter = new StringBuilderRenderAppender(script);
401             IScriptReporter sr = getScriptReporter();
402
403             if (buttonDisableAndSubmit)
404                 srs.writeFeature(sr, scriptWriter, CoreScriptFeature.BUTTON_DISABLE_AND_SUBMIT, true, false, null);
405             if (buttonDisable)
406                 srs.writeFeature(sr, scriptWriter, CoreScriptFeature.BUTTON_DISABLE, true, false, null);
407             if (_popupSupport != null)
408                 _popupSupport.writeScript(request, srs, getScriptReporter(), scriptWriter);
409             if (idScript != null)
410                 scriptWriter.append(idScript);
411             write(script.toString());
412         }
413         
414         // Evaluate the remainder of this page
415
localRelease();
416         return EVAL_PAGE;
417     }
418
419     private String JavaDoc getActionUrl(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
420             throws JspException JavaDoc
421     {
422         String JavaDoc href = null;
423
424         if (_action != null) {
425             ServletContext JavaDoc servletContext = pageContext.getServletContext();
426             boolean forXML = TagRenderingBase.Factory.isXHTML(request);
427             try {
428                 href = PageFlowUtils.getRewrittenActionURI(servletContext, request, response, _action, _params, null, forXML);
429             }
430             catch (URISyntaxException JavaDoc e) {
431                 // report the error...
432
logger.error(Bundle.getString("Tags_URISyntaxException"));
433                 String JavaDoc s = Bundle.getString("Tags_Button_URLException",
434                         new Object JavaDoc[]{_action, e.getMessage()});
435                 registerTagError(s, e);
436             }
437         }
438         else {
439             Form parentForm = getNearestForm();
440             if (parentForm != null)
441                 href = HtmlUtils.addParams(parentForm.getActionUrl(), _params, response.getCharacterEncoding());
442         }
443
444         return href;
445     }
446
447     /**
448      * Release any acquired resources.
449      */

450     protected void localRelease()
451     {
452         super.localRelease();
453
454         _state.clear();
455         _action = null;
456         _value = null;
457         _params = null;
458         _targetScope = null;
459         _popupSupport = null;
460         _disableSecondClick = false;
461     }
462
463     /* ==================================================================
464      *
465      * This tag's publically exposed HTML, CSS, and JavaScript attributes
466      *
467      * ==================================================================
468      */

469
470     /**
471      * Sets the accessKey attribute value. This should key value of the
472      * keyboard navigation key. It is recommended not to use the following
473      * values because there are often used by browsers <code>A, C, E, F, G,
474      * H, V, left arrow, and right arrow</code>.
475      * @param accessKey the accessKey value.
476      * @jsptagref.attributedescription The keyboard navigation key for the element.
477      * The following values are not recommended because they
478      * are often used by browsers: <code>A, C, E, F, G,
479      * H, V, left arrow, and right arrow</code>
480      * @jsptagref.databindable false
481      * @jsptagref.attributesyntaxvalue <i>string_accessKey</i>
482      * @netui:attribute required="false" rtexprvalue="true" type="char"
483      * description="The keyboard navigation key for the element.
484      * The following values are not recommended because they
485      * are often used by browsers: A, C, E, F, G,
486      * H, V, left arrow, and right arrow"
487      */

488     public void setAccessKey(char accessKey)
489     {
490         if (accessKey == 0x00)
491             return;
492         _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, ACCESSKEY, Character.toString(accessKey));
493     }
494
495     /**
496      * Sets the alt attribute value.
497      * @param alt the alt value.
498      * @jsptagref.attributedescription The alt attribute of the element.
499      * @jsptagref.databindable Read Only
500      * @jsptagref.attributesyntaxvalue <i>string_alt</i>
501      * @netui:attribute required="false" rtexprvalue="true"
502      * description="The alt attribute of the element."
503      */

504     public void setAlt(String JavaDoc alt)
505     {
506         _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, ALT, alt);
507     }
508
509     /**
510      * Sets the tabIndex of the rendered html tag.
511      * @param tabindex the tab index.
512      * @jsptagref.attributedescription The tabIndex of the rendered HTML tag. This attribute determines the position of the
513      * tag in the sequence of page elements that the user may advance through by pressing the TAB key.
514      * @jsptagref.databindable false
515      * @jsptagref.attributesyntaxvalue <i>string_tabIndex</i>
516      * @netui:attribute required="false" rtexprvalue="true" type="int"
517      * description="The tabIndex of the rendered HTML tag. This attribute determines the position of the
518      * tag in the sequence of page elements that the user may advance through by pressing the TAB key."
519      */

520     public void setTabindex(int tabindex)
521     {
522         _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TABINDEX, Integer.toString(tabindex));
523     }
524
525     public PopupSupport getPopupSupport()
526     {
527         return _popupSupport;
528     }
529 }
530
Popular Tags