View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.shared.renderkit.html;
20  
21  import java.io.IOException;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.Map;
26  
27  import javax.faces.component.UICommand;
28  import javax.faces.component.UIComponent;
29  import javax.faces.component.UIParameter;
30  import javax.faces.component.ValueHolder;
31  import javax.faces.component.behavior.ClientBehavior;
32  import javax.faces.component.behavior.ClientBehaviorContext;
33  import javax.faces.component.behavior.ClientBehaviorHint;
34  import javax.faces.component.behavior.ClientBehaviorHolder;
35  import javax.faces.component.html.HtmlCommandButton;
36  import javax.faces.component.html.HtmlCommandLink;
37  import javax.faces.context.ExternalContext;
38  import javax.faces.context.FacesContext;
39  import javax.faces.context.ResponseWriter;
40  import javax.faces.event.ActionEvent;
41  
42  import org.apache.myfaces.shared.config.MyfacesConfig;
43  import org.apache.myfaces.shared.renderkit.ClientBehaviorEvents;
44  import org.apache.myfaces.shared.renderkit.JSFAttr;
45  import org.apache.myfaces.shared.renderkit.RendererUtils;
46  import org.apache.myfaces.shared.renderkit.html.util.FormInfo;
47  import org.apache.myfaces.shared.renderkit.html.util.JavascriptUtils;
48  import org.apache.myfaces.shared.renderkit.html.util.ResourceUtils;
49  import org.apache.myfaces.shared.util._ComponentUtils;
50  
51  /**
52   * @author Manfred Geiler (latest modification by $Author: lu4242 $)
53   * @author Thomas Spiegl
54   * @author Anton Koinov
55   * @version $Revision: 1533195 $ $Date: 2013-10-17 13:21:06 -0500 (Thu, 17 Oct 2013) $
56   */
57  public class HtmlButtonRendererBase
58      extends HtmlRenderer
59  {
60      private static final String IMAGE_BUTTON_SUFFIX_X = ".x";
61      private static final String IMAGE_BUTTON_SUFFIX_Y = ".y";
62  
63      public static final String ACTION_FOR_LIST = "org.apache.myfaces.ActionForList";
64  
65      public void decode(FacesContext facesContext, UIComponent uiComponent)
66      {
67          org.apache.myfaces.shared.renderkit.RendererUtils.checkParamValidity(
68                  facesContext, uiComponent, UICommand.class);
69  
70          //super.decode must not be called, because value is handled here
71          boolean disabled = isDisabled(facesContext, uiComponent);
72          if (!isReset(uiComponent) && isSubmitted(facesContext, uiComponent) &&
73              !disabled)
74          {
75              uiComponent.queueEvent(new ActionEvent(uiComponent));
76  
77              org.apache.myfaces.shared.renderkit.RendererUtils.initPartialValidationAndModelUpdate(
78                      uiComponent, facesContext);
79          }
80          
81          if (uiComponent instanceof ClientBehaviorHolder &&
82                  !disabled)
83          {
84              HtmlRendererUtils.decodeClientBehaviors(facesContext, uiComponent);
85          }
86      }
87  
88      private static boolean isReset(UIComponent uiComponent)
89      {
90          return "reset".equals((String) uiComponent.getAttributes().get(HTML.TYPE_ATTR));
91      }
92      
93      private static boolean isButton(UIComponent uiComponent)
94      {
95          return "button".equals((String) uiComponent.getAttributes().get(HTML.TYPE_ATTR));
96      }
97  
98      private static boolean isSubmitted(FacesContext facesContext, UIComponent uiComponent)
99      {
100         String clientId = uiComponent.getClientId(facesContext);
101         Map paramMap = facesContext.getExternalContext().getRequestParameterMap();
102         FormInfo formInfo = _ComponentUtils.findNestingForm(uiComponent, facesContext);
103         String hiddenLink = null;
104          
105         if (formInfo != null)
106         {
107             hiddenLink = (String) facesContext.getExternalContext().getRequestParameterMap().get(
108                 HtmlRendererUtils.getHiddenCommandLinkFieldName(formInfo, facesContext));
109         }
110         return paramMap.containsKey(clientId) || paramMap.containsKey(clientId + IMAGE_BUTTON_SUFFIX_X) 
111             || paramMap.containsKey(clientId + IMAGE_BUTTON_SUFFIX_Y)
112             || (hiddenLink != null && hiddenLink.equals (clientId))
113             || HtmlRendererUtils.isPartialOrBehaviorSubmit(facesContext, clientId);
114     }
115 
116     public void encodeEnd(FacesContext facesContext, UIComponent uiComponent)
117             throws IOException
118     {
119         org.apache.myfaces.shared.renderkit.RendererUtils.checkParamValidity(
120                 facesContext, uiComponent, UICommand.class);
121 
122         String clientId = uiComponent.getClientId(facesContext);
123 
124         ResponseWriter writer = facesContext.getResponseWriter();
125         
126         // commandButton does not need to be nested in a form since JSF 2.0
127         FormInfo formInfo = findNestingForm(uiComponent, facesContext);
128 
129         boolean reset = isReset(uiComponent);
130         boolean button = isButton(uiComponent);
131 
132         Map<String, List<ClientBehavior>> behaviors = null;
133         if (uiComponent instanceof ClientBehaviorHolder)
134         {
135             behaviors = ((ClientBehaviorHolder) uiComponent).getClientBehaviors();
136             if (!behaviors.isEmpty())
137             {
138                 ResourceUtils.renderDefaultJsfJsInlineIfNecessary(facesContext, writer);
139             }
140         }
141         
142         // If we are nested in a form, and we have javascript enabled, and autoscroll is enabled, 
143         // we should write the form submit script
144         // (define oamSetHiddenInput, oamClearHiddenInput, oamSubmitForm)
145         // because oamSetHiddenInput is called on onclick function
146         List<UIComponent> childrenList = null;
147         if (getChildCount(uiComponent) > 0)
148         {
149             childrenList = getChildren(uiComponent);
150         }
151         else
152         {
153            childrenList = Collections.emptyList();
154         }
155         List<UIParameter> validParams = HtmlRendererUtils.getValidUIParameterChildren(
156                 facesContext, childrenList, false, false);
157         
158         boolean javascriptAllowed = JavascriptUtils.isJavascriptAllowed(facesContext.getExternalContext());
159         
160         if (formInfo != null && javascriptAllowed
161                 && (MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).isAutoScroll() ||
162                         (validParams != null && !validParams.isEmpty() )))
163         {        
164             HtmlRendererUtils.renderFormSubmitScript(facesContext);
165         }
166         
167         String commandOnclick = (String)uiComponent.getAttributes().get(HTML.ONCLICK_ATTR);
168         
169         if (commandOnclick != null && (validParams != null && !validParams.isEmpty() ) )
170         {
171             ResourceUtils.renderDefaultJsfJsInlineIfNecessary(facesContext, writer);
172         }
173 
174         writer.startElement(HTML.INPUT_ELEM, uiComponent);
175 
176         writer.writeAttribute(HTML.ID_ATTR, clientId, org.apache.myfaces.shared.renderkit.JSFAttr.ID_ATTR);
177         writer.writeAttribute(HTML.NAME_ATTR, clientId, JSFAttr.ID_ATTR);
178 
179         ExternalContext externalContext = facesContext.getExternalContext();
180 
181         String image = RendererUtils.getIconSrc(facesContext, uiComponent, JSFAttr.IMAGE_ATTR);
182         if (image != null)
183         {
184             writer.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_IMAGE, 
185                     org.apache.myfaces.shared.renderkit.JSFAttr.TYPE_ATTR);
186             writer.writeURIAttribute(HTML.SRC_ATTR, image, org.apache.myfaces.shared.renderkit.JSFAttr.IMAGE_ATTR);
187         }
188         else
189         {
190             String type = getType(uiComponent);
191 
192             if (type == null || (!reset && !button))
193             {
194                 type = HTML.INPUT_TYPE_SUBMIT;
195             }
196             writer.writeAttribute(HTML.TYPE_ATTR, type, org.apache.myfaces.shared.renderkit.JSFAttr.TYPE_ATTR);
197             Object value = getValue(uiComponent);
198             if (value != null)
199             {
200                 writer.writeAttribute(org.apache.myfaces.shared.renderkit.html.HTML.VALUE_ATTR, value, 
201                         org.apache.myfaces.shared.renderkit.JSFAttr.VALUE_ATTR);
202             }
203         }
204         
205         if (javascriptAllowed &&
206             (HtmlRendererUtils.hasClientBehavior(ClientBehaviorEvents.CLICK, behaviors, facesContext) ||
207              HtmlRendererUtils.hasClientBehavior(ClientBehaviorEvents.ACTION, behaviors, facesContext)))
208         {
209             if (!reset && !button)
210             {
211                 String onClick = buildBehaviorizedOnClick(
212                         uiComponent, behaviors, facesContext, writer, formInfo, validParams);
213                 if (onClick.length() != 0)
214                 {
215                     writer.writeAttribute(HTML.ONCLICK_ATTR, onClick.toString(), null);
216                 }
217             }
218             else
219             {
220                 Collection<ClientBehaviorContext.Parameter> paramList = 
221                     HtmlRendererUtils.getClientBehaviorContextParameters(
222                         HtmlRendererUtils.mapAttachedParamsToStringValues(facesContext, uiComponent));
223                     
224                 String onClick = HtmlRendererUtils.buildBehaviorChain(facesContext, uiComponent,
225                         ClientBehaviorEvents.CLICK, paramList, ClientBehaviorEvents.ACTION, paramList, behaviors,
226                         commandOnclick , null);
227                 if (onClick.length() != 0)
228                 {
229                     writer.writeAttribute(HTML.ONCLICK_ATTR, onClick.toString(), null);
230                 }
231             }
232             
233             Map<String, Object> attributes = uiComponent.getAttributes(); 
234             
235             HtmlRendererUtils.buildBehaviorChain(
236                     facesContext, uiComponent, ClientBehaviorEvents.DBLCLICK, null, behaviors,   
237                         (String) attributes.get(HTML.ONDBLCLICK_ATTR), "");
238         }
239         else if (javascriptAllowed)
240         {
241             //fallback into the pre 2.0 code to keep backwards compatibility with libraries which rely on internals
242             if (!reset && !button)
243             {
244                 StringBuilder onClick = buildOnClick(uiComponent, facesContext, writer, validParams);
245                 if (onClick.length() != 0)
246                 {
247                     writer.writeAttribute(HTML.ONCLICK_ATTR, onClick.toString(), null);
248                 }
249             }
250             else
251             {
252                 HtmlRendererUtils.renderHTMLStringAttribute(writer, uiComponent, HTML.ONCLICK_ATTR, HTML.ONCLICK_ATTR);
253             }
254         }
255         
256         //if (javascriptAllowed)
257         //{
258             if (isCommonPropertiesOptimizationEnabled(facesContext))
259             {
260                 CommonPropertyUtils.renderButtonPassthroughPropertiesWithoutDisabledAndEvents(writer, 
261                         CommonPropertyUtils.getCommonPropertiesMarked(uiComponent), uiComponent);
262             }
263             else
264             {
265                 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent,
266                                                        HTML.BUTTON_PASSTHROUGH_ATTRIBUTES_WITHOUT_DISABLED_AND_EVENTS);
267             }
268         //}
269 
270         if (behaviors != null && !behaviors.isEmpty())
271         {
272             HtmlRendererUtils.renderBehaviorizedEventHandlersWithoutOnclick(
273                     facesContext, writer, uiComponent, behaviors);
274             HtmlRendererUtils.renderBehaviorizedFieldEventHandlers(facesContext, writer, uiComponent, behaviors);
275         }
276         else
277         {
278             if (isCommonPropertiesOptimizationEnabled(facesContext))
279             {
280                 long commonPropertiesMarked = CommonPropertyUtils.getCommonPropertiesMarked(uiComponent);
281                 CommonPropertyUtils.renderEventPropertiesWithoutOnclick(writer, commonPropertiesMarked, uiComponent);
282                 CommonPropertyUtils.renderCommonFieldEventProperties(writer, commonPropertiesMarked, uiComponent);
283             }
284             else
285             {
286                 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent,
287                         HTML.EVENT_HANDLER_ATTRIBUTES_WITHOUT_ONCLICK);
288                 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent,
289                         HTML.COMMON_FIELD_EVENT_ATTRIBUTES);
290             }
291         }
292 
293         if (isDisabled(facesContext, uiComponent))
294         {
295             writer.writeAttribute(HTML.DISABLED_ATTR, Boolean.TRUE, 
296                     org.apache.myfaces.shared.renderkit.JSFAttr.DISABLED_ATTR);
297         }
298         
299         if (isReadonly(facesContext, uiComponent))
300         {
301             writer.writeAttribute(HTML.READONLY_ATTR, Boolean.TRUE, 
302                     org.apache.myfaces.shared.renderkit.JSFAttr.READONLY_ATTR);
303         }
304 
305         writer.endElement(HTML.INPUT_ELEM);
306         
307         if (formInfo != null)
308         {
309             HtmlFormRendererBase.renderScrollHiddenInputIfNecessary(
310                     formInfo.getForm(), facesContext, writer);
311         }
312         
313         // render the UIParameter children of the commandButton (since 2.0)
314         /*
315         List<UIParameter> validParams = HtmlRendererUtils.getValidUIParameterChildren(
316                 facesContext, uiComponent.getChildren(), false, false);
317         for (UIParameter param : validParams)
318         {
319             HtmlInputHidden parameterComponent = new HtmlInputHidden();
320             parameterComponent.setId(param.getName());
321             parameterComponent.setValue(param.getValue());
322             parameterComponent.encodeAll(facesContext);
323         }*/
324     }
325 
326     private boolean hasSubmittingBehavior(Map<String, List<ClientBehavior>> clientBehaviors, String eventName)
327     {
328         List<ClientBehavior> eventBehaviors = clientBehaviors.get(eventName);
329         if (eventBehaviors != null && !eventBehaviors.isEmpty())
330         {
331             for (ClientBehavior behavior : eventBehaviors)
332             {
333                 if (behavior.getHints().contains(ClientBehaviorHint.SUBMITTING))
334                 {
335                     return true;
336                 }
337             }
338         }
339         return false;
340     }
341     
342     protected String buildBehaviorizedOnClick(UIComponent uiComponent, Map<String, List<ClientBehavior>> behaviors, 
343                                               FacesContext facesContext, ResponseWriter writer, 
344                                               FormInfo nestedFormInfo, List<UIParameter> validParams)
345         throws IOException
346     {
347         //we can omit autoscroll here for now maybe we should check if it is an ajax 
348         //behavior and omit it only in this case
349         StringBuilder userOnClick = new StringBuilder();
350         //user onclick part 
351         String commandOnClick = (String) uiComponent.getAttributes().get(HTML.ONCLICK_ATTR);
352 
353         if (commandOnClick != null)
354         {
355             userOnClick.append(commandOnClick);
356             userOnClick.append(';');
357         }
358 
359         StringBuilder rendererOnClick = new StringBuilder();
360 
361         if (nestedFormInfo != null) 
362         {
363             // There is no clean way to detect if a "submit" behavior has been added to the component, 
364             // so to keep things simple, if the button is submit type, it is responsibility of the 
365             // developer to add a client behavior that submit the form, for example using a f:ajax tag.
366             // Otherwise, there will be a situation where a full submit could be trigger after an ajax
367             // operation. Note we still need to append two scripts if necessary: autoscroll and clear
368             // hidden fields, because this code is called for a submit button.
369             //if (behaviors.isEmpty() && validParams != null && !validParams.isEmpty() )
370             //{
371             //    rendererOnClick.append(buildServerOnclick(facesContext, uiComponent, 
372             //            uiComponent.getClientId(facesContext), nestedFormInfo, validParams));
373             //}
374             //else
375             //{
376                 String formName = nestedFormInfo.getFormName();
377                 if (JavascriptUtils.isRenderClearJavascriptOnButton(facesContext.getExternalContext()))
378                 {
379                     //call the script to clear the form (clearFormHiddenParams_<formName>) method
380                     HtmlRendererUtils.appendClearHiddenCommandFormParamsFunctionCall(rendererOnClick, formName);
381                 }
382         
383                 if (MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).isAutoScroll())
384                 {
385                     HtmlRendererUtils.appendAutoScrollAssignment(rendererOnClick, formName);
386                 }
387             //}
388         }
389 
390         //according to the specification in jsf.util.chain jdocs and the spec document we have to use
391         //jsf.util.chain to chain the functions and
392         Collection<ClientBehaviorContext.Parameter> paramList = HtmlRendererUtils.getClientBehaviorContextParameters(
393                 HtmlRendererUtils.mapAttachedParamsToStringValues(facesContext, uiComponent));
394         
395         return HtmlRendererUtils.buildBehaviorChain(facesContext, uiComponent,
396                 ClientBehaviorEvents.CLICK, paramList, ClientBehaviorEvents.ACTION, paramList, behaviors,
397                 userOnClick.toString() , rendererOnClick.toString());
398     }
399     
400     protected String buildServerOnclick(FacesContext facesContext, UIComponent component, 
401             String clientId, FormInfo formInfo, List<UIParameter> validParams) throws IOException
402     {
403         UIComponent nestingForm = formInfo.getForm();
404         String formName = formInfo.getFormName();
405 
406         StringBuilder onClick = new StringBuilder();
407 
408         if (RendererUtils.isAdfOrTrinidadForm(formInfo.getForm()))
409         {
410             onClick.append("submitForm('");
411             onClick.append(formInfo.getForm().getClientId(facesContext));
412             onClick.append("',1,{source:'");
413             onClick.append(component.getClientId(facesContext));
414             onClick.append("'});return false;");
415         }
416         else
417         {
418             StringBuilder params = addChildParameters(facesContext, component, nestingForm, validParams);
419 
420             String target = getTarget(component);
421 
422             if (MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).isRenderFormSubmitScriptInline())
423             {
424                 onClick.append("return ").
425                     append(HtmlRendererUtils.SUBMIT_FORM_FN_NAME).append("('").
426                     append(formName).append("','").
427                     append(component.getClientId(facesContext)).append("'");                    
428             }
429             else
430             {
431                 onClick.append("return ").
432                     append(HtmlRendererUtils.SUBMIT_FORM_FN_NAME_JSF2).append("('").
433                     append(formName).append("','").
434                     append(component.getClientId(facesContext)).append("'");
435             }
436 
437             if (params.length() > 2 || target != null)
438             {
439                 onClick.append(",").
440                     append(target == null ? "null" : ("'" + target + "'")).append(",").
441                     append(params);
442             }
443             onClick.append(");");
444 
445             //Not necessary since we are using oamSetHiddenInput to create input hidden fields
446             //render hidden field - todo: in here for backwards compatibility
447             //String hiddenFieldName = HtmlRendererUtils.getHiddenCommandLinkFieldName(formInfo);
448             //addHiddenCommandParameter(facesContext, nestingForm, hiddenFieldName);
449 
450         }
451         return onClick.toString();
452     }
453     
454     private StringBuilder addChildParameters(FacesContext context, UIComponent component, 
455             UIComponent nestingForm, List<UIParameter> validParams)
456     {
457         //add child parameters
458         StringBuilder params = new StringBuilder();
459         params.append("[");
460         
461         for (UIParameter param : validParams) 
462         {
463             String name = param.getName();
464 
465             //Not necessary, since we are using oamSetHiddenInput to create hidden fields
466             if (MyfacesConfig.getCurrentInstance(context.getExternalContext()).isRenderHiddenFieldsForLinkParams())
467             {
468                 addHiddenCommandParameter(context, nestingForm, name);
469             }
470 
471             Object value = param.getValue();
472 
473             //UIParameter is no ValueHolder, so no conversion possible - calling .toString on value....
474             // MYFACES-1832 bad charset encoding for f:param
475             // if HTMLEncoder.encode is called, then
476             // when is called on writer.writeAttribute, encode method
477             // is called again so we have a duplicated encode call.
478             // MYFACES-2726 All '\' and "'" chars must be escaped 
479             // because there will be inside "'" javascript quotes, 
480             // otherwise the value will not correctly restored when
481             // the command is post.
482             //String strParamValue = value != null ? value.toString() : "";
483             String strParamValue = "";
484             if (value != null)
485             {
486                 strParamValue = value.toString();
487                 StringBuilder buff = null;
488                 for (int i = 0; i < strParamValue.length(); i++)
489                 {
490                     char c = strParamValue.charAt(i); 
491                     if (c == '\'' || c == '\\')
492                     {
493                         if (buff == null)
494                         {
495                             buff = new StringBuilder();
496                             buff.append(strParamValue.substring(0,i));
497                         }
498                         buff.append('\\');
499                         buff.append(c);
500                     }
501                     else if (buff != null)
502                     {
503                         buff.append(c);
504                     }
505                 }
506                 if (buff != null)
507                 {
508                     strParamValue = buff.toString();
509                 }
510             }
511 
512             if (params.length() > 1) 
513             {
514                 params.append(",");
515             }
516 
517             params.append("['");
518             params.append(name);
519             params.append("','");
520             params.append(strParamValue);
521             params.append("']");
522         }
523         params.append("]");
524         return params;
525     }
526 
527     private String getTarget(UIComponent component)
528     {
529         // for performance reason: double check for the target attribute
530         String target;
531         if (component instanceof HtmlCommandLink)
532         {
533             target = ((HtmlCommandLink) component).getTarget();
534         }
535         else
536         {
537             target = (String) component.getAttributes().get(HTML.TARGET_ATTR);
538         }
539         return target;
540     }
541 
542     protected StringBuilder buildOnClick(UIComponent uiComponent, FacesContext facesContext,
543                                         ResponseWriter writer, List<UIParameter> validParams)
544         throws IOException
545     {
546         /* DUMMY STUFF
547         //Find form
548         UIComponent parent = uiComponent.getParent();
549         while (parent != null && !(parent instanceof UIForm))
550         {
551             parent = parent.getParent();
552         }
553 
554         UIForm nestingForm = null;
555         String formName;
556 
557         if (parent != null)
558         {
559             //link is nested inside a form
560             nestingForm = (UIForm)parent;
561             formName = nestingForm.getClientId(facesContext);
562 
563         }
564         else
565         {
566             //not nested in form, we must add a dummy form at the end of the document
567             formName = DummyFormUtils.DUMMY_FORM_NAME;
568             //dummyFormResponseWriter = DummyFormUtils.getDummyFormResponseWriter(facesContext);
569             //dummyFormResponseWriter.setWriteDummyForm(true);
570             DummyFormUtils.setWriteDummyForm(facesContext, true);
571         }
572         */
573         StringBuilder onClick = new StringBuilder();
574         String commandOnClick = (String) uiComponent.getAttributes().get(HTML.ONCLICK_ATTR);
575 
576         if (commandOnClick != null)
577         {
578             onClick.append("var cf = function(){");
579             onClick.append(commandOnClick);
580             onClick.append('}');
581             onClick.append(';');
582             onClick.append("var oamSF = function(){");
583         }
584         
585         FormInfo nestedFormInfo = findNestingForm(uiComponent, facesContext);
586         
587         if (nestedFormInfo != null)
588         {
589             String formName = nestedFormInfo.getFormName();
590             
591             if (validParams != null && !validParams.isEmpty() )
592             {
593                 StringBuilder params = addChildParameters(
594                         facesContext, uiComponent, nestedFormInfo.getForm(), validParams);
595 
596                 String target = getTarget(uiComponent);
597 
598                 if (MyfacesConfig.getCurrentInstance(
599                         facesContext.getExternalContext()).isRenderFormSubmitScriptInline())
600                 {
601                     onClick.append("return ").
602                         append(HtmlRendererUtils.SUBMIT_FORM_FN_NAME).append("('").
603                         append(formName).append("','").
604                         append(uiComponent.getClientId(facesContext)).append("'");                    
605                 }
606                 else
607                 {
608                     onClick.append("return ").
609                         append(HtmlRendererUtils.SUBMIT_FORM_FN_NAME_JSF2).append("('").
610                         append(formName).append("','").
611                         append(uiComponent.getClientId(facesContext)).append("'");
612                 }
613 
614                 if (params.length() > 2 || target != null)
615                 {
616                     onClick.append(",").
617                         append(target == null ? "null" : ("'" + target + "'")).append(",").
618                         append(params);
619                 }
620                 onClick.append(");");
621 
622                 //Not necessary since we are using oamSetHiddenInput to create input hidden fields
623                 //render hidden field - todo: in here for backwards compatibility
624                 if (MyfacesConfig.getCurrentInstance(
625                         facesContext.getExternalContext()).isRenderHiddenFieldsForLinkParams())
626                 {
627                     String hiddenFieldName = HtmlRendererUtils.getHiddenCommandLinkFieldName(
628                             nestedFormInfo, facesContext);
629                     addHiddenCommandParameter(facesContext, nestedFormInfo.getForm(), hiddenFieldName);
630                 }
631             }
632             else
633             {
634         
635                 if (JavascriptUtils.isRenderClearJavascriptOnButton(facesContext.getExternalContext()) ||
636                         MyfacesConfig.getCurrentInstance(
637                                 facesContext.getExternalContext()).isRenderHiddenFieldsForLinkParams() )
638                 {
639                     //call the script to clear the form (clearFormHiddenParams_<formName>) method
640                     HtmlRendererUtils.appendClearHiddenCommandFormParamsFunctionCall(onClick, formName);
641                 }
642         
643                 if (MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).isAutoScroll())
644                 {
645                     HtmlRendererUtils.appendAutoScrollAssignment(onClick, formName);
646                 }
647             }
648         }
649         
650         if (commandOnClick != null)
651         {
652             onClick.append('}');
653             onClick.append(';');
654             onClick.append("return (cf.apply(this, [])==false)? false : oamSF.apply(this, []); ");
655         }  
656 
657         //The hidden field has only sense if isRenderClearJavascriptOnButton is
658         //set to true. In other case, this hidden field should not be rendered.
659         //if (JavascriptUtils.isRenderClearJavascriptOnButton(facesContext.getExternalContext()))
660         //{
661             //add hidden field for the case there is no commandLink in the form
662             //String hiddenFieldName = HtmlRendererUtils.getHiddenCommandLinkFieldName(formInfo);
663             //addHiddenCommandParameter(facesContext, nestingForm, hiddenFieldName);
664         //}
665 
666         return onClick;
667     }
668 
669     protected void addHiddenCommandParameter(FacesContext facesContext, 
670             UIComponent nestingForm, String hiddenFieldName)
671     {
672         if (nestingForm != null)
673         {
674             HtmlFormRendererBase.addHiddenCommandParameter(facesContext, nestingForm, hiddenFieldName);
675         }
676     }
677 
678     /**
679      * find nesting form<br />
680      * need to be overrideable to deal with dummyForm stuff in tomahawk.
681      */
682     protected FormInfo findNestingForm(UIComponent uiComponent, FacesContext facesContext)
683     {
684         return RendererUtils.findNestingForm(uiComponent, facesContext);
685     }
686 
687     protected boolean isDisabled(FacesContext facesContext, UIComponent uiComponent)
688     {
689         //TODO: overwrite in extended HtmlButtonRenderer and check for enabledOnUserRole
690         if (uiComponent instanceof HtmlCommandButton)
691         {
692             return ((HtmlCommandButton)uiComponent).isDisabled();
693         }
694 
695         return org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanAttribute(
696                 uiComponent, HTML.DISABLED_ATTR, false);
697         
698     }
699 
700     protected boolean isReadonly(FacesContext facesContext, UIComponent uiComponent)
701     {
702         if (uiComponent instanceof HtmlCommandButton)
703         {
704             return ((HtmlCommandButton)uiComponent).isReadonly();
705         }
706         return org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanAttribute(
707                 uiComponent, HTML.READONLY_ATTR, false);
708     }
709 
710     private String getImage(UIComponent uiComponent)
711     {
712         if (uiComponent instanceof HtmlCommandButton)
713         {
714             return ((HtmlCommandButton)uiComponent).getImage();
715         }
716         return (String)uiComponent.getAttributes().get(JSFAttr.IMAGE_ATTR);
717     }
718 
719     private String getType(UIComponent uiComponent)
720     {
721         if (uiComponent instanceof HtmlCommandButton)
722         {
723             return ((HtmlCommandButton)uiComponent).getType();
724         }
725         return (String)uiComponent.getAttributes().get(org.apache.myfaces.shared.renderkit.JSFAttr.TYPE_ATTR);
726     }
727 
728     private Object getValue(UIComponent uiComponent)
729     {
730         if (uiComponent instanceof ValueHolder)
731         {
732             return ((ValueHolder)uiComponent).getValue();
733         }
734         return uiComponent.getAttributes().get(JSFAttr.VALUE_ATTR);
735     }
736 }