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