View Javadoc

1   /**
2    * This file Copyright (c) 2012-2013 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
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   * Creates and initializes an edit field based on a field definition.
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       * Event is emit from server to client when link has been selected.
72       */
73      public static final String EVENT_SEND_MAGNOLIA_LINK = "mgnlLinkSelected";
74  
75      /**
76       * Event is emit from server to client when link dialog has been
77       * canceled or exception has occurred. In case of exception
78       * the event will carry error message.
79       */
80      public static final String EVENT_CANCEL_LINK = "mgnlLinkCancel";
81  
82      /**
83       * Event is emit from client to server when user requests a link dialog.
84       * Event carries optional link that should be treated as default link value.
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         // RichTextFieldDefinition editDefinition = definition;
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                     // MGNLUI-1528: Workaround.
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 }