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