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.ui.field.factory;
35
36 import static info.magnolia.ui.vaadin.ckeditor.MagnoliaCKEditorConfig.*;
37 import static info.magnolia.ui.vaadin.ckeditor.MagnoliaCKEditorTextFieldEvents.*;
38
39 import info.magnolia.i18nsystem.SimpleTranslator;
40 import info.magnolia.jcr.util.PropertyUtil;
41 import info.magnolia.jcr.util.SessionUtil;
42 import info.magnolia.objectfactory.ComponentProvider;
43 import info.magnolia.repository.RepositoryConstants;
44 import info.magnolia.ui.api.i18n.I18NAuthoringSupport;
45 import info.magnolia.ui.api.app.registry.AppDescriptorRegistry;
46 import info.magnolia.ui.framework.chooser.SingleItemWorkbenchChooser;
47 import info.magnolia.ui.framework.chooser.definition.AppAwareWorkbenchChooserDefinition;
48 import info.magnolia.ui.framework.chooser.definition.ChooserDefinition;
49 import info.magnolia.ui.framework.chooser.definition.SingleItemWorkbenchChooserDefinition;
50 import info.magnolia.ui.field.RichTextFieldDefinition;
51 import info.magnolia.ui.framework.overlay.ChooserController;
52 import info.magnolia.ui.vaadin.ckeditor.MagnoliaCKEditorTextField;
53 import info.magnolia.ui.vaadin.ckeditor.MagnoliaCKEditorConfig;
54 import info.magnolia.ui.vaadin.ckeditor.MagnoliaCKEditorConfig.ToolbarGroup;
55
56 import java.util.List;
57 import java.util.Locale;
58
59 import javax.inject.Inject;
60 import javax.jcr.Node;
61 import javax.jcr.RepositoryException;
62
63 import org.apache.commons.lang3.StringUtils;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67 import com.google.gson.Gson;
68 import com.vaadin.server.Sizeable.Unit;
69 import com.vaadin.server.VaadinService;
70
71 import lombok.SneakyThrows;
72
73
74
75
76
77 public class RichTextFieldFactory extends AbstractFieldFactory<RichTextFieldDefinition, String, MagnoliaCKEditorTextField> {
78
79 public static final String PLUGIN_NAME_MAGNOLIALINK = "magnolialink";
80 public static final String PLUGIN_PATH_MAGNOLIALINK = "/VAADIN/js/magnolialink/";
81
82 private static final Logger log = LoggerFactory.getLogger(RichTextFieldFactory.class);
83
84 private final SimpleTranslator i18n;
85 private final ChooserController chooserController;
86 private final AppDescriptorRegistry appDescriptorRegistry;
87
88 private MagnoliaCKEditorTextField richTextEditor;
89
90 @Inject
91 public RichTextFieldFactory(RichTextFieldDefinition definition, ComponentProvider componentProvider, Locale locale,
92 I18NAuthoringSupport i18NAuthoringSupport, SimpleTranslator i18n, ChooserController chooserController,
93 AppDescriptorRegistry appDescriptorRegistry) {
94 super(definition, componentProvider, locale, i18NAuthoringSupport);
95 this.i18n = i18n;
96 this.chooserController = chooserController;
97 this.appDescriptorRegistry = appDescriptorRegistry;
98 }
99
100 @Override
101 protected MagnoliaCKEditorTextField createFieldComponent() {
102 MagnoliaCKEditorConfig config = initializeCKEditorConfig();
103 richTextEditor = new MagnoliaCKEditorTextField(config);
104
105 if (getDefinition().getHeight() > 0) {
106 richTextEditor.setHeight(getDefinition().getHeight(), Unit.PIXELS);
107 }
108
109 richTextEditor.addListener((eventName, value) -> {
110 if (eventName.equals(EVENT_GET_MAGNOLIA_LINK)) {
111 try {
112 Gson gson = new Gson();
113 PluginData pluginData = gson.fromJson(value, PluginData.class);
114 openLinkDialog(pluginData.path, pluginData.workspace);
115 } catch (Exception e) {
116 log.error("openLinkDialog failed", e);
117 richTextEditor.firePluginEvent(EVENT_CANCEL_LINK, i18n.translate("ui-framework.richtexteditorexception.opentargetappfailure"));
118 }
119 }
120 });
121
122 return richTextEditor;
123 }
124
125 protected MagnoliaCKEditorConfig initializeCKEditorConfig() {
126
127 MagnoliaCKEditorConfig config = new MagnoliaCKEditorConfig();
128 String path = VaadinService.getCurrentRequest().getContextPath();
129
130
131 config.addExternalPlugin(PLUGIN_NAME_MAGNOLIALINK, path + PLUGIN_PATH_MAGNOLIALINK);
132 config.addListenedEvent(EVENT_GET_MAGNOLIA_LINK);
133
134
135 if (StringUtils.isNotBlank(getDefinition().getConfigJsFile())) {
136 config.addExtraConfig("customConfig", "'" + path + getDefinition().getConfigJsFile() + "'");
137 return config;
138 }
139
140
141 if (!getDefinition().isAlignment()) {
142 config.addToRemovePlugins("justify");
143 }
144 if (!getDefinition().isImages()) {
145 config.addToRemovePlugins("image");
146 }
147 if (!getDefinition().isLists()) {
148
149 config.addToRemovePlugins("enterkey");
150 config.addToRemovePlugins("indent");
151 config.addToRemovePlugins("list");
152 }
153 if (!getDefinition().isSource()) {
154 config.addToRemovePlugins("sourcearea");
155 }
156 if (!getDefinition().isTables()) {
157 config.addToRemovePlugins("table");
158 config.addToRemovePlugins("tabletools");
159 config.addToRemovePlugins("tableselection");
160 }
161
162 if (getDefinition().getColors() != null) {
163 config.addExtraConfig("colorButton_colors", "'" + getDefinition().getColors() + "'");
164 config.addExtraConfig("colorButton_enableMore", "false");
165 config.addToRemovePlugins("colordialog");
166 } else {
167 config.addToRemovePlugins("colorbutton");
168 config.addToRemovePlugins("colordialog");
169 }
170 if (getDefinition().getFonts() != null) {
171 config.addExtraConfig("font_names", "'" + getDefinition().getFonts() + "'");
172 } else {
173 config.addExtraConfig("removeButtons", "'Font'");
174 }
175 if (getDefinition().getFontSizes() != null) {
176 config.addExtraConfig("fontSize_sizes", "'" + getDefinition().getFontSizes() + "'");
177 } else {
178 config.addExtraConfig("removeButtons", "'FontSize'");
179 }
180 if (getDefinition().getFonts() == null && getDefinition().getFontSizes() == null) {
181 config.addToRemovePlugins("font");
182 config.addToRemovePlugins("fontSize");
183 }
184
185
186 List<ToolbarGroup> toolbars = initializeToolbarConfig();
187 config.addToolbarLine(toolbars);
188
189 config.addToExtraPlugins(PLUGIN_NAME_MAGNOLIALINK);
190 config.addToRemovePlugins("elementspath");
191 config.setBaseFloatZIndex(150);
192 config.setResizeEnabled(false);
193
194 return config;
195 }
196
197 protected List<ToolbarGroup> initializeToolbarConfig() {
198 return defaultToolbar();
199 }
200
201 private String mapWorkSpaceToApp(String workspace) {
202 if (workspace.equalsIgnoreCase("dam")) {
203 return "assets";
204 } else if (workspace.equalsIgnoreCase(RepositoryConstants.WEBSITE)) {
205 return "pages";
206 }
207
208 throw new IllegalArgumentException(workspace + " is not a supported workspace by rich text field");
209 }
210
211 private void openLinkDialog(String path, String workspace) {
212 chooserController.openChooser(createChooserDefinition(workspace), SessionUtil.getNode(path, workspace))
213 .whenComplete((ChooserController.ChooseResult<Node> result, Throwable e) -> {
214
215 if (!result.isChosen()) {
216 richTextEditor.firePluginEvent(EVENT_CANCEL_LINK);
217 return;
218 }
219 if (e != null) {
220 String error = i18n.translate("ui-framework.richtexteditorexception.cannotaccessselecteditem");
221 log.error(error, e);
222 richTextEditor.firePluginEvent(EVENT_CANCEL_LINK, error);
223 }
224 result.getChoice().ifPresent(node -> {
225 Gson gson = new Gson();
226 MagnoliaLink mlink = createMagnoliaLink(node);
227 richTextEditor.firePluginEvent(EVENT_SEND_MAGNOLIA_LINK, gson.toJson(mlink));
228 });
229 });
230 }
231
232 @SneakyThrows(RepositoryException.class)
233 private MagnoliaLink createMagnoliaLink(Node node) {
234 MagnoliaLink mlink = new MagnoliaLink();
235 mlink.identifier = node.getIdentifier();
236 mlink.repository = node.getSession().getWorkspace().getName();
237 mlink.path = node.getPath();
238 mlink.caption = PropertyUtil.getString(node, "title", node.getName());
239
240 return mlink;
241 }
242
243 private <DD> ChooserDefinition<Node, SingleItemWorkbenchChooser<DD, Node>> createChooserDefinition(String workspace) {
244 SingleItemWorkbenchChooserDefinition<DD, Node> definition = new SingleItemWorkbenchChooserDefinition<>();
245 AppAwareWorkbenchChooserDefinition<DD, Node> workbenchChooserDefinition = new AppAwareWorkbenchChooserDefinition<>(appDescriptorRegistry);
246 workbenchChooserDefinition.setAppName(mapWorkSpaceToApp(workspace));
247 definition.setWorkbenchChooser(workbenchChooserDefinition);
248 return definition;
249 }
250
251
252
253
254 public static class MagnoliaLink {
255
256 public String identifier;
257
258 public String repository;
259
260 public String path;
261
262 public String caption;
263
264 }
265
266
267
268
269 public static class PluginData {
270 public String workspace;
271 public String path;
272 }
273 }