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.io.UnsupportedEncodingException;
23 import java.net.URLEncoder;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.RandomAccess;
29
30 import jakarta.faces.component.UICommand;
31 import jakarta.faces.component.UIComponent;
32 import jakarta.faces.component.UIOutcomeTarget;
33 import jakarta.faces.component.UIOutput;
34 import jakarta.faces.component.UIParameter;
35 import jakarta.faces.component.behavior.ClientBehavior;
36 import jakarta.faces.component.behavior.ClientBehaviorContext;
37 import jakarta.faces.component.behavior.ClientBehaviorHint;
38 import jakarta.faces.component.behavior.ClientBehaviorHolder;
39 import jakarta.faces.component.html.HtmlCommandLink;
40 import jakarta.faces.component.html.HtmlOutputLink;
41 import jakarta.faces.context.FacesContext;
42 import jakarta.faces.context.ResponseWriter;
43 import jakarta.faces.event.ActionEvent;
44
45 import org.apache.myfaces.shared.config.MyfacesConfig;
46 import org.apache.myfaces.shared.renderkit.ClientBehaviorEvents;
47 import org.apache.myfaces.shared.renderkit.JSFAttr;
48 import org.apache.myfaces.shared.renderkit.RendererUtils;
49 import org.apache.myfaces.shared.renderkit.html.util.FormInfo;
50 import org.apache.myfaces.shared.renderkit.html.util.ResourceUtils;
51 import org.apache.myfaces.shared.util._ComponentUtils;
52
53 public abstract class HtmlLinkRendererBase
54 extends HtmlRenderer
55 {
56
57
58
59
60
61
62
63 public static final String END_LINK_OUTCOME_AS_SPAN =
64 "oam.shared.HtmlLinkRendererBase.END_LINK_OUTCOME_AS_SPAN";
65
66 public boolean getRendersChildren()
67 {
68
69
70 return true;
71 }
72
73 public void decode(FacesContext facesContext, UIComponent component)
74 {
75 super.decode(facesContext, component);
76
77 if (component instanceof UICommand)
78 {
79 String clientId = component.getClientId(facesContext);
80 FormInfo formInfo = findNestingForm(component, facesContext);
81 boolean disabled = HtmlRendererUtils.isDisabled(component);
82
83 boolean activateActionEvent = false;
84 if (formInfo != null && !disabled)
85 {
86 String reqValue = (String) facesContext.getExternalContext().getRequestParameterMap().get(
87 HtmlRendererUtils.getHiddenCommandLinkFieldName(formInfo, facesContext));
88 activateActionEvent = reqValue != null && reqValue.equals(clientId)
89 || HtmlRendererUtils.isPartialOrBehaviorSubmit(facesContext, clientId);
90 if (activateActionEvent)
91 {
92 RendererUtils.initPartialValidationAndModelUpdate(component, facesContext);
93 }
94 }
95 if (component instanceof ClientBehaviorHolder &&
96 !disabled)
97 {
98 HtmlRendererUtils.decodeClientBehaviors(facesContext, component);
99 }
100 if (activateActionEvent)
101 {
102 component.queueEvent(new ActionEvent(component));
103 }
104 }
105 else if (component instanceof UIOutput)
106 {
107
108 if (component instanceof ClientBehaviorHolder &&
109 !HtmlRendererUtils.isDisabled(component))
110 {
111 HtmlRendererUtils.decodeClientBehaviors(facesContext, component);
112 }
113 }
114 else
115 {
116 throw new IllegalArgumentException("Unsupported component class " + component.getClass().getName());
117 }
118 }
119
120
121 public void encodeBegin(FacesContext facesContext, UIComponent component) throws IOException
122 {
123 super.encodeBegin(facesContext, component);
124
125 Map<String, List<ClientBehavior>> behaviors = null;
126 if (component instanceof ClientBehaviorHolder)
127 {
128 behaviors = ((ClientBehaviorHolder) component).getClientBehaviors();
129 if (!behaviors.isEmpty())
130 {
131 ResourceUtils.renderDefaultJsfJsInlineIfNecessary(facesContext, facesContext.getResponseWriter());
132 }
133 }
134
135 if (component instanceof UICommand)
136 {
137 renderCommandLinkStart(facesContext, component,
138 component.getClientId(facesContext),
139 ((UICommand)component).getValue(),
140 getStyle(facesContext, component),
141 getStyleClass(facesContext, component));
142 }
143 else if (component instanceof UIOutcomeTarget)
144 {
145 renderOutcomeLinkStart(facesContext, (UIOutcomeTarget)component);
146 }
147 else if (component instanceof UIOutput)
148 {
149 renderOutputLinkStart(facesContext, (UIOutput)component);
150 }
151 else
152 {
153 throw new IllegalArgumentException("Unsupported component class " + component.getClass().getName());
154 }
155 }
156
157
158
159
160
161 protected String getStyle(FacesContext facesContext, UIComponent link)
162 {
163 if (link instanceof HtmlCommandLink)
164 {
165 return ((HtmlCommandLink)link).getStyle();
166 }
167
168 return (String)link.getAttributes().get(HTML.STYLE_ATTR);
169
170 }
171
172
173
174
175 protected String getStyleClass(FacesContext facesContext, UIComponent link)
176 {
177 if (link instanceof HtmlCommandLink)
178 {
179 return ((HtmlCommandLink)link).getStyleClass();
180 }
181
182 return (String)link.getAttributes().get(HTML.STYLE_CLASS_ATTR);
183
184 }
185
186 public void encodeChildren(FacesContext facesContext, UIComponent component) throws IOException
187 {
188 RendererUtils.renderChildren(facesContext, component);
189 }
190
191 public void encodeEnd(FacesContext facesContext, UIComponent component) throws IOException
192 {
193 super.encodeEnd(facesContext, component);
194
195 if (component instanceof UICommand)
196 {
197 renderCommandLinkEnd(facesContext, component);
198
199 FormInfo formInfo = findNestingForm(component, facesContext);
200
201 if (formInfo != null)
202 {
203 HtmlFormRendererBase.renderScrollHiddenInputIfNecessary(
204 formInfo.getForm(), facesContext, facesContext.getResponseWriter());
205 }
206 }
207 else if (component instanceof UIOutcomeTarget)
208 {
209 renderOutcomeLinkEnd(facesContext, component);
210 }
211 else if (component instanceof UIOutput)
212 {
213 renderOutputLinkEnd(facesContext, component);
214 }
215 else
216 {
217 throw new IllegalArgumentException("Unsupported component class " + component.getClass().getName());
218 }
219 }
220
221 protected void renderCommandLinkStart(FacesContext facesContext, UIComponent component,
222 String clientId,
223 Object value,
224 String style,
225 String styleClass)
226 throws IOException
227 {
228 ResponseWriter writer = facesContext.getResponseWriter();
229 Map<String, List<ClientBehavior>> behaviors = null;
230
231
232 FormInfo formInfo = findNestingForm(component, facesContext);
233
234 boolean disabled = HtmlRendererUtils.isDisabled(component);
235
236 if (disabled || formInfo == null)
237 {
238 writer.startElement(HTML.SPAN_ELEM, component);
239 if (component instanceof ClientBehaviorHolder)
240 {
241 behaviors = ((ClientBehaviorHolder) component).getClientBehaviors();
242 if (!behaviors.isEmpty())
243 {
244 HtmlRendererUtils.writeIdAndName(writer, component, facesContext);
245 }
246 else
247 {
248 HtmlRendererUtils.writeIdIfNecessary(writer, component, facesContext);
249 }
250 long commonPropertiesMarked = 0L;
251 if (isCommonPropertiesOptimizationEnabled(facesContext))
252 {
253 commonPropertiesMarked = CommonPropertyUtils.getCommonPropertiesMarked(component);
254 }
255
256
257 if (!disabled)
258 {
259 if (behaviors.isEmpty() && isCommonPropertiesOptimizationEnabled(facesContext))
260 {
261 CommonPropertyUtils.renderEventProperties(writer,
262 commonPropertiesMarked, component);
263 CommonPropertyUtils.renderFocusBlurEventProperties(writer,
264 commonPropertiesMarked, component);
265 }
266 else
267 {
268 if (isCommonEventsOptimizationEnabled(facesContext))
269 {
270 Long commonEventsMarked = CommonEventUtils.getCommonEventsMarked(component);
271 CommonEventUtils.renderBehaviorizedEventHandlers(facesContext, writer,
272 commonPropertiesMarked, commonEventsMarked, component, behaviors);
273 CommonEventUtils.renderBehaviorizedFieldEventHandlersWithoutOnchangeAndOnselect(
274 facesContext, writer, commonPropertiesMarked, commonEventsMarked, component, behaviors);
275 }
276 else
277 {
278 HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, component,
279 behaviors);
280 HtmlRendererUtils.renderBehaviorizedFieldEventHandlersWithoutOnchangeAndOnselect(
281 facesContext, writer, component, behaviors);
282 }
283 }
284 }
285 else
286 {
287 if (behaviors.isEmpty() && isCommonPropertiesOptimizationEnabled(facesContext))
288 {
289 CommonPropertyUtils.renderEventPropertiesWithoutOnclick(writer,
290 commonPropertiesMarked, component);
291 CommonPropertyUtils.renderFocusBlurEventProperties(writer,
292 commonPropertiesMarked, component);
293 }
294 else
295 {
296 if (isCommonEventsOptimizationEnabled(facesContext))
297 {
298 Long commonEventsMarked = CommonEventUtils.getCommonEventsMarked(component);
299 CommonEventUtils.renderBehaviorizedEventHandlersWithoutOnclick(facesContext, writer,
300 commonPropertiesMarked, commonEventsMarked, component, behaviors);
301 CommonEventUtils.renderBehaviorizedFieldEventHandlersWithoutOnchangeAndOnselect(
302 facesContext, writer, commonPropertiesMarked, commonEventsMarked, component, behaviors);
303 }
304 else
305 {
306 HtmlRendererUtils.renderBehaviorizedEventHandlersWithoutOnclick(facesContext, writer,
307 component, behaviors);
308 HtmlRendererUtils.renderBehaviorizedFieldEventHandlersWithoutOnchangeAndOnselect(
309 facesContext, writer, component, behaviors);
310 }
311 }
312 }
313 if (isCommonPropertiesOptimizationEnabled(facesContext))
314 {
315 CommonPropertyUtils.renderAnchorPassthroughPropertiesDisabledWithoutEvents(writer,
316 commonPropertiesMarked, component);
317 }
318 else
319 {
320 HtmlRendererUtils.renderHTMLAttributes(writer, component,
321 HTML.ANCHOR_PASSTHROUGH_ATTRIBUTES_DISABLED_WITHOUT_EVENTS);
322 }
323 }
324 else
325 {
326 HtmlRendererUtils.writeIdIfNecessary(writer, component, facesContext);
327 if (isCommonPropertiesOptimizationEnabled(facesContext))
328 {
329 CommonPropertyUtils.renderAnchorPassthroughPropertiesDisabled(writer,
330 CommonPropertyUtils.getCommonPropertiesMarked(component), component);
331 }
332 else
333 {
334 HtmlRendererUtils.renderHTMLAttributes(writer, component,
335 HTML.ANCHOR_PASSTHROUGH_ATTRIBUTES_DISABLED);
336 }
337 }
338 }
339 else
340 {
341
342 if (component instanceof ClientBehaviorHolder)
343 {
344 behaviors = ((ClientBehaviorHolder) component).getClientBehaviors();
345 renderBehaviorizedJavaScriptAnchorStart(
346 facesContext, writer, component, clientId, behaviors, formInfo);
347 if (!behaviors.isEmpty())
348 {
349 HtmlRendererUtils.writeIdAndName(writer, component, facesContext);
350 }
351 else
352 {
353
354
355
356
357 String commandOnclick;
358 if (component instanceof HtmlCommandLink)
359 {
360 commandOnclick = ((HtmlCommandLink)component).getOnclick();
361 }
362 else
363 {
364 commandOnclick = (String)component.getAttributes().get(HTML.ONCLICK_ATTR);
365 }
366
367 if (commandOnclick != null)
368 {
369 HtmlRendererUtils.writeIdAndName(writer, component, facesContext);
370 }
371 else
372 {
373 HtmlRendererUtils.writeIdIfNecessary(writer, component, facesContext);
374 }
375 }
376 long commonPropertiesMarked = 0L;
377 if (isCommonPropertiesOptimizationEnabled(facesContext))
378 {
379 commonPropertiesMarked = CommonPropertyUtils.getCommonPropertiesMarked(component);
380 }
381 if (behaviors.isEmpty() && isCommonPropertiesOptimizationEnabled(facesContext))
382 {
383 CommonPropertyUtils.renderEventPropertiesWithoutOnclick(writer,
384 commonPropertiesMarked, component);
385 CommonPropertyUtils.renderFocusBlurEventProperties(writer,
386 commonPropertiesMarked, component);
387 }
388 else
389 {
390 HtmlRendererUtils.renderBehaviorizedEventHandlersWithoutOnclick(
391 facesContext, writer, component, behaviors);
392 HtmlRendererUtils.renderBehaviorizedFieldEventHandlersWithoutOnchangeAndOnselect(
393 facesContext, writer, component, behaviors);
394 }
395 if (isCommonPropertiesOptimizationEnabled(facesContext))
396 {
397 CommonPropertyUtils.renderAnchorPassthroughPropertiesWithoutStyleAndEvents(writer,
398 commonPropertiesMarked, component);
399 }
400 else
401 {
402 HtmlRendererUtils.renderHTMLAttributes(writer, component,
403 HTML.ANCHOR_PASSTHROUGH_ATTRIBUTES_WITHOUT_STYLE_AND_EVENTS);
404 }
405 }
406 else
407 {
408 renderJavaScriptAnchorStart(facesContext, writer, component, clientId, formInfo);
409 HtmlRendererUtils.writeIdIfNecessary(writer, component, facesContext);
410 if (isCommonPropertiesOptimizationEnabled(facesContext))
411 {
412 CommonPropertyUtils.renderAnchorPassthroughPropertiesWithoutOnclickAndStyle(writer,
413 CommonPropertyUtils.getCommonPropertiesMarked(component), component);
414 }
415 else
416 {
417 HtmlRendererUtils.renderHTMLAttributes(writer, component,
418 HTML.ANCHOR_PASSTHROUGH_ATTRIBUTES_WITHOUT_ONCLICK_WITHOUT_STYLE);
419 }
420 }
421
422
423
424
425 HtmlRendererUtils.renderHTMLAttribute(writer, HTML.STYLE_ATTR, HTML.STYLE_ATTR,
426 style);
427 HtmlRendererUtils.renderHTMLAttribute(writer, HTML.STYLE_CLASS_ATTR, HTML.STYLE_CLASS_ATTR,
428 styleClass);
429 }
430
431
432 if(value != null)
433 {
434 writer.writeText(value.toString(), JSFAttr.VALUE_ATTR);
435 }
436
437
438 if (formInfo == null)
439 {
440 writer.writeText(": This link is deactivated, because it is not embedded in a JSF form.", null);
441 }
442 }
443
444 protected void renderJavaScriptAnchorStart(FacesContext facesContext,
445 ResponseWriter writer,
446 UIComponent component,
447 String clientId,
448 FormInfo formInfo)
449 throws IOException
450 {
451 UIComponent nestingForm = formInfo.getForm();
452 String formName = formInfo.getFormName();
453
454 StringBuilder onClick = new StringBuilder();
455
456 String commandOnclick;
457 if (component instanceof HtmlCommandLink)
458 {
459 commandOnclick = ((HtmlCommandLink)component).getOnclick();
460 }
461 else
462 {
463 commandOnclick = (String)component.getAttributes().get(HTML.ONCLICK_ATTR);
464 }
465 if (commandOnclick != null)
466 {
467 onClick.append("var cf = function(){");
468 onClick.append(commandOnclick);
469 onClick.append('}');
470 onClick.append(';');
471 onClick.append("var oamSF = function(){");
472 }
473
474 if (RendererUtils.isAdfOrTrinidadForm(formInfo.getForm()))
475 {
476 onClick.append("submitForm('");
477 onClick.append(formInfo.getForm().getClientId(facesContext));
478 onClick.append("',1,{source:'");
479 onClick.append(component.getClientId(facesContext));
480 onClick.append("'});return false;");
481 }
482 else
483 {
484 HtmlRendererUtils.renderFormSubmitScript(facesContext);
485
486 StringBuilder params = addChildParameters(facesContext, component, nestingForm);
487
488 String target = getTarget(component);
489
490 onClick.append("return ").
491 append(HtmlRendererUtils.SUBMIT_FORM_FN_NAME_JSF2).append("('").
492 append(formName).append("','").
493 append(clientId).append("'");
494
495 if (params.length() > 2 || target != null)
496 {
497 onClick.append(",").
498 append(target == null ? "null" : ("'" + target + "'")).append(",").
499 append(params);
500 }
501 onClick.append(");");
502
503
504
505 if (MyfacesConfig.getCurrentInstance(
506 facesContext.getExternalContext()).isRenderHiddenFieldsForLinkParams())
507 {
508 String hiddenFieldName = HtmlRendererUtils.getHiddenCommandLinkFieldName(
509 formInfo, facesContext);
510 addHiddenCommandParameter(facesContext, nestingForm, hiddenFieldName);
511 }
512
513 }
514
515 if (commandOnclick != null)
516 {
517 onClick.append('}');
518 onClick.append(';');
519 onClick.append("return (cf.apply(this, [])==false)? false : oamSF.apply(this, []); ");
520 }
521
522 writer.startElement(HTML.ANCHOR_ELEM, component);
523 writer.writeURIAttribute(HTML.HREF_ATTR, "#", null);
524 writer.writeAttribute(HTML.ONCLICK_ATTR, onClick.toString(), null);
525 }
526
527
528 protected void renderBehaviorizedJavaScriptAnchorStart(FacesContext facesContext,
529 ResponseWriter writer,
530 UIComponent component,
531 String clientId,
532 Map<String, List<ClientBehavior>> behaviors,
533 FormInfo formInfo)
534 throws IOException
535 {
536 String commandOnclick;
537 if (component instanceof HtmlCommandLink)
538 {
539 commandOnclick = ((HtmlCommandLink)component).getOnclick();
540 }
541 else
542 {
543 commandOnclick = (String)component.getAttributes().get(HTML.ONCLICK_ATTR);
544 }
545
546
547 String serverEventCode = buildServerOnclick(facesContext, component, clientId, formInfo);
548
549 String onclick = null;
550
551 if (commandOnclick == null && (behaviors.isEmpty() ||
552 (!behaviors.containsKey(ClientBehaviorEvents.CLICK) &&
553 !behaviors.containsKey(ClientBehaviorEvents.ACTION) ) ) )
554 {
555
556 onclick = serverEventCode;
557 }
558 else
559 {
560 boolean hasSubmittingBehavior = hasSubmittingBehavior(behaviors, ClientBehaviorEvents.CLICK)
561 || hasSubmittingBehavior(behaviors, ClientBehaviorEvents.ACTION);
562 if (!hasSubmittingBehavior)
563 {
564
565 ResourceUtils.renderDefaultJsfJsInlineIfNecessary(facesContext, writer);
566 }
567
568
569 Collection<ClientBehaviorContext.Parameter> paramList =
570 HtmlRendererUtils.getClientBehaviorContextParameters(
571 HtmlRendererUtils.mapAttachedParamsToStringValues(facesContext, component));
572
573 onclick = HtmlRendererUtils.buildBehaviorChain(facesContext, component,
574 ClientBehaviorEvents.CLICK, paramList, ClientBehaviorEvents.ACTION, paramList, behaviors,
575 commandOnclick , hasSubmittingBehavior ? null : serverEventCode);
576 }
577
578 writer.startElement(HTML.ANCHOR_ELEM, component);
579 writer.writeURIAttribute(HTML.HREF_ATTR, "#", null);
580 writer.writeAttribute(HTML.ONCLICK_ATTR, onclick, null);
581 }
582
583 private boolean hasSubmittingBehavior(Map<String, List<ClientBehavior>> clientBehaviors, String eventName)
584 {
585 List<ClientBehavior> eventBehaviors = clientBehaviors.get(eventName);
586 if (eventBehaviors != null && !eventBehaviors.isEmpty())
587 {
588
589
590
591 if (eventBehaviors instanceof RandomAccess)
592 {
593 for (int i = 0, size = eventBehaviors.size(); i < size; i++)
594 {
595 ClientBehavior behavior = eventBehaviors.get(i);
596 if (behavior.getHints().contains(ClientBehaviorHint.SUBMITTING))
597 {
598 return true;
599 }
600 }
601 }
602 else
603 {
604 for (ClientBehavior behavior : eventBehaviors)
605 {
606 if (behavior.getHints().contains(ClientBehaviorHint.SUBMITTING))
607 {
608 return true;
609 }
610 }
611 }
612 }
613 return false;
614 }
615
616 protected String buildServerOnclick(FacesContext facesContext, UIComponent component,
617 String clientId, FormInfo formInfo) throws IOException
618 {
619 UIComponent nestingForm = formInfo.getForm();
620 String formName = formInfo.getFormName();
621
622 StringBuilder onClick = new StringBuilder();
623
624 if (RendererUtils.isAdfOrTrinidadForm(formInfo.getForm()))
625 {
626 onClick.append("submitForm('");
627 onClick.append(formInfo.getForm().getClientId(facesContext));
628 onClick.append("',1,{source:'");
629 onClick.append(component.getClientId(facesContext));
630 onClick.append("'});return false;");
631 }
632 else
633 {
634 HtmlRendererUtils.renderFormSubmitScript(facesContext);
635
636 StringBuilder params = addChildParameters(facesContext, component, nestingForm);
637
638 String target = getTarget(component);
639
640 onClick.append("return ").
641 append(HtmlRendererUtils.SUBMIT_FORM_FN_NAME_JSF2).append("('").
642 append(formName).append("','").
643 append(clientId).append("'");
644
645 if (params.length() > 2 || target != null)
646 {
647 onClick.append(",").
648 append(target == null ? "null" : ("'" + target + "'")).append(",").
649 append(params);
650 }
651 onClick.append(");");
652
653
654
655
656
657
658 }
659 return onClick.toString();
660 }
661
662 private String getTarget(UIComponent component)
663 {
664
665 String target;
666 if (component instanceof HtmlCommandLink)
667 {
668 target = ((HtmlCommandLink) component).getTarget();
669 }
670 else
671 {
672 target = (String) component.getAttributes().get(HTML.TARGET_ATTR);
673 }
674 return target;
675 }
676
677 private StringBuilder addChildParameters(FacesContext context, UIComponent component, UIComponent nestingForm)
678 {
679
680 StringBuilder params = new StringBuilder();
681 params.append("[");
682
683 List<UIComponent> childrenList = null;
684 if (getChildCount(component) > 0)
685 {
686 childrenList = getChildren(component);
687 }
688 else
689 {
690 childrenList = Collections.emptyList();
691 }
692 List<UIParameter> validParams = HtmlRendererUtils.getValidUIParameterChildren(
693 context, childrenList, false, false);
694 for (int j = 0, size = validParams.size(); j < size; j++)
695 {
696 UIParameter param = validParams.get(j);
697 String name = param.getName();
698
699
700 if (MyfacesConfig.getCurrentInstance(context.getExternalContext()).isRenderHiddenFieldsForLinkParams())
701 {
702 addHiddenCommandParameter(context, nestingForm, name);
703 }
704
705 Object value = param.getValue();
706
707
708
709
710
711
712
713
714
715
716
717 String strParamValue = "";
718 if (value != null)
719 {
720 strParamValue = value.toString();
721 StringBuilder buff = null;
722 for (int i = 0; i < strParamValue.length(); i++)
723 {
724 char c = strParamValue.charAt(i);
725 if (c == '\'' || c == '\\')
726 {
727 if (buff == null)
728 {
729 buff = new StringBuilder();
730 buff.append(strParamValue.substring(0,i));
731 }
732 buff.append('\\');
733 buff.append(c);
734 }
735 else if (buff != null)
736 {
737 buff.append(c);
738 }
739 }
740 if (buff != null)
741 {
742 strParamValue = buff.toString();
743 }
744 }
745
746 if (params.length() > 1)
747 {
748 params.append(",");
749 }
750
751 params.append("['");
752 params.append(name);
753 params.append("','");
754 params.append(strParamValue);
755 params.append("']");
756 }
757 params.append("]");
758 return params;
759 }
760
761
762
763
764
765 protected FormInfo findNestingForm(UIComponent uiComponent, FacesContext facesContext)
766 {
767 return _ComponentUtils.findNestingForm(uiComponent, facesContext);
768 }
769
770 protected void addHiddenCommandParameter(
771 FacesContext facesContext, UIComponent nestingForm, String hiddenFieldName)
772 {
773 if (nestingForm != null)
774 {
775 HtmlFormRendererBase.addHiddenCommandParameter(facesContext, nestingForm, hiddenFieldName);
776 }
777 }
778
779 private void addChildParametersToHref(FacesContext facesContext,
780 UIComponent linkComponent,
781 StringBuilder hrefBuf,
782 boolean firstParameter,
783 String charEncoding)
784 throws IOException
785 {
786 boolean strictXhtmlLinks
787 = MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).isStrictXhtmlLinks();
788 List<UIComponent> childrenList = null;
789 if (getChildCount(linkComponent) > 0)
790 {
791 childrenList = getChildren(linkComponent);
792 }
793 else
794 {
795 childrenList = Collections.emptyList();
796 }
797 List<UIParameter> validParams = HtmlRendererUtils.getValidUIParameterChildren(
798 facesContext, childrenList, false, false);
799
800 for (int i = 0, size = validParams.size(); i < size; i++)
801 {
802 UIParameter param = validParams.get(i);
803 String name = param.getName();
804 Object value = param.getValue();
805 addParameterToHref(name, value, hrefBuf, firstParameter, charEncoding, strictXhtmlLinks);
806 firstParameter = false;
807 }
808 }
809
810 protected void renderOutputLinkStart(FacesContext facesContext, UIOutput output)
811 throws IOException
812 {
813 ResponseWriter writer = facesContext.getResponseWriter();
814 Map<String, List<ClientBehavior>> behaviors = null;
815
816 if (HtmlRendererUtils.isDisabled(output))
817 {
818 writer.startElement(HTML.SPAN_ELEM, output);
819 if (output instanceof ClientBehaviorHolder)
820 {
821 behaviors = ((ClientBehaviorHolder) output).getClientBehaviors();
822 if (!behaviors.isEmpty())
823 {
824 HtmlRendererUtils.writeIdAndName(writer, output, facesContext);
825 }
826 else
827 {
828 HtmlRendererUtils.writeIdIfNecessary(writer, output, facesContext);
829 }
830 long commonPropertiesMarked = 0L;
831 if (isCommonPropertiesOptimizationEnabled(facesContext))
832 {
833 commonPropertiesMarked = CommonPropertyUtils.getCommonPropertiesMarked(output);
834 }
835
836 if (behaviors.isEmpty() && isCommonPropertiesOptimizationEnabled(facesContext))
837 {
838 CommonPropertyUtils.renderEventProperties(writer,
839 commonPropertiesMarked, output);
840 CommonPropertyUtils.renderFocusBlurEventProperties(writer,
841 commonPropertiesMarked, output);
842 }
843 else
844 {
845 if (isCommonEventsOptimizationEnabled(facesContext))
846 {
847 Long commonEventsMarked = CommonEventUtils.getCommonEventsMarked(output);
848 CommonEventUtils.renderBehaviorizedEventHandlers(facesContext, writer,
849 commonPropertiesMarked, commonEventsMarked, output, behaviors);
850 CommonEventUtils.renderBehaviorizedFieldEventHandlersWithoutOnchangeAndOnselect(
851 facesContext, writer, commonPropertiesMarked, commonEventsMarked, output, behaviors);
852 }
853 else
854 {
855 HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, output, behaviors);
856 HtmlRendererUtils.renderBehaviorizedFieldEventHandlersWithoutOnchangeAndOnselect(
857 facesContext, writer, output, behaviors);
858 }
859 }
860 if (isCommonPropertiesOptimizationEnabled(facesContext))
861 {
862 CommonPropertyUtils.renderAnchorPassthroughPropertiesDisabledWithoutEvents(writer,
863 commonPropertiesMarked, output);
864 }
865 else
866 {
867 HtmlRendererUtils.renderHTMLAttributes(writer, output,
868 HTML.ANCHOR_PASSTHROUGH_ATTRIBUTES_DISABLED_WITHOUT_EVENTS);
869 }
870 }
871 else
872 {
873 HtmlRendererUtils.writeIdIfNecessary(writer, output, facesContext);
874 if (isCommonPropertiesOptimizationEnabled(facesContext))
875 {
876 CommonPropertyUtils.renderAnchorPassthroughPropertiesDisabled(writer,
877 CommonPropertyUtils.getCommonPropertiesMarked(output), output);
878 }
879 else
880 {
881 HtmlRendererUtils.renderHTMLAttributes(writer, output, HTML.ANCHOR_PASSTHROUGH_ATTRIBUTES_DISABLED);
882 }
883 }
884 }
885 else
886 {
887
888 String href = org.apache.myfaces.shared.renderkit.RendererUtils.getStringValue(facesContext, output);
889
890
891 int index = href.indexOf('#');
892 String anchorString = null;
893 boolean isAnchorInHref = (index > -1);
894 if (isAnchorInHref)
895 {
896
897 anchorString = href.substring(index,href.length());
898 href = href.substring(0,index);
899 }
900 if (getChildCount(output) > 0)
901 {
902 StringBuilder hrefBuf = new StringBuilder(href);
903 addChildParametersToHref(facesContext, output, hrefBuf,
904 (href.indexOf('?') == -1),
905 writer.getCharacterEncoding());
906 href = hrefBuf.toString();
907 }
908
909 String fragmentAttr = null;
910 if (output instanceof HtmlOutputLink)
911 {
912 fragmentAttr = ((HtmlOutputLink) output).getFragment();
913 }
914 else
915 {
916 fragmentAttr = (String) output.getAttributes().get(JSFAttr.FRAGMENT_ATTR);
917 }
918 if (fragmentAttr != null && !"".equals(fragmentAttr))
919 {
920 href += "#" + fragmentAttr;
921 }
922 else if (isAnchorInHref)
923 {
924 href += anchorString;
925 }
926 href = facesContext.getExternalContext().encodeResourceURL(href);
927
928
929 writer.startElement(HTML.ANCHOR_ELEM, output);
930 writer.writeURIAttribute(HTML.HREF_ATTR, href, null);
931 if (output instanceof ClientBehaviorHolder)
932 {
933 behaviors = ((ClientBehaviorHolder) output).getClientBehaviors();
934 if (!behaviors.isEmpty())
935 {
936 HtmlRendererUtils.writeIdAndName(writer, output, facesContext);
937 }
938 else
939 {
940 HtmlRendererUtils.writeIdAndNameIfNecessary(writer, output, facesContext);
941 }
942 long commonPropertiesMarked = 0L;
943 if (isCommonPropertiesOptimizationEnabled(facesContext))
944 {
945 commonPropertiesMarked = CommonPropertyUtils.getCommonPropertiesMarked(output);
946 }
947 if (behaviors.isEmpty() && isCommonPropertiesOptimizationEnabled(facesContext))
948 {
949 CommonPropertyUtils.renderEventProperties(writer,
950 commonPropertiesMarked, output);
951 CommonPropertyUtils.renderFocusBlurEventProperties(writer,
952 commonPropertiesMarked, output);
953 }
954 else
955 {
956 if (isCommonEventsOptimizationEnabled(facesContext))
957 {
958 Long commonEventsMarked = CommonEventUtils.getCommonEventsMarked(output);
959 CommonEventUtils.renderBehaviorizedEventHandlers(facesContext, writer,
960 commonPropertiesMarked, commonEventsMarked, output, behaviors);
961 CommonEventUtils.renderBehaviorizedFieldEventHandlersWithoutOnchangeAndOnselect(
962 facesContext, writer, commonPropertiesMarked, commonEventsMarked, output, behaviors);
963 }
964 else
965 {
966 HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, output, behaviors);
967 HtmlRendererUtils.renderBehaviorizedFieldEventHandlersWithoutOnchangeAndOnselect(
968 facesContext, writer, output, behaviors);
969 }
970 }
971 if (isCommonPropertiesOptimizationEnabled(facesContext))
972 {
973 CommonPropertyUtils.renderAnchorPassthroughPropertiesWithoutEvents(writer,
974 commonPropertiesMarked, output);
975 }
976 else
977 {
978 HtmlRendererUtils.renderHTMLAttributes(writer, output,
979 HTML.ANCHOR_PASSTHROUGH_ATTRIBUTES_WITHOUT_EVENTS);
980 }
981 }
982 else
983 {
984 HtmlRendererUtils.writeIdAndNameIfNecessary(writer, output, facesContext);
985 if (isCommonPropertiesOptimizationEnabled(facesContext))
986 {
987 CommonPropertyUtils.renderAnchorPassthroughProperties(writer,
988 CommonPropertyUtils.getCommonPropertiesMarked(output), output);
989 }
990 else
991 {
992 HtmlRendererUtils.renderHTMLAttributes(writer, output, HTML.ANCHOR_PASSTHROUGH_ATTRIBUTES);
993 }
994 }
995 writer.flush();
996 }
997 }
998
999 protected void renderOutcomeLinkStart(FacesContext facesContext, UIOutcomeTarget output)
1000 throws IOException
1001 {
1002 ResponseWriter writer = facesContext.getResponseWriter();
1003 Map<String, List<ClientBehavior>> behaviors = null;
1004
1005
1006 String targetHref = HtmlRendererUtils.getOutcomeTargetHref(facesContext, output);
1007
1008 if (HtmlRendererUtils.isDisabled(output) || targetHref == null)
1009 {
1010
1011
1012
1013 facesContext.getAttributes().put(END_LINK_OUTCOME_AS_SPAN, Boolean.TRUE);
1014 writer.startElement(HTML.SPAN_ELEM, output);
1015 if (output instanceof ClientBehaviorHolder)
1016 {
1017 behaviors = ((ClientBehaviorHolder) output).getClientBehaviors();
1018 if (!behaviors.isEmpty())
1019 {
1020 HtmlRendererUtils.writeIdAndName(writer, output, facesContext);
1021 }
1022 else
1023 {
1024 HtmlRendererUtils.writeIdIfNecessary(writer, output, facesContext);
1025 }
1026 long commonPropertiesMarked = 0L;
1027 if (isCommonPropertiesOptimizationEnabled(facesContext))
1028 {
1029 commonPropertiesMarked = CommonPropertyUtils.getCommonPropertiesMarked(output);
1030 }
1031 if (behaviors.isEmpty() && isCommonPropertiesOptimizationEnabled(facesContext))
1032 {
1033 CommonPropertyUtils.renderEventProperties(writer,
1034 commonPropertiesMarked, output);
1035 CommonPropertyUtils.renderFocusBlurEventProperties(writer,
1036 commonPropertiesMarked, output);
1037 }
1038 else
1039 {
1040 if (isCommonEventsOptimizationEnabled(facesContext))
1041 {
1042 Long commonEventsMarked = CommonEventUtils.getCommonEventsMarked(output);
1043 CommonEventUtils.renderBehaviorizedEventHandlers(facesContext, writer,
1044 commonPropertiesMarked, commonEventsMarked, output, behaviors);
1045 CommonEventUtils.renderBehaviorizedFieldEventHandlersWithoutOnchangeAndOnselect(
1046 facesContext, writer, commonPropertiesMarked, commonEventsMarked, output, behaviors);
1047 }
1048 else
1049 {
1050 HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, output, behaviors);
1051 HtmlRendererUtils.renderBehaviorizedFieldEventHandlersWithoutOnchangeAndOnselect(
1052 facesContext, writer, output, behaviors);
1053 }
1054 }
1055 if (isCommonPropertiesOptimizationEnabled(facesContext))
1056 {
1057 CommonPropertyUtils.renderAnchorPassthroughPropertiesDisabledWithoutEvents(writer,
1058 commonPropertiesMarked, output);
1059 }
1060 else
1061 {
1062 HtmlRendererUtils.renderHTMLAttributes(writer, output,
1063 HTML.ANCHOR_PASSTHROUGH_ATTRIBUTES_DISABLED_WITHOUT_EVENTS);
1064 }
1065 }
1066 else
1067 {
1068 HtmlRendererUtils.writeIdIfNecessary(writer, output, facesContext);
1069 if (isCommonPropertiesOptimizationEnabled(facesContext))
1070 {
1071 CommonPropertyUtils.renderAnchorPassthroughPropertiesDisabled(writer,
1072 CommonPropertyUtils.getCommonPropertiesMarked(output), output);
1073 }
1074 else
1075 {
1076 HtmlRendererUtils.renderHTMLAttributes(writer, output, HTML.ANCHOR_PASSTHROUGH_ATTRIBUTES_DISABLED);
1077 }
1078 }
1079
1080 Object value = output.getValue();
1081
1082 if(value != null)
1083 {
1084 writer.writeText(value.toString(), JSFAttr.VALUE_ATTR);
1085 }
1086 }
1087 else
1088 {
1089
1090 writer.startElement(HTML.ANCHOR_ELEM, output);
1091 writer.writeURIAttribute(HTML.HREF_ATTR, targetHref, null);
1092 if (output instanceof ClientBehaviorHolder)
1093 {
1094 behaviors = ((ClientBehaviorHolder) output).getClientBehaviors();
1095 if (!behaviors.isEmpty())
1096 {
1097 HtmlRendererUtils.writeIdAndName(writer, output, facesContext);
1098 }
1099 else
1100 {
1101 HtmlRendererUtils.writeIdAndNameIfNecessary(writer, output, facesContext);
1102 }
1103 long commonPropertiesMarked = 0L;
1104 if (isCommonPropertiesOptimizationEnabled(facesContext))
1105 {
1106 commonPropertiesMarked = CommonPropertyUtils.getCommonPropertiesMarked(output);
1107 }
1108 if (behaviors.isEmpty() && isCommonPropertiesOptimizationEnabled(facesContext))
1109 {
1110 CommonPropertyUtils.renderEventProperties(writer,
1111 commonPropertiesMarked, output);
1112 CommonPropertyUtils.renderFocusBlurEventProperties(writer,
1113 commonPropertiesMarked, output);
1114 }
1115 else
1116 {
1117 if (isCommonEventsOptimizationEnabled(facesContext))
1118 {
1119 Long commonEventsMarked = CommonEventUtils.getCommonEventsMarked(output);
1120 CommonEventUtils.renderBehaviorizedEventHandlers(facesContext, writer,
1121 commonPropertiesMarked, commonEventsMarked, output, behaviors);
1122 CommonEventUtils.renderBehaviorizedFieldEventHandlersWithoutOnchangeAndOnselect(
1123 facesContext, writer, commonPropertiesMarked, commonEventsMarked, output, behaviors);
1124 }
1125 else
1126 {
1127 HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, output, behaviors);
1128 HtmlRendererUtils.renderBehaviorizedFieldEventHandlersWithoutOnchangeAndOnselect(
1129 facesContext, writer, output, behaviors);
1130 }
1131 }
1132 if (isCommonPropertiesOptimizationEnabled(facesContext))
1133 {
1134 CommonPropertyUtils.renderAnchorPassthroughPropertiesWithoutEvents(writer,
1135 commonPropertiesMarked, output);
1136 }
1137 else
1138 {
1139 HtmlRendererUtils.renderHTMLAttributes(writer, output,
1140 HTML.ANCHOR_PASSTHROUGH_ATTRIBUTES_WITHOUT_EVENTS);
1141 }
1142 }
1143 else
1144 {
1145 HtmlRendererUtils.writeIdAndNameIfNecessary(writer, output, facesContext);
1146 if (isCommonPropertiesOptimizationEnabled(facesContext))
1147 {
1148 CommonPropertyUtils.renderAnchorPassthroughProperties(writer,
1149 CommonPropertyUtils.getCommonPropertiesMarked(output), output);
1150 }
1151 else
1152 {
1153 HtmlRendererUtils.renderHTMLAttributes(writer, output,
1154 HTML.ANCHOR_PASSTHROUGH_ATTRIBUTES);
1155 }
1156 }
1157
1158 writer.flush();
1159 }
1160 }
1161
1162 private static void addParameterToHref(String name,
1163 Object value,
1164 StringBuilder hrefBuf,
1165 boolean firstParameter,
1166 String charEncoding,
1167 boolean strictXhtmlLinks) throws UnsupportedEncodingException
1168 {
1169 if (name == null)
1170 {
1171 throw new IllegalArgumentException("Unnamed parameter value not allowed within command link.");
1172 }
1173
1174 if (firstParameter)
1175 {
1176 hrefBuf.append('?');
1177 }
1178 else
1179 {
1180 if (strictXhtmlLinks)
1181 {
1182 hrefBuf.append("&");
1183 }
1184 else
1185 {
1186 hrefBuf.append('&');
1187 }
1188 }
1189
1190 hrefBuf.append(URLEncoder.encode(name, charEncoding));
1191 hrefBuf.append('=');
1192 if (value != null)
1193 {
1194
1195 hrefBuf.append(URLEncoder.encode(value.toString(), charEncoding));
1196 }
1197 }
1198
1199 protected void renderOutcomeLinkEnd(FacesContext facesContext, UIComponent component)
1200 throws IOException
1201 {
1202 ResponseWriter writer = facesContext.getResponseWriter();
1203
1204 if (HtmlRendererUtils.isDisabled(component) || Boolean.TRUE.equals(
1205 facesContext.getAttributes().get(END_LINK_OUTCOME_AS_SPAN)))
1206 {
1207 writer.endElement(HTML.SPAN_ELEM);
1208 facesContext.getAttributes().put(END_LINK_OUTCOME_AS_SPAN, Boolean.FALSE);
1209 }
1210 else
1211 {
1212 writer.writeText (org.apache.myfaces.shared.renderkit.RendererUtils.getStringValue
1213 (facesContext, component), null);
1214 writer.endElement(HTML.ANCHOR_ELEM);
1215 }
1216 }
1217
1218 protected void renderOutputLinkEnd(FacesContext facesContext, UIComponent component)
1219 throws IOException
1220 {
1221 ResponseWriter writer = facesContext.getResponseWriter();
1222
1223 if (HtmlRendererUtils.isDisabled(component))
1224 {
1225 writer.endElement(HTML.SPAN_ELEM);
1226 }
1227 else
1228 {
1229
1230 writer.writeText("", null);
1231 writer.endElement(HTML.ANCHOR_ELEM);
1232 }
1233 }
1234
1235 protected void renderCommandLinkEnd(FacesContext facesContext, UIComponent component)
1236 throws IOException
1237 {
1238 FormInfo formInfo = findNestingForm(component, facesContext);
1239
1240 ResponseWriter writer = facesContext.getResponseWriter();
1241 if (HtmlRendererUtils.isDisabled(component) || formInfo == null)
1242 {
1243
1244 writer.endElement(HTML.SPAN_ELEM);
1245 }
1246 else
1247 {
1248 writer.writeText("", null);
1249 writer.endElement(HTML.ANCHOR_ELEM);
1250 }
1251 }
1252 }