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.form.field.factory;
35
36 import info.magnolia.i18nsystem.SimpleTranslator;
37 import info.magnolia.repository.RepositoryConstants;
38 import info.magnolia.ui.api.app.AppController;
39 import info.magnolia.ui.api.app.ChooseDialogCallback;
40 import info.magnolia.ui.api.context.UiContext;
41 import info.magnolia.ui.form.field.definition.RichTextFieldDefinition;
42 import info.magnolia.ui.vaadin.integration.jcr.JcrItemId;
43 import info.magnolia.ui.vaadin.integration.jcr.JcrItemUtil;
44 import info.magnolia.ui.vaadin.richtext.MagnoliaRichTextField;
45 import info.magnolia.ui.vaadin.richtext.MagnoliaRichTextFieldConfig;
46 import info.magnolia.ui.vaadin.richtext.MagnoliaRichTextFieldConfig.ToolbarGroup;
47
48 import java.util.ArrayList;
49 import java.util.List;
50
51 import javax.jcr.Node;
52
53 import org.apache.commons.lang3.StringUtils;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 import com.google.gson.Gson;
58 import com.google.inject.Inject;
59 import com.vaadin.data.Item;
60 import com.vaadin.server.Sizeable.Unit;
61 import com.vaadin.server.VaadinService;
62 import com.vaadin.ui.Field;
63
64
65
66
67 public class RichTextFieldFactory extends AbstractFieldFactory<RichTextFieldDefinition, String> {
68
69 private static final Logger log = LoggerFactory.getLogger(RichTextFieldFactory.class);
70
71 private static final String PLUGIN_NAME_MAGNOLIALINK = "magnolialink";
72
73 private static final String PLUGIN_PATH_MAGNOLIALINK = "/VAADIN/js/magnolialink/";
74
75
76
77
78 public static final String EVENT_SEND_MAGNOLIA_LINK = "mgnlLinkSelected";
79
80
81
82
83
84
85 public static final String EVENT_CANCEL_LINK = "mgnlLinkCancel";
86
87
88
89
90
91 public static final String EVENT_GET_MAGNOLIA_LINK = "mgnlGetLink";
92
93 protected final AppController appController;
94 protected final UiContext uiContext;
95 protected final SimpleTranslator i18n;
96 protected MagnoliaRichTextField richTextEditor;
97
98 @Inject
99 public RichTextFieldFactory(RichTextFieldDefinition definition, Item relatedFieldItem, AppController appController, UiContext uiContext, SimpleTranslator i18n) {
100 super(definition, relatedFieldItem);
101 this.appController = appController;
102 this.uiContext = uiContext;
103 this.i18n = i18n;
104 }
105
106 @Override
107 protected Field<String> createFieldComponent() {
108
109 MagnoliaRichTextFieldConfig config = initializeCKEditorConfig();
110 richTextEditor = new MagnoliaRichTextField(config);
111 if (definition.getHeight() > 0) {
112 richTextEditor.setHeight(definition.getHeight(), Unit.PIXELS);
113 }
114
115 richTextEditor.addListener(new MagnoliaRichTextField.PluginListener() {
116 @Override
117 public void onPluginEvent(String eventName, String value) {
118 if (eventName.equals(EVENT_GET_MAGNOLIA_LINK)) {
119 try {
120 Gson gson = new Gson();
121 PluginData pluginData = gson.fromJson(value, PluginData.class);
122 openLinkDialog(pluginData.path, pluginData.workspace);
123 } catch (Exception e) {
124 log.error("openLinkDialog failed", e);
125 richTextEditor.firePluginEvent(EVENT_CANCEL_LINK, i18n.translate("ui-form.richtexteditorexception.opentargetappfailure"));
126 }
127 }
128 }
129 });
130
131 return richTextEditor;
132 }
133
134 protected MagnoliaRichTextFieldConfig initializeCKEditorConfig() {
135
136 MagnoliaRichTextFieldConfig config = new MagnoliaRichTextFieldConfig();
137 String path = VaadinService.getCurrentRequest().getContextPath();
138
139
140 config.addExternalPlugin(PLUGIN_NAME_MAGNOLIALINK, path + PLUGIN_PATH_MAGNOLIALINK);
141 config.addListenedEvent(EVENT_GET_MAGNOLIA_LINK);
142
143
144 if (StringUtils.isNotBlank(definition.getConfigJsFile())) {
145 config.addExtraConfig("customConfig", "'" + path + definition.getConfigJsFile() + "'");
146 return config;
147 }
148
149
150 if (!definition.isAlignment()) {
151 config.addToRemovePlugins("justify");
152 }
153 if (!definition.isImages()) {
154 config.addToRemovePlugins("image");
155 }
156 if (!definition.isLists()) {
157
158 config.addToRemovePlugins("enterkey");
159 config.addToRemovePlugins("indent");
160 config.addToRemovePlugins("list");
161 }
162 if (!definition.isSource()) {
163 config.addToRemovePlugins("sourcearea");
164 }
165 if (!definition.isTables()) {
166 config.addToRemovePlugins("table");
167 config.addToRemovePlugins("tabletools");
168 }
169
170 if (definition.getColors() != null) {
171 config.addExtraConfig("colorButton_colors", "'" + definition.getColors() + "'");
172 config.addExtraConfig("colorButton_enableMore", "false");
173 config.addToRemovePlugins("colordialog");
174 } else {
175 config.addToRemovePlugins("colorbutton");
176 config.addToRemovePlugins("colordialog");
177 }
178 if (definition.getFonts() != null) {
179 config.addExtraConfig("font_names", "'" + definition.getFonts() + "'");
180 } else {
181 config.addExtraConfig("removeButtons", "'Font'");
182 }
183 if (definition.getFontSizes() != null) {
184 config.addExtraConfig("fontSize_sizes", "'" + definition.getFontSizes() + "'");
185 } else {
186 config.addExtraConfig("removeButtons", "'FontSize'");
187 }
188 if (definition.getFonts() == null && definition.getFontSizes() == null) {
189 config.addToRemovePlugins("font");
190 config.addToRemovePlugins("fontSize");
191 }
192
193
194 List<ToolbarGroup> toolbars = initializeToolbarConfig();
195 config.addToolbarLine(toolbars);
196
197 config.addToExtraPlugins(PLUGIN_NAME_MAGNOLIALINK);
198 config.addToRemovePlugins("elementspath");
199 config.setBaseFloatZIndex(150);
200 config.setResizeEnabled(false);
201
202 return config;
203 }
204
205 protected List<ToolbarGroup> initializeToolbarConfig() {
206 List<ToolbarGroup> toolbars = new ArrayList<ToolbarGroup>();
207 toolbars.add(new ToolbarGroup("basicstyles", new String[] { "Bold", "Italic", "Underline", "SpecialChar" }));
208 toolbars.add(new ToolbarGroup("paragraph", new String[] { "NumberedList", "BulletedList", "JustifyLeft", "JustifyCenter", "JustifyRight", "JustifyBlock", "Image", "Table" }));
209 toolbars.add(new ToolbarGroup("links", new String[] { "Link", "InternalLink", "DamLink", "Unlink" }));
210 toolbars.add(new ToolbarGroup("styles", new String[] { "Font", "FontSize", "TextColor" }));
211 toolbars.add(new ToolbarGroup("clipboard", new String[] { "Cut", "Copy", "Paste", "PasteText", "PasteFromWord" }));
212 toolbars.add(new ToolbarGroup("undo", new String[] { "Undo", "Redo" }));
213 toolbars.add(new ToolbarGroup("tools", new String[] { "Source" }));
214 return toolbars;
215 }
216
217 private String mapWorkSpaceToApp(String workspace) {
218 if (workspace.equalsIgnoreCase("dam")) {
219 return "assets";
220 } else if (workspace.equalsIgnoreCase(RepositoryConstants.WEBSITE)) {
221 return "pages";
222 }
223
224 return "";
225 }
226
227 private void openLinkDialog(String path, String workspace) {
228 appController.openChooseDialog(mapWorkSpaceToApp(workspace), uiContext, null, new ChooseDialogCallback() {
229 @Override
230 public void onItemChosen(String actionName, Object chosenValue) {
231 if (!(chosenValue instanceof JcrItemId)) {
232 richTextEditor.firePluginEvent(EVENT_CANCEL_LINK);
233 return;
234 }
235 try {
236 javax.jcr.Item jcrItem = JcrItemUtil.getJcrItem((JcrItemId) chosenValue);
237 if (!jcrItem.isNode()) {
238 return;
239 }
240 final Node selected = (Node) jcrItem;
241 Gson gson = new Gson();
242 MagnoliaLink mlink = new MagnoliaLink();
243 mlink.identifier = selected.getIdentifier();
244 mlink.repository = selected.getSession().getWorkspace().getName();
245 mlink.path = selected.getPath();
246 if (selected.hasProperty("title")) {
247 mlink.caption = selected.getProperty("title").getString();
248 } else {
249 mlink.caption = selected.getName();
250 }
251
252 richTextEditor.firePluginEvent(EVENT_SEND_MAGNOLIA_LINK, gson.toJson(mlink));
253 } catch (Exception e) {
254 String error = i18n.translate("ui-form.richtexteditorexception.cannotaccessselecteditem");
255 log.error(error, e);
256 richTextEditor.firePluginEvent(EVENT_CANCEL_LINK, error);
257 }
258 }
259
260 @Override
261 public void onCancel() {
262 richTextEditor.firePluginEvent(EVENT_CANCEL_LINK);
263 }
264 });
265 }
266
267
268
269
270 protected static class MagnoliaLink {
271
272 public String identifier;
273
274 public String repository;
275
276 public String path;
277
278 public String caption;
279
280 }
281
282
283
284
285 protected static class PluginData {
286 public String workspace;
287 public String path;
288 }
289 }