001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020 package org.apache.myfaces.tobago.renderkit.html;
021
022 import org.apache.commons.collections.set.ListOrderedSet;
023 import org.apache.commons.lang.StringUtils;
024 import org.apache.commons.logging.Log;
025 import org.apache.commons.logging.LogFactory;
026 import org.apache.myfaces.tobago.component.ComponentUtil;
027 import org.apache.myfaces.tobago.component.SupportsMarkup;
028 import org.apache.myfaces.tobago.context.ClientProperties;
029 import org.apache.myfaces.tobago.context.Theme;
030
031 import javax.faces.application.FacesMessage;
032 import javax.faces.component.UIComponent;
033 import javax.faces.component.UIInput;
034 import javax.faces.context.FacesContext;
035 import java.io.Serializable;
036 import java.util.Iterator;
037 import java.util.Locale;
038 import java.util.Map;
039
040 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_DISABLED;
041 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_INLINE;
042 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_READONLY;
043 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_STYLE_CLASS;
044
045 public class StyleClasses implements Serializable {
046
047 private static final long serialVersionUID = 3738052927067803517L;
048
049 private static final Log LOG = LogFactory.getLog(StyleClasses.class);
050
051 public static final char SEPERATOR = '-';
052 public static final String PREFIX = "tobago" + SEPERATOR;
053 public static final String MARKUP = SEPERATOR + "markup" + SEPERATOR;
054
055 private ListOrderedSet classes;
056
057 public StyleClasses() {
058 classes = new ListOrderedSet();
059 }
060
061 private StyleClasses(StyleClasses base) {
062 this();
063 classes.addAll(base.classes);
064 }
065
066 public static StyleClasses ensureStyleClasses(UIComponent component) {
067 Map attributes = component.getAttributes();
068 StyleClasses classes = (StyleClasses) attributes.get(ATTR_STYLE_CLASS);
069 if (classes == null) {
070 classes = new StyleClasses();
071 attributes.put(ATTR_STYLE_CLASS, classes);
072 }
073 return classes;
074 }
075
076 public static StyleClasses ensureStyleClassesCopy(UIComponent component) {
077 return new StyleClasses(ensureStyleClasses(component));
078 }
079
080 @Deprecated
081 public void addFullQualifiedClass(String clazz) {
082 classes.add(clazz);
083 }
084
085 @Deprecated
086 public void removeFullQualifiedClass(String clazz) {
087 classes.remove(clazz);
088 }
089
090 public void addClass(String renderer, String sub) {
091 classes.add(nameOfClass(renderer, sub));
092 }
093
094 public void removeClass(String renderer, String sub) {
095 classes.remove(nameOfClass(renderer, sub));
096 }
097
098 private String nameOfClass(String renderer, String sub) {
099 StringBuilder builder = new StringBuilder(PREFIX);
100 builder.append(renderer);
101 builder.append(SEPERATOR);
102 builder.append(sub);
103 return builder.toString();
104 }
105
106 public void addMarkupClass(String renderer, String markup) {
107 addMarkupClass(renderer, null, markup);
108 }
109
110 public void removeMarkupClass(String renderer, String markup) {
111 removeMarkupClass(renderer, null, markup);
112 }
113
114 public void addMarkupClass(String renderer, String sub, String markup) {
115 classes.add(nameOfMarkupClass(renderer, sub, markup));
116 }
117
118 public void removeMarkupClass(String renderer, String sub, String markup) {
119 classes.remove(nameOfMarkupClass(renderer, sub, markup));
120 }
121
122 private String nameOfMarkupClass(String renderer, String sub, String markup) {
123 StringBuilder builder = new StringBuilder(PREFIX);
124 builder.append(renderer);
125 if (sub != null) {
126 builder.append(SEPERATOR);
127 builder.append(sub);
128 }
129 builder.append(MARKUP);
130 builder.append(markup);
131 return builder.toString();
132 }
133
134 public void addMarkupClass(UIComponent component, String rendererName) {
135 if (component instanceof SupportsMarkup) {
136 addMarkupClass((SupportsMarkup) component, rendererName, null);
137 }
138 }
139
140 public void addMarkupClass(SupportsMarkup supportsMarkup, String rendererName, String sub) {
141 for (String markup : supportsMarkup.getMarkup()) {
142 if (!StringUtils.isBlank(markup)) {
143 Theme theme = ClientProperties.getInstance(FacesContext.getCurrentInstance().getViewRoot()).getTheme();
144 if (theme.getRenderersConfig().isMarkupSupported(rendererName, markup)) {
145 addMarkupClass(rendererName, sub, markup);
146 } else if (!"none".equals(markup)) {
147 LOG.warn("Ignoring unknown markup='" + markup + "' for rendererName='" + rendererName + "'");
148 }
149 }
150 }
151 }
152
153 public void addAspectClass(String renderer, Aspect aspect) {
154 classes.add(nameOfAspectClass(renderer, aspect));
155 }
156
157 public void removeAspectClass(String renderer, Aspect aspect) {
158 classes.remove(nameOfAspectClass(renderer, aspect));
159 }
160
161 private String nameOfAspectClass(String renderer, Aspect aspect) {
162 StringBuilder builder = new StringBuilder(PREFIX);
163 builder.append(renderer);
164 builder.append(aspect);
165 return builder.toString();
166 }
167
168
169 public void addAspectClass(String renderer, String sub, Aspect aspect) {
170 classes.add(nameOfAspectClass(renderer, sub, aspect));
171 }
172
173 public void removeAspectClass(String renderer, String sub, Aspect aspect) {
174 classes.remove(nameOfAspectClass(renderer, sub, aspect));
175 }
176
177 private String nameOfAspectClass(String renderer, String sub, Aspect aspect) {
178 StringBuilder builder = new StringBuilder(PREFIX);
179 builder.append(renderer);
180 builder.append(SEPERATOR);
181 builder.append(sub);
182 builder.append(aspect);
183 return builder.toString();
184 }
185
186 public void addClasses(StyleClasses styleClasses) {
187 for (String clazz : (Iterable<String>) styleClasses.classes) {
188 classes.add(clazz);
189 }
190 }
191
192 public void removeClass(String clazz) {
193 classes.remove(clazz);
194 }
195
196 public void removeTobagoClasses(String rendererName) {
197 for (Iterator i = classes.iterator(); i.hasNext();) {
198 String clazz = (String) i.next();
199 if (clazz.startsWith(PREFIX + rendererName)) {
200 i.remove();
201 }
202 }
203 }
204
205 public void updateClassAttributeAndMarkup(UIComponent component, String rendererName) {
206 updateClassAttribute(component, rendererName);
207 addMarkupClass(component, rendererName);
208 }
209
210 public void updateClassAttribute(UIComponent component, String rendererName) {
211 // first remove old tobago-<rendererName>-<type> classes from class-attribute
212 removeTobagoClasses(rendererName);
213
214 addAspectClass(rendererName, Aspect.DEFAULT);
215 if (ComponentUtil.getBooleanAttribute(component, ATTR_DISABLED)) {
216 addAspectClass(rendererName, Aspect.DISABLED);
217 }
218 if (ComponentUtil.getBooleanAttribute(component, ATTR_READONLY)) {
219 addAspectClass(rendererName, Aspect.READONLY);
220 }
221 if (ComponentUtil.getBooleanAttribute(component, ATTR_INLINE)) {
222 addAspectClass(rendererName, Aspect.INLINE);
223 }
224 FacesMessage.Severity severity = ComponentUtil.getMaximumSeverity(component);
225 if (severity != null) {
226 if (severity.equals(FacesMessage.SEVERITY_FATAL)) {
227 addMarkupClass(rendererName, "fatal");
228 addAspectClass(rendererName, Aspect.ERROR);
229 } else if (severity.equals(FacesMessage.SEVERITY_ERROR)) {
230 addMarkupClass(rendererName, "error");
231 addAspectClass(rendererName, Aspect.ERROR);
232 } else if (severity.equals(FacesMessage.SEVERITY_WARN)) {
233 addMarkupClass(rendererName, "warn");
234 } else if (severity.equals(FacesMessage.SEVERITY_INFO)) {
235 addMarkupClass(rendererName, "info");
236 } else {
237 assert false : "Ordinal constants may be wrong";
238 }
239 }
240 if (component instanceof UIInput) {
241 UIInput input = (UIInput) component;
242 if (input.isRequired()) {
243 addAspectClass(rendererName, Aspect.REQUIRED);
244 }
245 }
246 }
247
248 public boolean isEmpty() {
249 return classes.isEmpty();
250 }
251
252 @Override
253 public String toString() {
254 if (classes.isEmpty()) {
255 return null;
256 }
257 StringBuilder buffer = new StringBuilder(32);
258 for (Iterator i = classes.iterator(); i.hasNext();) {
259 String clazz = (String) i.next();
260 buffer.append(clazz);
261 if (i.hasNext()) {
262 buffer.append(' ');
263 }
264 }
265 return buffer.toString();
266 }
267
268 public enum Aspect {
269
270 DEFAULT,
271 DISABLED,
272 READONLY,
273 INLINE,
274 ERROR,
275 REQUIRED;
276
277 private String aspect;
278
279 Aspect() {
280 aspect = '-' + name().toLowerCase(Locale.ENGLISH);
281 }
282
283 @Override
284 public String toString() {
285 return aspect;
286 }
287 }
288 }