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<>());
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        String defaultInlineEditor = styleConfiguration.getAttribute("defaultInlineEditor", null);
122        List<String> removeInlineEditor = List.of(StringUtils.split(styleConfiguration.getAttribute("removeInlineEditor", ""), " ,"));
123        
124        Set<String> boCSSFiles = new LinkedHashSet<>();
125        Set<String> inlineEditorCSSFiles = new LinkedHashSet<>();
126        
127        for (Configuration configuration : styleConfiguration.getChild("import").getChildren("button"))
128        {
129            boCSSFiles.add(_getImport(configuration, contextParameters));
130            // adding null will be ignored later
131        }
132        for (Configuration configuration : styleConfiguration.getChild("import").getChildren("inline-editor"))
133        {
134            inlineEditorCSSFiles.add(_getImport(configuration, contextParameters));
135            // adding null will be ignored later
136        }
137        
138        List<Style> styleList = new ArrayList<>();
139        for (Configuration styleConf : styleConfiguration.getChildren("style"))
140        {
141            Style style = _configureStyle(styleConf, defaultCatalogue, defaultIcons, contextParameters);
142            styleList.add(style);
143        }
144        
145        return new StyleCategory(boCSSFiles, inlineEditorCSSFiles, styleList, defaultInlineEditor, removeInlineEditor);
146    }
147    
148    /**
149     * Determine an url from a configuration node.
150     * @param configuration Read the optional plugin attribute and concatenate it to the value of the node. Can be null
151     * @param contextParameters Contextuals parameters transmitted by the environment.
152     * @return The non-null path to the plugin resource
153     */
154    protected String _getImport(Configuration configuration, Map<String, Object> contextParameters)
155    {
156        String boPlugin = configuration.getAttribute("plugin", null);
157        
158        String boFileLocation;
159        if (StringUtils.isNotBlank(boPlugin))
160        {
161            boFileLocation = "/plugins/" + boPlugin + "/resources/";
162        }
163        else
164        {
165            boFileLocation = "/param_resources/edition-styles/";
166        }
167        
168        String uri = configuration.getValue(null);
169        return StringUtils.isBlank(uri) ? null : boFileLocation + uri;
170    }
171    
172    /**
173     * Configure a style
174     * @param configuration The style configuration
175     * @param defaultCatalogue The default i18n catalogue to use
176     * @param defaultIcons the path to the button's default icons in small, medium and large size
177     * @param contextParameters Contextual parameters transmitted by the environment.
178     * @return The style configured
179     * @throws ConfigurationException If the configuration is incorrect
180     */
181    protected Style _configureStyle(Configuration configuration, String defaultCatalogue, String[] defaultIcons, Map<String, Object> contextParameters) throws ConfigurationException
182    {
183        String buttonSmallIcon = defaultIcons != null ? defaultIcons[0] : null;
184        String buttonMediumIcon = defaultIcons != null ? defaultIcons[1] : null;
185        String buttonLargeIcon = defaultIcons != null ? defaultIcons[2] : null;
186        I18nizableText buttonLabel;
187        I18nizableText buttonDescription;
188        String buttonCSSClass;
189
190        Configuration iconSmallConf = configuration.getChild("button").getChild("icon-small", false);
191        if (iconSmallConf != null)
192        {
193            buttonSmallIcon = _getImport(iconSmallConf, contextParameters);
194        }
195        
196        Configuration iconMediumConf = configuration.getChild("button").getChild("icon-medium", false);
197        if (iconMediumConf == null)
198        {
199            // Try to look for "icon" if no "icon-medium".
200            iconMediumConf = configuration.getChild("button").getChild("icon", false);
201        }
202        
203        if (iconMediumConf != null)
204        {
205            buttonMediumIcon = _getImport(iconMediumConf, contextParameters);
206        }
207        
208        Configuration iconLargeConf = configuration.getChild("button").getChild("icon-large", false);
209        if (iconLargeConf == null)
210        {
211            // Try to look for "icon" if no "icon-large".
212            iconLargeConf = configuration.getChild("button").getChild("icon", false);
213        }
214        
215        if (iconLargeConf != null)
216        {
217            buttonLargeIcon = _getImport(iconLargeConf, contextParameters);
218        }
219        
220        Configuration labelConf = configuration.getChild("button").getChild("label");
221        if (labelConf.getAttributeAsBoolean("i18n", false))
222        {
223            buttonLabel = new I18nizableText(defaultCatalogue, labelConf.getValue());
224        }
225        else
226        {
227            buttonLabel = new I18nizableText(labelConf.getValue());
228        }
229
230        Configuration descriptionConf = configuration.getChild("button").getChild("description");
231        if (descriptionConf.getAttributeAsBoolean("i18n", false))
232        {
233            buttonDescription = new I18nizableText(defaultCatalogue, descriptionConf.getValue());
234        }
235        else
236        {
237            buttonDescription = new I18nizableText(descriptionConf.getValue());
238        }
239        
240        buttonCSSClass = configuration.getChild("button").getChild("cssclass").getValue("");
241        
242        String inlineEditorRender = configuration.getChild("inline-editor").getValue();
243        
244        return new Style(buttonLabel, buttonDescription, buttonSmallIcon, buttonMediumIcon, buttonLargeIcon, buttonCSSClass, inlineEditorRender);
245    }
246    
247    @Override
248    public Set<String> getCategories()
249    {
250        return Set.of("content");
251    }
252
253    @Override
254    public StyleCategory getPara(String category, Map<String, Object> contextualParameters)
255    {
256        return "content".equals(category) ? _paraStyleCategory : null;
257    }
258    
259    @Override
260    public StyleCategory getTable(String category, Map<String, Object> contextualParameters)
261    {
262        return  "content".equals(category) ? _tableStyleCategory : null;
263    }
264    
265    @Override
266    public StyleCategory getLink(String category, Map<String, Object> contextualParameters)
267    {
268        return "content".equals(category) ? _linkStyleCategory : null;
269    }
270    
271    @Override
272    public StyleCategory getImage(String category, Map<String, Object> contextualParameters)
273    {
274        return  "content".equals(category) ? _imageStyleCategory : null;
275    }
276    
277    @Override
278    public StyleCategory getUnorderedList(String category, Map<String, Object> contextualParameters)
279    {
280        return  "content".equals(category) ? _ulStyleCategory : null;
281    }
282    
283    @Override
284    public StyleCategory getOrderedList(String category, Map<String, Object> contextualParameters)
285    {
286        return  "content".equals(category) ? _olStyleCategory : null;
287    }
288}