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.ClientBehaviorHolder;
34 import javax.faces.component.html.HtmlCommandButton;
35 import javax.faces.component.html.HtmlCommandLink;
36 import javax.faces.context.FacesContext;
37 import javax.faces.context.ResponseWriter;
38 import javax.faces.event.ActionEvent;
39
40 import org.apache.myfaces.shared.config.MyfacesConfig;
41 import org.apache.myfaces.shared.renderkit.ClientBehaviorEvents;
42 import org.apache.myfaces.shared.renderkit.JSFAttr;
43 import org.apache.myfaces.shared.renderkit.RendererUtils;
44 import org.apache.myfaces.shared.renderkit.html.util.FormInfo;
45 import org.apache.myfaces.shared.renderkit.html.util.JavascriptUtils;
46 import org.apache.myfaces.shared.renderkit.html.util.ResourceUtils;
47 import org.apache.myfaces.shared.util._ComponentUtils;
48
49 public class HtmlButtonRendererBase
50 extends HtmlRenderer
51 {
52 private static final String IMAGE_BUTTON_SUFFIX_X = ".x";
53 private static final String IMAGE_BUTTON_SUFFIX_Y = ".y";
54
55 public static final String ACTION_FOR_LIST = "org.apache.myfaces.ActionForList";
56
57 public void decode(FacesContext facesContext, UIComponent uiComponent)
58 {
59 org.apache.myfaces.shared.renderkit.RendererUtils.checkParamValidity(
60 facesContext, uiComponent, UICommand.class);
61
62
63 boolean disabled = isDisabled(facesContext, uiComponent);
64
65 boolean activateActionEvent = !isReset(uiComponent) && isSubmitted(facesContext, uiComponent) &&
66 !disabled;
67 if (activateActionEvent)
68 {
69 org.apache.myfaces.shared.renderkit.RendererUtils.initPartialValidationAndModelUpdate(
70 uiComponent, facesContext);
71 }
72
73 if (uiComponent instanceof ClientBehaviorHolder &&
74 !disabled)
75 {
76 HtmlRendererUtils.decodeClientBehaviors(facesContext, uiComponent);
77 }
78
79 if (activateActionEvent)
80 {
81 uiComponent.queueEvent(new ActionEvent(uiComponent));
82 }
83 }
84
85 private static boolean isReset(UIComponent uiComponent)
86 {
87 return "reset".equals((String) uiComponent.getAttributes().get(HTML.TYPE_ATTR));
88 }
89
90 private static boolean isButton(UIComponent uiComponent)
91 {
92 return "button".equals((String) uiComponent.getAttributes().get(HTML.TYPE_ATTR));
93 }
94
95 private static boolean isSubmitted(FacesContext facesContext, UIComponent uiComponent)
96 {
97 String clientId = uiComponent.getClientId(facesContext);
98 Map paramMap = facesContext.getExternalContext().getRequestParameterMap();
99 FormInfo formInfo = _ComponentUtils.findNestingForm(uiComponent, facesContext);
100 String hiddenLink = null;
101
102 if (formInfo != null)
103 {
104 hiddenLink = (String) facesContext.getExternalContext().getRequestParameterMap().get(
105 HtmlRendererUtils.getHiddenCommandLinkFieldName(formInfo, facesContext));
106 }
107 return paramMap.containsKey(clientId) || paramMap.containsKey(clientId + IMAGE_BUTTON_SUFFIX_X)
108 || paramMap.containsKey(clientId + IMAGE_BUTTON_SUFFIX_Y)
109 || (hiddenLink != null && hiddenLink.equals (clientId))
110 || HtmlRendererUtils.isPartialOrBehaviorSubmit(facesContext, clientId);
111 }
112
113 @Override
114 public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException
115 {
116 org.apache.myfaces.shared.renderkit.RendererUtils.checkParamValidity(
117 facesContext, uiComponent, UICommand.class);
118
119 String clientId = uiComponent.getClientId(facesContext);
120
121 ResponseWriter writer = facesContext.getResponseWriter();
122
123
124 FormInfo formInfo = findNestingForm(uiComponent, facesContext);
125
126 boolean reset = isReset(uiComponent);
127 boolean button = isButton(uiComponent);
128
129 Map<String, List<ClientBehavior>> behaviors = null;
130 if (uiComponent instanceof ClientBehaviorHolder)
131 {
132 behaviors = ((ClientBehaviorHolder) uiComponent).getClientBehaviors();
133 if (!behaviors.isEmpty())
134 {
135 ResourceUtils.renderDefaultJsfJsInlineIfNecessary(facesContext, writer);
136 }
137 }
138
139
140
141
142
143 List<UIComponent> childrenList = null;
144 if (getChildCount(uiComponent) > 0)
145 {
146 childrenList = getChildren(uiComponent);
147 }
148 else
149 {
150 childrenList = Collections.emptyList();
151 }
152 List<UIParameter> validParams = HtmlRendererUtils.getValidUIParameterChildren(
153 facesContext, childrenList, false, false);
154
155 if (formInfo != null
156 && (MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).isAutoScroll() ||
157 (validParams != null && !validParams.isEmpty() )))
158 {
159 HtmlRendererUtils.renderFormSubmitScript(facesContext);
160 }
161
162 String commandOnclick = (String)uiComponent.getAttributes().get(HTML.ONCLICK_ATTR);
163
164 if (commandOnclick != null && (validParams != null && !validParams.isEmpty() ) )
165 {
166 ResourceUtils.renderDefaultJsfJsInlineIfNecessary(facesContext, writer);
167 }
168
169 writer.startElement(HTML.INPUT_ELEM, uiComponent);
170
171 writer.writeAttribute(HTML.ID_ATTR, clientId, org.apache.myfaces.shared.renderkit.JSFAttr.ID_ATTR);
172 writer.writeAttribute(HTML.NAME_ATTR, clientId, JSFAttr.ID_ATTR);
173
174 String image = RendererUtils.getIconSrc(facesContext, uiComponent, JSFAttr.IMAGE_ATTR);
175 if (image != null)
176 {
177 writer.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_IMAGE,
178 org.apache.myfaces.shared.renderkit.JSFAttr.TYPE_ATTR);
179 writer.writeURIAttribute(HTML.SRC_ATTR, image, org.apache.myfaces.shared.renderkit.JSFAttr.IMAGE_ATTR);
180 }
181 else
182 {
183 String type = getType(uiComponent);
184
185 if (type == null || (!reset && !button))
186 {
187 type = HTML.INPUT_TYPE_SUBMIT;
188 }
189 writer.writeAttribute(HTML.TYPE_ATTR, type, org.apache.myfaces.shared.renderkit.JSFAttr.TYPE_ATTR);
190 Object value = getValue(uiComponent);
191 if (value != null)
192 {
193 writer.writeAttribute(org.apache.myfaces.shared.renderkit.html.HTML.VALUE_ATTR, value,
194 org.apache.myfaces.shared.renderkit.JSFAttr.VALUE_ATTR);
195 }
196 }
197
198 if ((HtmlRendererUtils.hasClientBehavior(ClientBehaviorEvents.CLICK, behaviors, facesContext) ||
199 HtmlRendererUtils.hasClientBehavior(ClientBehaviorEvents.ACTION, behaviors, facesContext)))
200 {
201 if (!reset && !button)
202 {
203 String onClick = buildBehaviorizedOnClick(
204 uiComponent, behaviors, facesContext, writer, formInfo, validParams);
205 if (onClick.length() != 0)
206 {
207 writer.writeAttribute(HTML.ONCLICK_ATTR, onClick, null);
208 }
209 }
210 else
211 {
212 Collection<ClientBehaviorContext.Parameter> paramList =
213 HtmlRendererUtils.getClientBehaviorContextParameters(
214 HtmlRendererUtils.mapAttachedParamsToStringValues(facesContext, uiComponent));
215
216 String onClick = HtmlRendererUtils.buildBehaviorChain(facesContext, uiComponent,
217 ClientBehaviorEvents.CLICK, paramList, ClientBehaviorEvents.ACTION, paramList, behaviors,
218 commandOnclick , null);
219 if (onClick.length() != 0)
220 {
221 writer.writeAttribute(HTML.ONCLICK_ATTR, onClick, null);
222 }
223 }
224
225 Map<String, Object> attributes = uiComponent.getAttributes();
226
227 HtmlRendererUtils.buildBehaviorChain(
228 facesContext, uiComponent, ClientBehaviorEvents.DBLCLICK, null, behaviors,
229 (String) attributes.get(HTML.ONDBLCLICK_ATTR), "");
230 }
231 else
232 {
233
234 if (!reset && !button)
235 {
236 StringBuilder onClick = buildOnClick(uiComponent, facesContext, writer, validParams);
237 if (onClick.length() != 0)
238 {
239 writer.writeAttribute(HTML.ONCLICK_ATTR, onClick.toString(), null);
240 }
241 }
242 else
243 {
244 HtmlRendererUtils.renderHTMLStringAttribute(writer, uiComponent, HTML.ONCLICK_ATTR, HTML.ONCLICK_ATTR);
245 }
246 }
247
248
249
250 if (isCommonPropertiesOptimizationEnabled(facesContext))
251 {
252 CommonPropertyUtils.renderButtonPassthroughPropertiesWithoutDisabledAndEvents(writer,
253 CommonPropertyUtils.getCommonPropertiesMarked(uiComponent), uiComponent);
254 }
255 else
256 {
257 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent,
258 HTML.BUTTON_PASSTHROUGH_ATTRIBUTES_WITHOUT_DISABLED_AND_EVENTS);
259 }
260
261
262 if (behaviors != null && !behaviors.isEmpty())
263 {
264 HtmlRendererUtils.renderBehaviorizedEventHandlersWithoutOnclick(
265 facesContext, writer, uiComponent, behaviors);
266 HtmlRendererUtils.renderBehaviorizedFieldEventHandlers(facesContext, writer, uiComponent, behaviors);
267 }
268 else
269 {
270 if (isCommonPropertiesOptimizationEnabled(facesContext))
271 {
272 long commonPropertiesMarked = CommonPropertyUtils.getCommonPropertiesMarked(uiComponent);
273 CommonPropertyUtils.renderEventPropertiesWithoutOnclick(writer, commonPropertiesMarked, uiComponent);
274 CommonPropertyUtils.renderCommonFieldEventProperties(writer, commonPropertiesMarked, uiComponent);
275 }
276 else
277 {
278 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent,
279 HTML.EVENT_HANDLER_ATTRIBUTES_WITHOUT_ONCLICK);
280 HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent,
281 HTML.COMMON_FIELD_EVENT_ATTRIBUTES);
282 }
283 }
284
285 if (isDisabled(facesContext, uiComponent))
286 {
287 writer.writeAttribute(HTML.DISABLED_ATTR, Boolean.TRUE,
288 org.apache.myfaces.shared.renderkit.JSFAttr.DISABLED_ATTR);
289 }
290
291 if (isReadonly(facesContext, uiComponent))
292 {
293 writer.writeAttribute(HTML.READONLY_ATTR, Boolean.TRUE,
294 org.apache.myfaces.shared.renderkit.JSFAttr.READONLY_ATTR);
295 }
296 }
297
298 public void encodeEnd(FacesContext facesContext, UIComponent uiComponent)
299 throws IOException
300 {
301 ResponseWriter writer = facesContext.getResponseWriter();
302
303 writer.endElement(HTML.INPUT_ELEM);
304
305 FormInfo formInfo = findNestingForm(uiComponent, facesContext);
306 if (formInfo != null)
307 {
308 HtmlFormRendererBase.renderScrollHiddenInputIfNecessary(
309 formInfo.getForm(), facesContext, writer);
310 }
311
312
313
314
315
316
317
318
319
320
321
322
323 }
324
325 protected String buildBehaviorizedOnClick(UIComponent uiComponent, Map<String, List<ClientBehavior>> behaviors,
326 FacesContext facesContext, ResponseWriter writer,
327 FormInfo nestedFormInfo, List<UIParameter> validParams)
328 throws IOException
329 {
330
331
332 StringBuilder userOnClick = new StringBuilder();
333
334 String commandOnClick = (String) uiComponent.getAttributes().get(HTML.ONCLICK_ATTR);
335
336 if (commandOnClick != null)
337 {
338 userOnClick.append(commandOnClick);
339 userOnClick.append(';');
340 }
341
342 StringBuilder rendererOnClick = new StringBuilder();
343
344 if (nestedFormInfo != null)
345 {
346
347
348
349
350
351
352
353
354
355
356
357
358
359 String formName = nestedFormInfo.getFormName();
360 if (JavascriptUtils.isRenderClearJavascriptOnButton(facesContext.getExternalContext()))
361 {
362
363 HtmlRendererUtils.appendClearHiddenCommandFormParamsFunctionCall(rendererOnClick, formName);
364 }
365
366 if (MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).isAutoScroll())
367 {
368 HtmlRendererUtils.appendAutoScrollAssignment(rendererOnClick, formName);
369 }
370
371 }
372
373
374
375 Collection<ClientBehaviorContext.Parameter> paramList = HtmlRendererUtils.getClientBehaviorContextParameters(
376 HtmlRendererUtils.mapAttachedParamsToStringValues(facesContext, uiComponent));
377
378 return HtmlRendererUtils.buildBehaviorChain(facesContext, uiComponent,
379 ClientBehaviorEvents.CLICK, paramList, ClientBehaviorEvents.ACTION, paramList, behaviors,
380 userOnClick.toString() , rendererOnClick.toString());
381 }
382
383 protected String buildServerOnclick(FacesContext facesContext, UIComponent component,
384 String clientId, FormInfo formInfo, List<UIParameter> validParams) throws IOException
385 {
386 UIComponent nestingForm = formInfo.getForm();
387 String formName = formInfo.getFormName();
388
389 StringBuilder onClick = new StringBuilder();
390
391 if (RendererUtils.isAdfOrTrinidadForm(formInfo.getForm()))
392 {
393 onClick.append("submitForm('");
394 onClick.append(formInfo.getForm().getClientId(facesContext));
395 onClick.append("',1,{source:'");
396 onClick.append(component.getClientId(facesContext));
397 onClick.append("'});return false;");
398 }
399 else
400 {
401 StringBuilder params = addChildParameters(facesContext, nestingForm, validParams);
402
403 String target = getTarget(component);
404
405 onClick.append("return ").
406 append(HtmlRendererUtils.SUBMIT_FORM_FN_NAME_JSF2).append("('").
407 append(formName).append("','").
408 append(component.getClientId(facesContext)).append("'");
409
410 if (params.length() > 2 || target != null)
411 {
412 onClick.append(",").
413 append(target == null ? "null" : ("'" + target + "'")).append(",").
414 append(params);
415 }
416 onClick.append(");");
417
418
419
420
421
422
423 }
424 return onClick.toString();
425 }
426
427 private StringBuilder addChildParameters(FacesContext context,
428 UIComponent nestingForm, List<UIParameter> validParams)
429 {
430
431 StringBuilder params = new StringBuilder();
432 params.append("[");
433
434 for (UIParameter param : validParams)
435 {
436 String name = param.getName();
437
438
439 if (MyfacesConfig.getCurrentInstance(context.getExternalContext()).isRenderHiddenFieldsForLinkParams())
440 {
441 addHiddenCommandParameter(context, nestingForm, name);
442 }
443
444 Object value = param.getValue();
445
446
447
448
449
450
451
452
453
454
455
456 String strParamValue = "";
457 if (value != null)
458 {
459 strParamValue = value.toString();
460 StringBuilder buff = null;
461 for (int i = 0; i < strParamValue.length(); i++)
462 {
463 char c = strParamValue.charAt(i);
464 if (c == '\'' || c == '\\')
465 {
466 if (buff == null)
467 {
468 buff = new StringBuilder();
469 buff.append(strParamValue.substring(0,i));
470 }
471 buff.append('\\');
472 buff.append(c);
473 }
474 else if (buff != null)
475 {
476 buff.append(c);
477 }
478 }
479 if (buff != null)
480 {
481 strParamValue = buff.toString();
482 }
483 }
484
485 if (params.length() > 1)
486 {
487 params.append(",");
488 }
489
490 params.append("['");
491 params.append(name);
492 params.append("','");
493 params.append(strParamValue);
494 params.append("']");
495 }
496 params.append("]");
497 return params;
498 }
499
500 private String getTarget(UIComponent component)
501 {
502
503 String target;
504 if (component instanceof HtmlCommandLink)
505 {
506 target = ((HtmlCommandLink) component).getTarget();
507 }
508 else
509 {
510 target = (String) component.getAttributes().get(HTML.TARGET_ATTR);
511 }
512 return target;
513 }
514
515 protected StringBuilder buildOnClick(UIComponent uiComponent, FacesContext facesContext,
516 ResponseWriter writer, List<UIParameter> validParams)
517 throws IOException
518 {
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546 StringBuilder onClick = new StringBuilder();
547 String commandOnClick = (String) uiComponent.getAttributes().get(HTML.ONCLICK_ATTR);
548
549 if (commandOnClick != null)
550 {
551 onClick.append("var cf = function(){");
552 onClick.append(commandOnClick);
553 onClick.append('}');
554 onClick.append(';');
555 onClick.append("var oamSF = function(){");
556 }
557
558 FormInfo nestedFormInfo = findNestingForm(uiComponent, facesContext);
559
560 if (nestedFormInfo != null)
561 {
562 String formName = nestedFormInfo.getFormName();
563
564 if (validParams != null && !validParams.isEmpty() )
565 {
566 StringBuilder params = addChildParameters(
567 facesContext, nestedFormInfo.getForm(), validParams);
568
569 String target = getTarget(uiComponent);
570
571 onClick.append("return ").
572 append(HtmlRendererUtils.SUBMIT_FORM_FN_NAME_JSF2).append("('").
573 append(formName).append("','").
574 append(uiComponent.getClientId(facesContext)).append("'");
575
576 if (params.length() > 2 || target != null)
577 {
578 onClick.append(",").
579 append(target == null ? "null" : ("'" + target + "'")).append(",").
580 append(params);
581 }
582 onClick.append(");");
583
584
585
586 if (MyfacesConfig.getCurrentInstance(
587 facesContext.getExternalContext()).isRenderHiddenFieldsForLinkParams())
588 {
589 String hiddenFieldName = HtmlRendererUtils.getHiddenCommandLinkFieldName(
590 nestedFormInfo, facesContext);
591 addHiddenCommandParameter(facesContext, nestedFormInfo.getForm(), hiddenFieldName);
592 }
593 }
594 else
595 {
596
597 if (JavascriptUtils.isRenderClearJavascriptOnButton(facesContext.getExternalContext()) ||
598 MyfacesConfig.getCurrentInstance(
599 facesContext.getExternalContext()).isRenderHiddenFieldsForLinkParams() )
600 {
601
602 HtmlRendererUtils.appendClearHiddenCommandFormParamsFunctionCall(onClick, formName);
603 }
604
605 if (MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).isAutoScroll())
606 {
607 HtmlRendererUtils.appendAutoScrollAssignment(onClick, formName);
608 }
609 }
610 }
611
612 if (commandOnClick != null)
613 {
614 onClick.append('}');
615 onClick.append(';');
616 onClick.append("return (cf.apply(this, [])==false)? false : oamSF.apply(this, []); ");
617 }
618
619
620
621
622
623
624
625
626
627
628 return onClick;
629 }
630
631 protected void addHiddenCommandParameter(FacesContext facesContext,
632 UIComponent nestingForm, String hiddenFieldName)
633 {
634 if (nestingForm != null)
635 {
636 HtmlFormRendererBase.addHiddenCommandParameter(facesContext, nestingForm, hiddenFieldName);
637 }
638 }
639
640
641
642
643
644 protected FormInfo findNestingForm(UIComponent uiComponent, FacesContext facesContext)
645 {
646 return RendererUtils.findNestingForm(uiComponent, facesContext);
647 }
648
649 protected boolean isDisabled(FacesContext facesContext, UIComponent uiComponent)
650 {
651
652 if (uiComponent instanceof HtmlCommandButton)
653 {
654 return ((HtmlCommandButton)uiComponent).isDisabled();
655 }
656
657 return org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanAttribute(
658 uiComponent, HTML.DISABLED_ATTR, false);
659
660 }
661
662 protected boolean isReadonly(FacesContext facesContext, UIComponent uiComponent)
663 {
664 if (uiComponent instanceof HtmlCommandButton)
665 {
666 return ((HtmlCommandButton)uiComponent).isReadonly();
667 }
668 return org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanAttribute(
669 uiComponent, HTML.READONLY_ATTR, false);
670 }
671
672 private String getType(UIComponent uiComponent)
673 {
674 if (uiComponent instanceof HtmlCommandButton)
675 {
676 return ((HtmlCommandButton)uiComponent).getType();
677 }
678 return (String)uiComponent.getAttributes().get(org.apache.myfaces.shared.renderkit.JSFAttr.TYPE_ATTR);
679 }
680
681 private Object getValue(UIComponent uiComponent)
682 {
683 if (uiComponent instanceof ValueHolder)
684 {
685 return ((ValueHolder)uiComponent).getValue();
686 }
687 return uiComponent.getAttributes().get(JSFAttr.VALUE_ATTR);
688 }
689 }