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 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
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
141
142
143
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
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
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
312
313
314
315
316
317
318
319
320
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
346
347 StringBuilder userOnClick = new StringBuilder();
348
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
362
363
364
365
366
367
368
369
370
371
372
373
374 String formName = nestedFormInfo.getFormName();
375 if (JavascriptUtils.isRenderClearJavascriptOnButton(facesContext.getExternalContext()))
376 {
377
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
389
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
444
445
446
447
448 }
449 return onClick.toString();
450 }
451
452 private StringBuilder addChildParameters(FacesContext context, UIComponent component,
453 UIComponent nestingForm, List<UIParameter> validParams)
454 {
455
456 StringBuilder params = new StringBuilder();
457 params.append("[");
458
459 for (UIParameter param : validParams)
460 {
461 String name = param.getName();
462
463
464 if (MyfacesConfig.getCurrentInstance(context.getExternalContext()).isRenderHiddenFieldsForLinkParams())
465 {
466 addHiddenCommandParameter(context, nestingForm, name);
467 }
468
469 Object value = param.getValue();
470
471
472
473
474
475
476
477
478
479
480
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
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
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
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
621
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
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
655
656
657
658
659
660
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
677
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
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 }