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 }