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 }