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.facelets.extension;
21
22 import org.apache.myfaces.tobago.component.Attributes;
23 import org.apache.myfaces.tobago.component.Facets;
24 import org.apache.myfaces.tobago.component.InputSuggest;
25 import org.apache.myfaces.tobago.component.OnComponentCreated;
26 import org.apache.myfaces.tobago.component.OnComponentPopulated;
27 import org.apache.myfaces.tobago.component.RendererTypes;
28 import org.apache.myfaces.tobago.component.SupportsMarkup;
29 import org.apache.myfaces.tobago.component.UIGridLayout;
30 import org.apache.myfaces.tobago.component.UILabel;
31 import org.apache.myfaces.tobago.component.UIPanel;
32 import org.apache.myfaces.tobago.context.Markup;
33 import org.apache.myfaces.tobago.facelets.SuggestMethodRule;
34 import org.apache.myfaces.tobago.facelets.SupportsMarkupRule;
35 import org.apache.myfaces.tobago.facelets.TobagoComponentHandler;
36 import org.apache.myfaces.tobago.internal.layout.LayoutUtils;
37 import org.apache.myfaces.tobago.util.ComponentUtils;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 import javax.el.ELException;
42 import javax.el.ValueExpression;
43 import javax.faces.FacesException;
44 import javax.faces.application.Application;
45 import javax.faces.component.EditableValueHolder;
46 import javax.faces.component.UIComponent;
47 import javax.faces.component.UIViewRoot;
48 import javax.faces.view.facelets.ComponentConfig;
49 import javax.faces.view.facelets.ComponentHandler;
50 import javax.faces.view.facelets.FaceletContext;
51 import javax.faces.view.facelets.MetaRuleset;
52 import javax.faces.view.facelets.Metadata;
53 import javax.faces.view.facelets.TagAttribute;
54 import java.io.IOException;
55
56 public abstract class TobagoLabelExtensionHandler extends ComponentHandler {
57 private static final Logger LOG = LoggerFactory.getLogger(TobagoLabelExtensionHandler.class);
58 private static final String DEFAULT_COLUMNS = "auto;*";
59 private TagAttribute labelWidthAttribute;
60 private TagAttribute tipAttribute;
61 private TagAttribute labelAttribute;
62 private TagAttribute markupAttribute;
63 private TagAttribute fieldIdAttribute;
64 private Class subComponentLastType = Object.class;
65 private Metadata subComponentMapper;
66
67 public TobagoLabelExtensionHandler(ComponentConfig config) {
68 super(config);
69 labelWidthAttribute = getAttribute("labelWidth");
70 tipAttribute = getAttribute(Attributes.TIP);
71 labelAttribute = getAttribute(Attributes.LABEL);
72 markupAttribute = getAttribute(Attributes.MARKUP);
73 fieldIdAttribute = getAttribute("fieldId");
74 }
75
76 protected abstract String getSubComponentType();
77
78 protected abstract String getSubRendererType();
79
80 protected String getRows() {
81 return "auto";
82 }
83
84 protected String getColumns(String first) {
85 return first + ";*";
86 }
87
88 public void applyNextHandler(FaceletContext ctx, UIComponent panel)
89 throws IOException, FacesException, ELException {
90 if (ComponentHandler.isNew(panel)) {
91
92 UIComponent input = panel.getChildren().remove(1);
93 try {
94 input.getAttributes().put("tobago.panel", panel);
95 nextHandler.apply(ctx, input);
96 } finally {
97 input.getAttributes().remove("tobago.panel");
98 }
99 UIComponent date = null;
100 if (panel.getChildCount() > 1) {
101 date = panel.getChildren().get(1);
102 }
103 panel.getChildren().add(input);
104 if (date != null) {
105 panel.getChildren().add(date);
106 }
107 } else {
108 UIComponent input = panel.getChildren().get(1);
109 nextHandler.apply(ctx, input);
110 }
111 }
112
113 public void onComponentCreated(FaceletContext faceletContext, UIComponent panel, UIComponent parent) {
114
115 Application application = faceletContext.getFacesContext().getApplication();
116 UIViewRoot root = ComponentUtils.findViewRoot(faceletContext, parent);
117
118 addGridLayout(faceletContext, panel, root);
119
120 addLabel(faceletContext, (UIPanel) panel, root);
121 String uid;
122 if (fieldIdAttribute != null) {
123 uid = fieldIdAttribute.getValue(faceletContext);
124 } else {
125 uid = root.createUniqueId();
126 }
127 if (checkForAlreadyCreated(panel, uid)) {
128 return;
129 }
130
131 UIComponent input = application.createComponent(getSubComponentType());
132 input.setRendererType(getSubRendererType());
133 input.setId(uid);
134
135 setSubComponentAttributes(faceletContext, input);
136 enrichInput(faceletContext, input);
137
138 panel.getChildren().add(input);
139 }
140
141 protected void enrichInput(FaceletContext faceletContext, UIComponent input) {
142 }
143
144 private void addLabel(FaceletContext faceletContext, UIPanel panel, UIViewRoot root) {
145 String uid = root.createUniqueId();
146 if (checkForAlreadyCreated(panel, uid)) {
147 return;
148 }
149 Application application = faceletContext.getFacesContext().getApplication();
150 UILabel label = (UILabel) application.createComponent(UILabel.COMPONENT_TYPE);
151 label.setRendererType(RendererTypes.LABEL);
152 label.setId(uid);
153 label.getAttributes().put(Attributes.FOR, "@auto");
154 if (tipAttribute != null) {
155 if (tipAttribute.isLiteral()) {
156 panel.setTip(tipAttribute.getValue(faceletContext));
157 } else {
158 ValueExpression expression = tipAttribute.getValueExpression(faceletContext, String.class);
159 panel.setValueExpression(Attributes.TIP, expression);
160 }
161 }
162 if (labelAttribute != null) {
163 if (labelAttribute.isLiteral()) {
164 label.setValue(labelAttribute.getValue(faceletContext));
165 } else {
166 ValueExpression expression = labelAttribute.getValueExpression(faceletContext, String.class);
167 label.setValueExpression(Attributes.VALUE, expression);
168 }
169 }
170 if (markupAttribute != null) {
171 if (markupAttribute.isLiteral()) {
172 label.setMarkup(Markup.valueOf(markupAttribute.getValue()));
173 } else {
174 ValueExpression expression = markupAttribute.getValueExpression(faceletContext, Object.class);
175 label.setValueExpression(Attributes.MARKUP, expression);
176 }
177 }
178 panel.getChildren().add(label);
179 }
180
181 private boolean checkForAlreadyCreated(UIComponent panel, String uid) {
182 if (panel.getChildCount() > 0) {
183 for (UIComponent child : panel.getChildren()) {
184 if (uid.equals(child.getId())) {
185 return true;
186 }
187 }
188 }
189 return false;
190 }
191
192 public void onComponentPopulated(FaceletContext faceletContext, UIComponent component, UIComponent parent) {
193 super.onComponentPopulated(faceletContext, component, parent);
194 if (component.getChildren().size() > 1 && component.getChildren().get(1) instanceof EditableValueHolder) {
195 TobagoComponentHandler.addDefaultValidators(faceletContext.getFacesContext(),
196 (EditableValueHolder) component.getChildren().get(1));
197 }
198 }
199
200 private void addGridLayout(FaceletContext faceletContext, UIComponent panel, UIViewRoot root) {
201 Application application = faceletContext.getFacesContext().getApplication();
202 UIGridLayout gridLayout = (UIGridLayout) application.createComponent(UIGridLayout.COMPONENT_TYPE);
203 gridLayout.setRendererType(RendererTypes.GRID_LAYOUT);
204 if (labelWidthAttribute != null) {
205 String columns = getColumns(labelWidthAttribute.getValue(faceletContext));
206 if (!LayoutUtils.checkTokens(columns)) {
207 LOG.warn("Illegal value for columns = \"" + columns + "\" replacing with default: \"" + DEFAULT_COLUMNS + "\"");
208 columns = DEFAULT_COLUMNS;
209 }
210 gridLayout.setColumns(columns);
211 } else {
212 gridLayout.setColumns(getColumns("auto"));
213 }
214 gridLayout.setRows(getRows());
215 gridLayout.setId(root.createUniqueId());
216 if (gridLayout instanceof OnComponentCreated) {
217 ((OnComponentCreated) gridLayout).onComponentCreated(faceletContext.getFacesContext(), panel);
218 }
219 panel.getFacets().put(Facets.LAYOUT, gridLayout);
220 if (gridLayout instanceof OnComponentPopulated) {
221 ((OnComponentPopulated) gridLayout).onComponentPopulated(faceletContext.getFacesContext(), panel);
222 }
223 }
224
225 private void setSubComponentAttributes(FaceletContext ctx, Object instance) {
226 if (instance != null) {
227 Class type = instance.getClass();
228 if (subComponentMapper == null || !subComponentLastType.equals(type)) {
229 subComponentLastType = type;
230 subComponentMapper = createSubComponentMetaRuleset(type).finish();
231 }
232 subComponentMapper.applyMetadata(ctx, instance);
233 }
234 }
235
236 protected MetaRuleset createSubComponentMetaRuleset(Class aClass) {
237 MetaRuleset metaRuleset = super.createMetaRuleset(aClass);
238
239 metaRuleset.ignore(Attributes.TIP);
240 metaRuleset.ignore("labelWidth");
241 if (SupportsMarkup.class.isAssignableFrom(aClass)) {
242 metaRuleset.addRule(SupportsMarkupRule.INSTANCE);
243 }
244 if (InputSuggest.class.isAssignableFrom(aClass)) {
245 metaRuleset.addRule(SuggestMethodRule.INSTANCE);
246 }
247 return metaRuleset;
248 }
249
250 protected MetaRuleset createMetaRuleset(Class aClass) {
251 MetaRuleset metaRuleset = super.createMetaRuleset(aClass);
252 TagAttribute [] attrs = tag.getAttributes().getAll();
253 for (int i = 0; i < attrs.length; i++) {
254 TagAttribute attr = attrs[i];
255 if (!attr.getLocalName().equals("rendered")) {
256 metaRuleset.ignore(attr.getLocalName());
257 }
258 }
259 return metaRuleset;
260 }
261 }