001/* 002 * Copyright 2017 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.core.ui.widgets.richtext; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.Collections; 021import java.util.HashMap; 022import java.util.HashSet; 023import java.util.List; 024import java.util.Map; 025import java.util.Map.Entry; 026import java.util.Set; 027 028import org.ametys.core.ui.Callable; 029import org.ametys.core.ui.ClientSideElement; 030import org.ametys.core.ui.ClientSideElement.Script; 031import org.ametys.core.ui.ClientSideElement.ScriptFile; 032import org.ametys.core.ui.widgets.richtext.RichTextConfigurationTag.EMPTY_TAG; 033import org.ametys.runtime.plugin.component.AbstractThreadSafeComponentExtensionPoint; 034 035/** 036 * Extension point for configuring the widget 'richtext' 037 */ 038public class RichTextConfigurationExtensionPoint extends AbstractThreadSafeComponentExtensionPoint<RichTextConfiguration> 039{ 040 /** The component role */ 041 public static final String ROLE = RichTextConfigurationExtensionPoint.class.getName(); 042 043 /** 044 * Converts all values to a single JSON object 045 * { 046 * "category1" : 047 * { 048 * "tags" : { 049 * "p" : { 050 * empty: "CLOSE|OPEN|REMOVE_EMPTY_CONTENT|PADDING|REMOVE_EMPTY_ATTRIBUTES", 051 * synonyms: ["div"], 052 * attributes: { 053 * "id": {}, 054 * "alt": { 055 * "default-value": "" 056 * }, 057 * "class": { 058 * "default-value": "value1", 059 * "values": ["value1", "value2"], 060 * "technical-values": [ "value1" ] // special for 'class' attribute 061 * } 062 * } 063 * } 064 * }, 065 * 066 * "styles" : { 067 * "paragraph" : { 068 * "groups": [ { 069 * "label": "Customized styles", 070 * "priority": 1, 071 * "values" : [ 072 * { 073 * "tagname": "h1", 074 * "cssclass": "big", 075 * 076 * "label": "Header 1 (big)", 077 * "description": "A big header", 078 * "buttonCSSClass": "h1-big", 079 * "buttonSmallIcon": "img/h1_16.png", 080 * "buttonMediumIcon": "img/h1_32.png", 081 * "buttonLargeIcon": "img/h1_48.png" 082 * } 083 * ] 084 * } ] 085 * } 086 * }, 087 * 088 * "css" : [ 089 * { language: false, url: "file1", debug: "all|true|false", rtl: "all|true|false" }, 090 * { language: true, default: "en", url : {"fr": "file1"} 091 * ], 092 * 093 * "validators": [ 094 * "class": { 095 * "name": "classname", 096 * "parameters": { ... } 097 * } 098 * ] 099 * 100 * "convertors": [ 101 * "class": { 102 * "name": "classname", 103 * "parameters": { ... } 104 * } 105 * ] 106 * } 107 * } 108 * @param contextualParameters Contextuals parameters transmitted by the environment. 109 * @return The non-null configuration 110 */ 111 @Callable 112 public Map<String, Object> toJSON(Map<String, Object> contextualParameters) 113 { 114 Map<String, Object> json = new HashMap<>(); 115 116 for (String extensionId : getExtensionsIds()) 117 { 118 _addExtensionToJSON(contextualParameters, json, getExtension(extensionId)); 119 } 120 121 return json; 122 } 123 124 @SuppressWarnings("unchecked") 125 private void _addExtensionToJSON(Map<String, Object> contextualParameters, Map<String, Object> json, RichTextConfiguration extension) 126 { 127 Set<String> categories = extension.getCategories(); 128 for (String category : categories) 129 { 130 if (!json.containsKey(category)) 131 { 132 Map<String, Object> jsonCategory = new HashMap<>(); 133 json.put(category, jsonCategory); 134 135 jsonCategory.put("tags", new HashMap<>()); 136 jsonCategory.put("styles", new HashMap<>()); 137 jsonCategory.put("css", new HashSet<>()); 138 jsonCategory.put("validators", new ArrayList<>()); 139 jsonCategory.put("convertors", new ArrayList<>()); 140 } 141 142 Map<String, Object> jsonCategory = (Map<String, Object>) json.get(category); 143 144 _addTagsToJSON((Map<String, Object>) jsonCategory.get("tags"), extension.getHandledTags(category, contextualParameters)); 145 _addStylesToJSON((Map<String, Map<String, List<Map<String, Object>>>>) jsonCategory.get("styles"), extension.getAvailableStyles(category, contextualParameters)); 146 _addFilesToJSON((Set<Map<String, Object>>) jsonCategory.get("css"), extension.getCSSFiles(category, contextualParameters)); 147 _addClientSideElementToJSON((List<Object>) jsonCategory.get("validators"), extension.getValidators(category, contextualParameters)); 148 _addClientSideElementToJSON((List<Object>) jsonCategory.get("convertors"), extension.getConvertors(category, contextualParameters)); 149 } 150 151 } 152 153 @SuppressWarnings("unchecked") 154 private void _addTagsToJSON(Map<String, Object> object, Collection<RichTextConfigurationTag> handledTags) 155 { 156 if (handledTags != null) 157 { 158 for (RichTextConfigurationTag handledTag : handledTags) 159 { 160 if (!object.containsKey(handledTag.getTag())) 161 { 162 Map<String, Object> jsonTag = new HashMap<>(); 163 jsonTag.put("empty", EMPTY_TAG.CLOSE); 164 jsonTag.put("synonyms", new HashSet<>()); 165 jsonTag.put("attributes", new HashMap<>()); 166 object.put(handledTag.getTag(), jsonTag); 167 } 168 169 Map<String, Object> jsonTag = (Map<String, Object>) object.get(handledTag.getTag()); 170 171 jsonTag.put("empty", handledTag.onEmptyTag().compareTo((EMPTY_TAG) jsonTag.get("empty")) < 0 ? handledTag.onEmptyTag() : (EMPTY_TAG) jsonTag.get("empty")); 172 173 ((Set<String>) jsonTag.get("synonyms")).addAll(handledTag.getSynonyms()); 174 175 Map<String, Object> attributes = (Map<String, Object>) jsonTag.get("attributes"); 176 for (RichTextConfigurationAttribute attribute : handledTag.getAttributes()) 177 { 178 boolean classAttribute = "class".equals(attribute.getName()); 179 180 if (!attributes.containsKey(attribute.getName())) 181 { 182 Map<String, Object> jsonAttribute = new HashMap<>(); 183 jsonAttribute.put("default-value", null); 184 jsonAttribute.put("values", new ArrayList<>()); 185 if (classAttribute) 186 { 187 jsonAttribute.put("technical-values", new ArrayList<>()); 188 } 189 attributes.put(attribute.getName(), jsonAttribute); 190 } 191 192 Map<String, Object> jsonAttribute = (Map<String, Object>) attributes.get(attribute.getName()); 193 jsonAttribute.put("default-value", attribute.getDefaultValue()); // Let's us take the last one 194 ((List<String>) jsonAttribute.get("values")).addAll(attribute.getAuthorizedValues()); 195 if (classAttribute) 196 { 197 ((List<String>) jsonAttribute.get("technical-values")).addAll(attribute.getTechnicalValues()); 198 } 199 } 200 } 201 } 202 } 203 204 private void _addStylesToJSON(Map<String, Map<String, List<Map<String, Object>>>> object, Map<String, Map<RichTextConfigurationStyleGroup, List<RichTextConfigurationStyle>>> availableStyles) 205 { 206 if (availableStyles != null) 207 { 208 for (Entry<String, Map<RichTextConfigurationStyleGroup, List<RichTextConfigurationStyle>>> entry : availableStyles.entrySet()) 209 { 210 if (!object.containsKey(entry.getKey())) 211 { 212 Map<String, List<Map<String, Object>>> jsonStylesGroups = new HashMap<>(); 213 jsonStylesGroups.put("groups", new ArrayList<>()); 214 object.put(entry.getKey(), jsonStylesGroups); 215 } 216 217 List<Map<String, Object>> jsonStylesGroups = object.get(entry.getKey()).get("groups"); 218 219 for (Entry<RichTextConfigurationStyleGroup, List<RichTextConfigurationStyle>> entry2 : entry.getValue().entrySet()) 220 { 221 List<Map<String, Object>> jsonStyles = new ArrayList<>(); 222 for (RichTextConfigurationStyle richTextConfigurationStyle : entry2.getValue()) 223 { 224 Map<String, Object> styleAsJSON = new HashMap<>(); 225 jsonStyles.add(styleAsJSON); 226 227 styleAsJSON.put("tagname", richTextConfigurationStyle.getTagName()); 228 styleAsJSON.put("cssclass", richTextConfigurationStyle.getClassName()); 229 230 styleAsJSON.put("label", richTextConfigurationStyle.getButtonLabel()); 231 styleAsJSON.put("description", richTextConfigurationStyle.getButtonDescription()); 232 styleAsJSON.put("buttonCSSClass", richTextConfigurationStyle.getButtonCSSClass()); 233 styleAsJSON.put("buttonSmallIcon", richTextConfigurationStyle.getButtonSmallIcon()); 234 styleAsJSON.put("buttonMediumIcon", richTextConfigurationStyle.getButtonMediumIcon()); 235 styleAsJSON.put("buttonLargeIcon", richTextConfigurationStyle.getButtonLargeIcon()); 236 } 237 238 Map<String, Object> group = new HashMap<>(); 239 group.put("label", entry2.getKey().getLabel()); 240 group.put("priority", entry2.getKey().getPriority()); 241 group.put("values", jsonStyles); 242 jsonStylesGroups.add(group); 243 } 244 } 245 } 246 } 247 248 private void _addFilesToJSON(Set<Map<String, Object>> object, List<ScriptFile> cssFiles) 249 { 250 if (cssFiles != null) 251 { 252 for (ScriptFile file : cssFiles) 253 { 254 object.add(_scriptFileToJson(file)); 255 } 256 } 257 } 258 259 private void _addClientSideElementToJSON(List<Object> list, Set<ClientSideElement> clientSideElements) 260 { 261 if (clientSideElements != null) 262 { 263 for (ClientSideElement clientSideElementn : clientSideElements) 264 { 265 List<Script> scripts = clientSideElementn.getScripts(Collections.EMPTY_MAP); 266 for (Script script : scripts) 267 { 268 Map<String, Object> jsonClientSideElement = new HashMap<>(); 269 270 Map<String, Object> jsonClass = new HashMap<>(); 271 jsonClass.put("name", script.getScriptClassname()); 272 jsonClass.put("parameters", script.getParameters()); 273 jsonClientSideElement.put("class", jsonClass); 274 275 list.add(jsonClientSideElement); 276 } 277 } 278 } 279 } 280 281 private Map<String, Object> _scriptFileToJson(ScriptFile scriptFile) 282 { 283 Map<String, Object> json = new HashMap<>(); 284 285 if (scriptFile.isLangSpecific()) 286 { 287 json.put("language", true); 288 json.put("default", scriptFile.getDefaultLang()); 289 json.put("url", scriptFile.getLangPaths()); 290 } 291 else 292 { 293 json.put("language", false); 294 json.put("url", scriptFile.getPath()); 295 json.put("rtl", scriptFile.getRtlMode()); 296 } 297 298 return json; 299 } 300}