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