001/* 002 * Copyright 2011 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.skinfactory.parameters; 017 018import java.io.File; 019import java.io.FileInputStream; 020import java.io.FileWriter; 021import java.io.IOException; 022import java.io.InputStream; 023import java.io.Writer; 024import java.util.ArrayList; 025import java.util.HashMap; 026import java.util.List; 027import java.util.Map; 028import java.util.regex.Matcher; 029import java.util.regex.Pattern; 030 031import org.apache.cocoon.xml.AttributesImpl; 032import org.apache.cocoon.xml.XMLUtils; 033import org.apache.commons.io.IOUtils; 034import org.xml.sax.ContentHandler; 035import org.xml.sax.SAXException; 036 037import org.ametys.runtime.i18n.I18nizableText; 038import org.ametys.web.skin.SkinModel; 039 040/** 041 * Implementation of {@link AbstractSkinParameter} for a CSS property 042 */ 043public class CSSParameter extends AbstractSkinParameter 044{ 045 private final List<File> _cssFiles; 046 private final String _cssProperty; 047 private final String _defaultValue; 048 049 /** 050 * Constructor 051 * @param id the unique id 052 * @param label the label 053 * @param description the description 054 * @param cssFile the css file 055 * @param cssProperty the css property 056 * @param defaultValue the default value 057 */ 058 public CSSParameter(String id, I18nizableText label, I18nizableText description, File cssFile, String cssProperty, String defaultValue) 059 { 060 super(id, label, description); 061 _cssFiles = new ArrayList<>(); 062 _cssFiles.add(cssFile); 063 _cssProperty = cssProperty; 064 _defaultValue = defaultValue; 065 } 066 067 /** 068 * Constructor 069 * @param id the unique id 070 * @param label the label 071 * @param description the description 072 * @param cssFiles the css files 073 * @param cssProperty the css property 074 * @param defaultValue the default value 075 */ 076 public CSSParameter(String id, I18nizableText label, I18nizableText description, List<File> cssFiles, String cssProperty, String defaultValue) 077 { 078 super(id, label, description); 079 _cssFiles = cssFiles; 080 _cssProperty = cssProperty; 081 _defaultValue = defaultValue; 082 } 083 084 @Override 085 public SkinParameterType getType() 086 { 087 return SkinParameterType.CSS; 088 } 089 090 /** 091 * Get the CSS files path 092 * @return the CSS files path 093 */ 094 public List<File> getCSSFiles () 095 { 096 return _cssFiles; 097 } 098 099 /** 100 * Add a CSS file 101 * @param cssFile The CSS file 102 */ 103 public void addCSSFile (File cssFile) 104 { 105 for (File f : _cssFiles) 106 { 107 if (f.getPath().equals(cssFile.getPath())) 108 { 109 // The file is already registered 110 return; 111 } 112 } 113 _cssFiles.add(cssFile); 114 } 115 116 /** 117 * Get the CSS property 118 * @return the CSS file path 119 */ 120 public String getCSSProperty () 121 { 122 return _cssProperty; 123 } 124 125 @Override 126 public void apply(File tempDir, File modelDir, Object value, String lang) throws SkinParameterException 127 { 128 for (File file : _cssFiles) 129 { 130 String relPath = file.getAbsolutePath().substring(modelDir.getAbsolutePath().length() + 1); 131 File cssFile = new File (tempDir, relPath); 132 String string = cssFileToString(cssFile); 133 134 Pattern pattern = getCSSPattern(); 135 Matcher matcher = pattern.matcher(string); 136 137 try (Writer writer = new FileWriter(cssFile)) 138 { 139 int startIndex = 0; 140 while (matcher.find()) 141 { 142 int propertyStart = matcher.start(2); 143 144 String beforeValue = string.substring(startIndex, propertyStart); 145 String oldValue = string.substring(propertyStart, matcher.end(2)); 146 IOUtils.write(beforeValue, writer); 147 148 IOUtils.write((String) value + (oldValue.endsWith(" ") ? " " : ""), writer); 149 IOUtils.write(string.substring(matcher.end(2), matcher.end(3)), writer); 150 151 startIndex = matcher.end(3); 152 } 153 154 IOUtils.write(string.substring(startIndex), writer); 155 } 156 catch (IOException e) 157 { 158 throw new SkinParameterException ("Unable to apply css parameter '" + getId() + "'", e); 159 } 160 } 161 } 162 163 /** 164 * Get the CSS pattern 165 * @return The CSS pattern 166 */ 167 protected Pattern getCSSPattern () 168 { 169 return Pattern.compile("\\s*([^,:\\s]*)\\s*:\\s*([^:;!]*)\\s*(?:!important)?\\s*\\/\\*\\s*AMETYS\\s*\\(\\s*\"(" + getId() + ")\"\\s*(?:,\\s*([^,\"\\s]+|\"[^\"]*\")\\s*)?(?:,\\s*([^,\"\\s]+|\"[^\"]*\")\\s*)?\\)\\s*\\*\\/\\s*;\\s*?", Pattern.MULTILINE); 170 } 171 172 /** 173 * Get the css file input stream as String 174 * @param cssFile The css file 175 * @return The css file content as String 176 * @throws SkinParameterException if the css file was not parsable 177 */ 178 protected String cssFileToString (File cssFile) throws SkinParameterException 179 { 180 try (InputStream is = new FileInputStream(cssFile)) 181 { 182 return org.apache.commons.io.IOUtils.toString(is); 183 } 184 catch (IOException e) 185 { 186 throw new SkinParameterException ("Unable to parse file '" + cssFile.getName() + "'", e); 187 } 188 } 189 190 @Override 191 public void toSAX(ContentHandler contentHandler, String modelName) throws SAXException 192 { 193 AttributesImpl attrs = new AttributesImpl(); 194 attrs.addCDATAAttribute("id", getId()); 195 attrs.addCDATAAttribute("type", SkinParameterType.CSS.name().toLowerCase()); 196 197 XMLUtils.startElement(contentHandler, "parameter", attrs); 198 199 getLabel().toSAX(contentHandler, "label"); 200 getDescription().toSAX(contentHandler, "description"); 201 XMLUtils.createElement(contentHandler, "property", getCSSProperty()); 202 203 XMLUtils.endElement(contentHandler, "parameter"); 204 } 205 206 @Override 207 public Map<String, Object> toJson(String modelName) 208 { 209 Map<String, Object> jsonObject = new HashMap<>(); 210 211 jsonObject.put("id", getId()); 212 jsonObject.put("type", SkinParameterType.CSS.name().toLowerCase()); 213 jsonObject.put("label", getLabel()); 214 jsonObject.put("description", getDescription()); 215 jsonObject.put("property", getCSSProperty()); 216 217 return jsonObject; 218 } 219 220 @Override 221 public String getDefaultValue(SkinModel model) 222 { 223 return _defaultValue; 224 } 225 226 @Override 227 public String getDefaultValue(SkinModel model, String lang) 228 { 229 return getDefaultValue(model); 230 } 231}