001/*
002 *  Copyright 2010 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.cms.clientsideelement.styles;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.LinkedHashSet;
021import java.util.List;
022import java.util.Map;
023import java.util.Set;
024
025import org.apache.avalon.framework.configuration.Configurable;
026import org.apache.avalon.framework.configuration.Configuration;
027import org.apache.avalon.framework.configuration.ConfigurationException;
028import org.apache.avalon.framework.logger.AbstractLogEnabled;
029import org.apache.avalon.framework.service.ServiceException;
030import org.apache.avalon.framework.service.ServiceManager;
031import org.apache.avalon.framework.service.Serviceable;
032import org.apache.commons.lang3.StringUtils;
033import org.apache.excalibur.source.SourceResolver;
034
035import org.ametys.runtime.i18n.I18nizableText;
036import org.ametys.runtime.plugin.component.PluginAware;
037
038/**
039 * This implementation is based upon a static configuration.
040 * FIXME For now, this implementation only supports styles for contents ('content' category). It cannot provided styles for other richtext 
041 */
042public class StaticHTMLEditorContentStyle extends AbstractLogEnabled implements HTMLEditorStyle, Configurable, Serviceable, PluginAware
043{
044    /** Default icons style for table */
045    protected static final String[] TABLE_DEFAULT_ICONS = new String[] {"/plugins/cms/resources/img/content/edition/table/Table_Border_16.png", "/plugins/cms/resources/img/content/edition/table/Table_Border_32.png", "/plugins/cms/resources/img/content/edition/table/Table_Border_32.png"};
046    /** Default icons style for link */
047    protected static final String[] LINK_DEFAULT_ICONS = new String[] {"/plugins/cms/resources/img/content/edition/link/Style_Normal_16.png", "/plugins/cms/resources/img/content/edition/link/Style_Normal_32.png", "/plugins/cms/resources/img/content/edition/link/Style_Normal_32.png"};
048    /** Default icons style for image */
049    protected static final String[] IMAGE_DEFAULT_ICONS = new String[] {"/plugins/cms/resources/img/content/edition/image/Image_Style_Border_16.png", "/plugins/cms/resources/img/content/edition/link/Style_Normal_32.png", "/plugins/cms/resources/img/content/edition/link/Style_Normal_32.png"};
050    /** Default icons style for unordered list */
051    protected static final String[] UL_DEFAULT_ICONS = new String[] {"/plugins/cms/resources/img/content/edition/list/disc_16.png", "/plugins/cms/resources/img/content/edition/link/Style_Normal_32.png", "/plugins/cms/resources/img/content/edition/link/Style_Normal_32.png"};
052    /** Default icons style for ordered list */
053    protected static final String[] OL_DEFAULT_ICONS = new String[] {"/plugins/cms/resources/img/content/edition/list/decimal_16.png", "/plugins/cms/resources/img/content/edition/link/Style_Normal_32.png", "/plugins/cms/resources/img/content/edition/link/Style_Normal_32.png"};
054    
055    /** Excalibur source resolver */
056    protected SourceResolver _resolver;
057    /** The values of the file */
058    protected StyleCategory _paraStyleCategory;
059    /** The values of the file */
060    protected StyleCategory _tableStyleCategory;
061    /** The values of the file */
062    protected StyleCategory _linkStyleCategory;
063    /** The values of the file */
064    protected StyleCategory _imageStyleCategory;
065    /** The values of the file */
066    protected StyleCategory _ulStyleCategory;
067    /** The values of the file */
068    protected StyleCategory _olStyleCategory;
069    /** The plugin that declared the instance */
070    protected String _pluginName;
071    /** The feature that declared the instance */
072    protected String _featureName;
073    
074    @Override
075    public void service(ServiceManager manager) throws ServiceException
076    {
077        _resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
078    }
079    
080    @Override
081    public void setPluginInfo(String pluginName, String featureName, String id)
082    {
083        _pluginName = pluginName;
084        _featureName = featureName;
085    }
086    
087    @Override
088    public void configure(Configuration configuration) throws ConfigurationException
089    {
090        _configure(configuration, "param.edition-styles", new HashMap<String, Object>());
091    }
092    
093    /**
094     * Configure this instance upon a configuration
095     * @param configuration The configuration
096     * @param defaultCatalogue The default i18n catalogue to use
097     * @param contextParameters Contextuals parameters transmitted by the environment.
098     * @throws ConfigurationException If the configuration is incorrect
099     */
100    protected void _configure(Configuration configuration, String defaultCatalogue, Map<String, Object> contextParameters) throws ConfigurationException
101    {
102        _paraStyleCategory = _configureStyleCategory(configuration.getChild("para"), defaultCatalogue, null, contextParameters);
103        _tableStyleCategory = _configureStyleCategory(configuration.getChild("table"), defaultCatalogue, TABLE_DEFAULT_ICONS, contextParameters);
104        _linkStyleCategory = _configureStyleCategory(configuration.getChild("link"), defaultCatalogue, LINK_DEFAULT_ICONS, contextParameters);
105        _imageStyleCategory = _configureStyleCategory(configuration.getChild("image"), defaultCatalogue, IMAGE_DEFAULT_ICONS, contextParameters);
106        _ulStyleCategory = _configureStyleCategory(configuration.getChild("unorderedlist"), defaultCatalogue, UL_DEFAULT_ICONS, contextParameters);
107        _olStyleCategory = _configureStyleCategory(configuration.getChild("orderedlist"), defaultCatalogue, OL_DEFAULT_ICONS, contextParameters);
108    }
109    
110    /**
111     * Configure this instance upon the style part of a configuration
112     * @param styleConfiguration The style part of the configuration
113     * @param defaultCatalogue The default i18n catalogue to use
114     * @param defaultIcons the path to the button's default icons in small, medium and large size
115     * @param contextParameters Contextuals parameters transmitted by the environment.
116     * @return The style that represents the values read
117     * @throws ConfigurationException If the configuration is incorrect
118     */
119    protected StyleCategory _configureStyleCategory(Configuration styleConfiguration, String defaultCatalogue, String[] defaultIcons, Map<String, Object> contextParameters) throws ConfigurationException
120    {
121        Set<String> boCSSFiles = new LinkedHashSet<>();
122        Set<String> inlineEditorCSSFiles = new LinkedHashSet<>();
123        
124        for (Configuration configuration : styleConfiguration.getChild("import").getChildren("button"))
125        {
126            boCSSFiles.add(_getImport(configuration, contextParameters));
127            // adding null will be ignored later
128        }
129        for (Configuration configuration : styleConfiguration.getChild("import").getChildren("inline-editor"))
130        {
131            inlineEditorCSSFiles.add(_getImport(configuration, contextParameters));
132            // adding null will be ignored later
133        }
134        
135        List<Style> styleList = new ArrayList<>();
136        for (Configuration styleConf : styleConfiguration.getChildren("style"))
137        {
138            Style style = _configureStyle(styleConf, defaultCatalogue, defaultIcons, contextParameters);
139            styleList.add(style);
140        }
141        
142        return new StyleCategory(boCSSFiles, inlineEditorCSSFiles, styleList);
143    }
144    
145    /**
146     * Determine an url from a configuration node.
147     * @param configuration Read the optional plugin attribute and concatenate it to the value of the node. Can be null
148     * @param contextParameters Contextuals parameters transmitted by the environment.
149     * @return The non-null path to the plugin resource
150     */
151    protected String _getImport(Configuration configuration, Map<String, Object> contextParameters)
152    {
153        String boPlugin = configuration.getAttribute("plugin", null);
154        
155        String boFileLocation;
156        if (StringUtils.isNotBlank(boPlugin))
157        {
158            boFileLocation = "/plugins/" + boPlugin + "/resources/";
159        }
160        else
161        {
162            boFileLocation = "/param_resources/edition-styles/";
163        }
164        
165        String uri = configuration.getValue(null);
166        return StringUtils.isBlank(uri) ? null : boFileLocation + uri;
167    }
168    
169    /**
170     * Configure a style
171     * @param configuration The style configuration
172     * @param defaultCatalogue The default i18n catalogue to use
173     * @param defaultIcons the path to the button's default icons in small, medium and large size
174     * @param contextParameters Contextual parameters transmitted by the environment.
175     * @return The style configured
176     * @throws ConfigurationException If the configuration is incorrect
177     */
178    protected Style _configureStyle(Configuration configuration, String defaultCatalogue, String[] defaultIcons, Map<String, Object> contextParameters) throws ConfigurationException
179    {
180        String buttonSmallIcon = defaultIcons != null ? defaultIcons[0] : null;
181        String buttonMediumIcon = defaultIcons != null ? defaultIcons[1] : null;
182        String buttonLargeIcon = defaultIcons != null ? defaultIcons[2] : null;
183        I18nizableText buttonLabel;
184        I18nizableText buttonDescription;
185        String buttonCSSClass;
186
187        Configuration iconSmallConf = configuration.getChild("button").getChild("icon-small", false);
188        if (iconSmallConf != null)
189        {
190            buttonSmallIcon = _getImport(iconSmallConf, contextParameters);
191        }
192        
193        Configuration iconMediumConf = configuration.getChild("button").getChild("icon-medium", false);
194        if (iconMediumConf == null)
195        {
196            // Try to look for "icon" if no "icon-medium".
197            iconMediumConf = configuration.getChild("button").getChild("icon", false);
198        }
199        
200        if (iconMediumConf != null)
201        {
202            buttonMediumIcon = _getImport(iconMediumConf, contextParameters);
203        }
204        
205        Configuration iconLargeConf = configuration.getChild("button").getChild("icon-large", false);
206        if (iconLargeConf == null)
207        {
208            // Try to look for "icon" if no "icon-large".
209            iconLargeConf = configuration.getChild("button").getChild("icon", false);
210        }
211        
212        if (iconLargeConf != null)
213        {
214            buttonLargeIcon = _getImport(iconLargeConf, contextParameters);
215        }
216        
217        Configuration labelConf = configuration.getChild("button").getChild("label");
218        if (labelConf.getAttributeAsBoolean("i18n", false))
219        {
220            buttonLabel = new I18nizableText(defaultCatalogue, labelConf.getValue());
221        }
222        else 
223        {
224            buttonLabel = new I18nizableText(labelConf.getValue());
225        }
226
227        Configuration descriptionConf = configuration.getChild("button").getChild("description");
228        if (descriptionConf.getAttributeAsBoolean("i18n", false))
229        {
230            buttonDescription = new I18nizableText(defaultCatalogue, descriptionConf.getValue());
231        }
232        else 
233        {
234            buttonDescription = new I18nizableText(descriptionConf.getValue());
235        }
236        
237        buttonCSSClass = configuration.getChild("button").getChild("cssclass").getValue("");
238        
239        String inlineEditorRender = configuration.getChild("inline-editor").getValue();
240        
241        return new Style(buttonLabel, buttonDescription, buttonSmallIcon, buttonMediumIcon, buttonLargeIcon, buttonCSSClass, inlineEditorRender);
242    }
243    
244    @Override
245    public Set<String> getCategories()
246    {
247        return Set.of("content");
248    }
249
250    @Override
251    public StyleCategory getPara(String category, Map<String, Object> contextualParameters)
252    {
253        return "content".equals(category) ? _paraStyleCategory : null;
254    }
255    
256    @Override
257    public StyleCategory getTable(String category, Map<String, Object> contextualParameters)
258    {
259        return  "content".equals(category) ? _tableStyleCategory : null;
260    }
261    
262    @Override
263    public StyleCategory getLink(String category, Map<String, Object> contextualParameters)
264    {
265        return "content".equals(category) ? _linkStyleCategory : null;
266    }
267    
268    @Override
269    public StyleCategory getImage(String category, Map<String, Object> contextualParameters)
270    {
271        return  "content".equals(category) ? _imageStyleCategory : null;
272    }
273    
274    @Override
275    public StyleCategory getUnorderedList(String category, Map<String, Object> contextualParameters)
276    {
277        return  "content".equals(category) ? _ulStyleCategory : null;
278    }
279    
280    @Override
281    public StyleCategory getOrderedList(String category, Map<String, Object> contextualParameters)
282    {
283        return  "content".equals(category) ? _olStyleCategory : null;
284    }
285}