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