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