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