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