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