1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
53
54
55
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
71 boolean disabled = isDisabled(facesContext, uiComponent);
72
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
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
148
149
150
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
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
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
319
320
321
322
323
324
325
326
327
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
353
354 StringBuilder userOnClick = new StringBuilder();
355
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
369
370
371
372
373
374
375
376
377
378
379
380
381 String formName = nestedFormInfo.getFormName();
382 if (JavascriptUtils.isRenderClearJavascriptOnButton(facesContext.getExternalContext()))
383 {
384
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
396
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
451
452
453
454
455 }
456 return onClick.toString();
457 }
458
459 private StringBuilder addChildParameters(FacesContext context, UIComponent component,
460 UIComponent nestingForm, List<UIParameter> validParams)
461 {
462
463 StringBuilder params = new StringBuilder();
464 params.append("[");
465
466 for (UIParameter param : validParams)
467 {
468 String name = param.getName();
469
470
471 if (MyfacesConfig.getCurrentInstance(context.getExternalContext()).isRenderHiddenFieldsForLinkParams())
472 {
473 addHiddenCommandParameter(context, nestingForm, name);
474 }
475
476 Object value = param.getValue();
477
478
479
480
481
482
483
484
485
486
487
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
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
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
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
628
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
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
663
664
665
666
667
668
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
685
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
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 }