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.ui.api.app.AppController;
37 import info.magnolia.ui.api.app.ItemChosenListener;
38 import info.magnolia.ui.api.context.UiContext;
39 import info.magnolia.ui.form.field.definition.FieldDefinition;
40 import info.magnolia.ui.form.field.definition.RichTextFieldDefinition;
41 import info.magnolia.ui.vaadin.integration.jcr.JcrItemAdapter;
42 import info.magnolia.ui.vaadin.richtext.MagnoliaRichTextField;
43 import info.magnolia.ui.vaadin.richtext.MagnoliaRichTextFieldConfig;
44 import info.magnolia.ui.vaadin.richtext.MagnoliaRichTextFieldConfig.ToolbarGroup;
45
46 import java.util.ArrayList;
47 import java.util.List;
48
49 import javax.jcr.Node;
50
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 import com.google.gson.Gson;
55 import com.google.inject.Inject;
56 import com.vaadin.data.Item;
57 import com.vaadin.server.VaadinService;
58 import com.vaadin.server.WebBrowser;
59 import com.vaadin.ui.Field;
60
61
62
63
64 public class RichTextFieldFactory extends AbstractFieldFactory<RichTextFieldDefinition, String> {
65
66 private static final String PLUGIN_NAME_MAGNOLIALINK = "magnolialink";
67
68 private static final String PLUGIN_PATH_MAGNOLIALINK = "/VAADIN/js/magnolialink/";
69
70
71
72
73 public static final String EVENT_SEND_MAGNOLIA_LINK = "mgnlLinkSelected";
74
75
76
77
78
79
80 public static final String EVENT_CANCEL_LINK = "mgnlLinkCancel";
81
82
83
84
85
86 public static final String EVENT_GET_MAGNOLIA_LINK = "mgnlGetLink";
87
88 private final AppController appController;
89 private MagnoliaRichTextField richTextEditor;
90 private static final Logger log = LoggerFactory.getLogger(LinkFieldFactory.class);
91
92 private final UiContext uiContext;
93
94 @Inject
95 public RichTextFieldFactory(RichTextFieldDefinition definition, Item relatedFieldItem, AppController appController, UiContext uiContext) {
96 super(definition, relatedFieldItem);
97 this.appController = appController;
98 this.uiContext = uiContext;
99 }
100
101 @Override
102 protected Field<String> createFieldComponent() {
103
104 final MagnoliaRichTextFieldConfig config = new MagnoliaRichTextFieldConfig();
105
106 List<ToolbarGroup> toolbars = new ArrayList<ToolbarGroup>();
107 toolbars.add(new ToolbarGroup("basictyles", new String[] { "Bold", "Italic", "Underline", "SpecialChar" }));
108 toolbars.add(new ToolbarGroup("paragraph", new String[] { "NumberedList", "BulletedList" }));
109 toolbars.add(new ToolbarGroup("insert", new String[] { "Link", "InternalLink", "DamLink", "Unlink" }));
110 toolbars.add(new ToolbarGroup("clipboard", new String[] { "Cut", "Copy", "Paste", "PasteText", "PasteFromWord" }));
111 toolbars.add(new ToolbarGroup("objects", new String[] { "Table" }));
112 toolbars.add(new ToolbarGroup("special", new String[] { "Undo", "Redo" }));
113 config.addToolbarLine(toolbars);
114 config.addListenedEvent(EVENT_GET_MAGNOLIA_LINK);
115 config.setResizeEnabled(false);
116
117 richTextEditor = new MagnoliaRichTextField(config) {
118 @Override
119 public void attach() {
120 super.attach();
121 String path = VaadinService.getCurrentRequest().getContextPath();
122 config.addPlugin(PLUGIN_NAME_MAGNOLIALINK, path + PLUGIN_PATH_MAGNOLIALINK);
123
124 WebBrowser browser = getSession().getBrowser();
125 if (browser.isTouchDevice()) {
126
127 richTextEditor.setEnabled(false);
128 richTextEditor.setReadOnly(true);
129 richTextEditor.addStyleName("richtextfield-disabled");
130 }
131
132 }
133 };
134
135 richTextEditor.addListener(new MagnoliaRichTextField.PluginListener() {
136
137 @Override
138 public void onPluginEvent(String eventName, String value) {
139
140 if (eventName.equals(EVENT_GET_MAGNOLIA_LINK)) {
141 try {
142 Gson gson = new Gson();
143 PluginData pluginData = gson.fromJson(value, PluginData.class);
144 openLinkDialog(pluginData.path, pluginData.workspace);
145 } catch (Exception e) {
146 log.error("openLinkDialog failed", e);
147 richTextEditor.firePluginEvent(EVENT_CANCEL_LINK, "Could not open target App");
148 }
149 }
150 }
151 });
152
153 return richTextEditor;
154 }
155
156 private static class PluginData {
157 public String workspace;
158 public String path;
159 }
160
161 private String mapWorkSpaceToApp(String workspace) {
162 if (workspace.equalsIgnoreCase("dam")) {
163 return "assets";
164 } else if (workspace.equalsIgnoreCase("website")) {
165 return "pages";
166 }
167
168 return "";
169 }
170
171 private void openLinkDialog(String path, String workspace) {
172
173 appController.openChooseDialog(mapWorkSpaceToApp(workspace), path, uiContext, null, new ItemChosenListener() {
174
175 @Override
176 public void onItemChosen(Item chosenValue) {
177 if (!(chosenValue instanceof JcrItemAdapter)) {
178 richTextEditor
179 .firePluginEvent(EVENT_CANCEL_LINK);
180 return;
181 }
182
183 try {
184
185 javax.jcr.Item jcrItem = ((JcrItemAdapter) chosenValue).getJcrItem();
186
187 if (!jcrItem.isNode()) {
188 return;
189 }
190
191 final Node selected = (Node) jcrItem;
192 Gson gson = new Gson();
193 MagnoliaLink mlink = new MagnoliaLink();
194 mlink.identifier = selected.getIdentifier();
195 mlink.repository = selected.getSession().getWorkspace().getName();
196 mlink.path = selected.getPath();
197 if (selected.hasProperty("title")) {
198 mlink.caption = selected.getProperty("title").getString();
199 } else {
200 mlink.caption = selected.getName();
201 }
202
203 richTextEditor.firePluginEvent(EVENT_SEND_MAGNOLIA_LINK, gson.toJson(mlink));
204 } catch (Exception e) {
205 String error = "Not able to access the selected item. Value will not be set.";
206 log.error(error, e);
207 richTextEditor.firePluginEvent(EVENT_CANCEL_LINK, error);
208 }
209 }
210
211 @Override
212 public void onChooseCanceled() {
213 richTextEditor.firePluginEvent(EVENT_CANCEL_LINK);
214 }
215 });
216 }
217
218 private static class MagnoliaLink {
219 @SuppressWarnings("unused")
220 public String identifier;
221 @SuppressWarnings("unused")
222 public String repository;
223 @SuppressWarnings("unused")
224 public String path;
225 @SuppressWarnings("unused")
226 public String caption;
227 }
228
229 @Override
230 protected Class<?> getDefaultFieldType(FieldDefinition fieldDefinition) {
231 return String.class;
232 }
233 }