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