1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.dam.app.ui.field.factory;
35
36 import info.magnolia.dam.api.Asset;
37 import info.magnolia.dam.api.AssetProviderRegistry;
38 import info.magnolia.dam.api.DamException;
39 import info.magnolia.dam.api.ItemKey;
40 import info.magnolia.dam.jcr.DamConstants;
41 import info.magnolia.i18nsystem.SimpleTranslator;
42 import info.magnolia.link.LinkException;
43 import info.magnolia.link.LinkUtil;
44 import info.magnolia.objectfactory.Components;
45 import info.magnolia.ui.api.app.AppController;
46 import info.magnolia.ui.api.app.ChooseDialogCallback;
47 import info.magnolia.ui.api.context.UiContext;
48 import info.magnolia.ui.api.i18n.I18NAuthoringSupport;
49 import info.magnolia.ui.form.field.definition.RichTextFieldDefinition;
50 import info.magnolia.ui.form.field.factory.RichTextFieldFactory;
51 import info.magnolia.ui.vaadin.integration.contentconnector.ContentConnector;
52 import info.magnolia.ui.vaadin.integration.jcr.JcrNodeItemId;
53 import info.magnolia.ui.vaadin.richtext.MagnoliaRichTextField;
54 import info.magnolia.ui.vaadin.richtext.MagnoliaRichTextFieldConfig;
55
56 import java.util.Locale;
57 import java.util.regex.Matcher;
58 import java.util.regex.Pattern;
59
60 import javax.inject.Inject;
61
62 import org.apache.commons.lang3.StringUtils;
63
64 import com.google.gson.Gson;
65 import com.vaadin.data.Item;
66 import com.vaadin.data.util.converter.Converter;
67 import com.vaadin.server.VaadinService;
68 import com.vaadin.ui.Field;
69 import com.vaadin.ui.UI;
70
71
72
73
74
75
76 public class AssetsEnabledRichTextFieldFactory extends RichTextFieldFactory {
77
78 private static final String FILE_BROWSER_PLUGIN = "magnoliaFileBrowser";
79
80 private static final String FILE_BROWSER_PLUGIN_CHOOSE_ASSET_EVENT = "chooseAsset";
81
82 public static final String ASSET_CHOSEN_EVENT_ID = "assetChosen";
83
84 private AssetProviderRegistry assetProviderRegistry;
85
86 private static final Pattern IMAGE_PATTERN = Pattern.compile(
87 "(<img " +
88 "[^>]*" +
89 "src[ ]*=[ ]*\")" +
90 "([^\"]*)" +
91 "(\"" +
92 "[^>]*" +
93 ">)");
94
95 @Inject
96 public AssetsEnabledRichTextFieldFactory(RichTextFieldDefinition definition, Item relatedFieldItem, UiContext uiContext, I18NAuthoringSupport i18nAuthoringSupport, AppController appController, SimpleTranslator i18n, AssetProviderRegistry assetProviderRegistry) {
97 super(definition, relatedFieldItem, uiContext, i18nAuthoringSupport, appController, i18n);
98 this.assetProviderRegistry = assetProviderRegistry;
99 }
100
101
102
103
104 @Deprecated
105 public AssetsEnabledRichTextFieldFactory(RichTextFieldDefinition definition, Item relatedFieldItem, AppController appController, UiContext uiContext, SimpleTranslator i18n, AssetProviderRegistry assetProviderRegistry) {
106 this(definition, relatedFieldItem, uiContext, Components.getComponent(I18NAuthoringSupport.class), appController, i18n, assetProviderRegistry);
107 }
108
109
110
111
112 @Deprecated
113 public AssetsEnabledRichTextFieldFactory(RichTextFieldDefinition definition, Item relatedFieldItem, AppController appController, UiContext uiContext, SimpleTranslator i18n, AssetProviderRegistry assetProviderRegistry, ContentConnector contentConnector) {
114 this(definition, relatedFieldItem, uiContext, Components.getComponent(I18NAuthoringSupport.class), appController, i18n, assetProviderRegistry);
115 }
116
117 @Override
118 protected Field<String> createFieldComponent() {
119 MagnoliaRichTextField field = (MagnoliaRichTextField) super.createFieldComponent();
120 if (definition.isImages() || StringUtils.isNotBlank(definition.getConfigJsFile())) {
121
122 field.addListener(new MagnoliaRichTextField.PluginListener() {
123 @Override
124 public void onPluginEvent(String eventName, String value) {
125 if (eventName.equals(FILE_BROWSER_PLUGIN_CHOOSE_ASSET_EVENT)) {
126 UI.getCurrent().addStyleName("ui-overlapping-ck-editor");
127 chooseAsset();
128 }
129 }
130 });
131
132 field.setConverter(new Converter<String, String>() {
133 @Override
134 public String convertToModel(String value, Class<? extends String> targetType, Locale locale) throws ConversionException {
135 return LinkUtil.convertAbsoluteLinksToUUIDs(value);
136 }
137
138 @Override
139 public String convertToPresentation(String value, Class<? extends String> targetType, Locale locale) throws ConversionException {
140 if (value != null) {
141
142
143 try {
144 Matcher matcher = IMAGE_PATTERN.matcher(value);
145 while (matcher.find()) {
146 value = value.replace(matcher.group(), LinkUtil.convertLinksFromUUIDPattern(matcher.group()));
147 }
148 return value;
149 } catch (LinkException e) {
150 return StringUtils.EMPTY;
151 }
152 }
153 return StringUtils.EMPTY;
154 }
155
156 @Override
157 public Class<String> getModelType() {
158 return String.class;
159 }
160
161 @Override
162 public Class<String> getPresentationType() {
163 return String.class;
164 }
165 });
166 }
167 return field;
168 }
169
170 private void chooseAsset() {
171 appController.openChooseDialog("assets", uiContext, null, new ChooseDialogCallback() {
172 @Override
173 public void onItemChosen(String actionName, Object chosenValue) {
174 UI.getCurrent().removeStyleName("ui-overlapping-ck-editor");
175
176 Gson gson = new Gson();
177 String eventJson = "{}";
178 Asset asset;
179
180 try {
181 if (!(chosenValue instanceof JcrNodeItemId)) {
182 return;
183 }
184 asset = assetProviderRegistry.getProviderById(DamConstants.DEFAULT_JCR_PROVIDER_ID).getAsset(new ItemKey(DamConstants.DEFAULT_JCR_PROVIDER_ID, ((JcrNodeItemId) chosenValue).getUuid()));
185 if (asset != null && asset.getMimeType().matches("image.*")) {
186 eventJson = gson.toJson(new FileBrowserUrlDTO(asset.getLink()));
187 } else {
188 eventJson = gson.toJson(new FileBrowserUrlDTO("", "Selected asset is not an image"));
189 }
190 } catch (DamException e) {
191 eventJson = gson.toJson(new FileBrowserUrlDTO("", e.getMessage()));
192 } finally {
193 richTextEditor.firePluginEvent(ASSET_CHOSEN_EVENT_ID, eventJson);
194 }
195 }
196
197
198 @Override
199 public void onCancel() {
200 UI.getCurrent().removeStyleName("ui-overlapping-ck-editor");
201 }
202 });
203 }
204
205 @Override
206 protected MagnoliaRichTextFieldConfig initializeCKEditorConfig() {
207 MagnoliaRichTextFieldConfig config = super.initializeCKEditorConfig();
208
209
210 boolean isCustomConfig = StringUtils.isNotBlank(definition.getConfigJsFile());
211 if (definition.isImages() || isCustomConfig) {
212
213
214 String path = VaadinService.getCurrentRequest().getContextPath();
215 config.addExternalPlugin(FILE_BROWSER_PLUGIN, path + "/VAADIN/js/filebrowser/");
216 config.addListenedEvent(FILE_BROWSER_PLUGIN_CHOOSE_ASSET_EVENT);
217 if (!isCustomConfig) {
218 config.addToExtraPlugins(FILE_BROWSER_PLUGIN);
219 }
220
221
222 config.setFilebrowserImageBrowseLinkUrl("dummy");
223 config.setFilebrowserImageBrowseUrl("dummy");
224 }
225 return config;
226 }
227
228
229
230
231 public static class FileBrowserUrlDTO {
232 public String url;
233 public String errorMessage;
234
235 public FileBrowserUrlDTO(String url, String errorMessage) {
236 this.url = url;
237 this.errorMessage = errorMessage;
238 }
239
240 public FileBrowserUrlDTO(String url) {
241 this(url, null);
242 }
243 }
244 }