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