1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.tobago.internal.renderkit.renderer;
21
22 import org.apache.myfaces.tobago.component.ClientBehaviors;
23 import org.apache.myfaces.tobago.context.Markup;
24 import org.apache.myfaces.tobago.internal.component.AbstractUIData;
25 import org.apache.myfaces.tobago.internal.component.AbstractUITree;
26 import org.apache.myfaces.tobago.internal.component.AbstractUITreeListbox;
27 import org.apache.myfaces.tobago.internal.component.AbstractUITreeNodeBase;
28 import org.apache.myfaces.tobago.internal.component.AbstractUITreeSelect;
29 import org.apache.myfaces.tobago.internal.renderkit.Command;
30 import org.apache.myfaces.tobago.internal.renderkit.CommandMap;
31 import org.apache.myfaces.tobago.internal.util.HtmlRendererUtils;
32 import org.apache.myfaces.tobago.internal.util.StringUtils;
33 import org.apache.myfaces.tobago.model.Selectable;
34 import org.apache.myfaces.tobago.renderkit.RendererBase;
35 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
36 import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
37 import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
38 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
39 import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
40 import org.apache.myfaces.tobago.util.ComponentUtils;
41 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 import javax.faces.component.UINamingContainer;
46 import javax.faces.context.FacesContext;
47 import java.io.IOException;
48 import java.lang.invoke.MethodHandles;
49 import java.util.Map;
50
51 public class TreeSelectRenderer<T extends AbstractUITreeSelect> extends RendererBase<T> {
52
53 private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
54
55 @Override
56 public void decodeInternal(final FacesContext facesContext, final T component) {
57
58 if (component.isDisabled()) {
59 return;
60 }
61
62 final AbstractUITreeNodeBase node = ComponentUtils.findAncestor(component, AbstractUITreeNodeBase.class);
63 final AbstractUIData data = ComponentUtils.findAncestor(node, AbstractUIData.class);
64 final String clientId = component.getClientId(facesContext);
65 final String name;
66
67 if (data.getSelectable().isSingle()) {
68 name = getClientIdWithoutRowIndex(data, clientId);
69 } else {
70 name = clientId;
71 }
72
73 final String parameter = facesContext.getExternalContext().getRequestParameterMap().get(name);
74
75 if (LOG.isDebugEnabled()) {
76 LOG.debug("parameter = '" + parameter + "'");
77 }
78
79 final boolean selected = clientId.equals(parameter);
80 if (!component.isValueStoredInState()) {
81 component.setSubmittedValue(selected ? "true" : "false");
82 }
83 }
84
85 @Override
86 public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
87
88 final AbstractUITree tree = ComponentUtils.findAncestor(component, AbstractUITree.class);
89 final AbstractUITreeNodeBase node = ComponentUtils.findAncestor(component, AbstractUITreeNodeBase.class);
90 final AbstractUIData data = ComponentUtils.findAncestor(node, AbstractUIData.class);
91
92 final TobagoResponseWriter writer = getResponseWriter(facesContext);
93
94 if (data instanceof AbstractUITreeListbox) {
95 writer.write(StringUtils.defaultString(component.getLabel()));
96 return;
97 }
98
99 final String id = component.getClientId(facesContext);
100 final String currentValue = getCurrentValue(facesContext, component);
101 final boolean checked;
102 if (component.isValueStoredInState()) {
103 checked = data.getSelectedState().isSelected(node.getPath());
104 } else {
105 checked = "true".equals(currentValue);
106 }
107
108 final boolean folder = data.isFolder();
109 final Selectable selectable = data.getSelectable();
110 final boolean showCustomControl = component.isShowCheckbox()
111 && selectable != Selectable.none && (!selectable.isLeafOnly() || !folder);
112
113 writer.startElement(HtmlElements.TOBAGO_TREE_SELECT);
114 final Markup markup = component.getMarkup();
115 writer.writeClassAttribute(
116 component.getCustomClass(),
117 TobagoClass.TREE_SELECT.createMarkup(markup),
118
119 showCustomControl ? BootstrapClass.FORM_CHECK_INLINE : null,
120 showCustomControl && selectable.isMulti() ? BootstrapClass.FORM_CHECK : null,
121 showCustomControl && selectable.isSingle() ? BootstrapClass.FORM_CHECK : null);
122 HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
123
124 if (showCustomControl) {
125 writer.startElement(HtmlElements.INPUT);
126 writer.writeClassAttribute(BootstrapClass.FORM_CHECK_INPUT);
127 if (selectable.isSingle()) {
128 writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.RADIO);
129 writer.writeNameAttribute(getClientIdWithoutRowIndex(data, id));
130 } else {
131 writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.CHECKBOX);
132 writer.writeNameAttribute(id);
133 }
134 writer.writeAttribute(HtmlAttributes.VALUE, id, false);
135
136 writer.writeIdAttribute(id);
137 writer.writeAttribute(HtmlAttributes.CHECKED, checked);
138
139 writer.endElement(HtmlElements.INPUT);
140 }
141
142 final String label = component.getLabel();
143 writer.startElement(HtmlElements.LABEL);
144 writer.writeClassAttribute(TobagoClass.TREE_SELECT__LABEL,
145 showCustomControl ? BootstrapClass.FORM_CHECK_LABEL : null);
146 final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
147 if (title != null) {
148 writer.writeAttribute(HtmlAttributes.TITLE, title, true);
149 }
150 writer.writeAttribute(HtmlAttributes.FOR, id, false);
151 writer.writeText(label);
152 writer.endElement(HtmlElements.LABEL);
153
154 if (showCustomControl) {
155 final CommandMap behaviorCommands = getBehaviorCommands(facesContext, component);
156 if (behaviorCommands != null) {
157 Map<ClientBehaviors, Command> other = behaviorCommands.getOther();
158 if (other != null) {
159 Command change = other.get(ClientBehaviors.change);
160 change.setExecute(change.getExecute() + " " + tree.getClientId(facesContext));
161 change.setRender(change.getRender() + " " + tree.getClientId(facesContext));
162 }
163 }
164 encodeBehavior(writer, behaviorCommands);
165 }
166
167 writer.endElement(HtmlElements.TOBAGO_TREE_SELECT);
168 }
169
170 private String getClientIdWithoutRowIndex(final AbstractUIData data, final String id) {
171 final char separatorChar = UINamingContainer.getSeparatorChar(FacesContext.getCurrentInstance());
172 return id.substring(0, id.indexOf("" + separatorChar + data.getRowIndex() + separatorChar));
173 }
174
175 @Override
176 public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
177 }
178 }