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.i18nsystem.SimpleTranslator;
37  import info.magnolia.ui.api.app.AppController;
38  import info.magnolia.ui.api.app.ChooseDialogCallback;
39  import info.magnolia.ui.api.context.UiContext;
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      private final SimpleTranslator i18n;
94  
95      @Inject
96      public RichTextFieldFactory(RichTextFieldDefinition definition, Item relatedFieldItem, AppController appController, UiContext uiContext, SimpleTranslator i18n) {
97          super(definition, relatedFieldItem);
98          this.appController = appController;
99          this.uiContext = uiContext;
100         this.i18n = i18n;
101     }
102 
103     @Override
104     protected Field<String> createFieldComponent() {
105         // RichTextFieldDefinition editDefinition = definition;
106         final MagnoliaRichTextFieldConfig config = new MagnoliaRichTextFieldConfig();
107 
108         List<ToolbarGroup> toolbars = new ArrayList<ToolbarGroup>();
109         toolbars.add(new ToolbarGroup("basictyles", new String[] { "Bold", "Italic", "Underline", "SpecialChar" }));
110         toolbars.add(new ToolbarGroup("paragraph", new String[] { "NumberedList", "BulletedList" }));
111         toolbars.add(new ToolbarGroup("insert", new String[] { "Link", "InternalLink", "DamLink", "Unlink" }));
112         toolbars.add(new ToolbarGroup("clipboard", new String[] { "Cut", "Copy", "Paste", "PasteText", "PasteFromWord" }));
113         toolbars.add(new ToolbarGroup("objects", new String[] { "Table" }));
114         toolbars.add(new ToolbarGroup("special", new String[] { "Undo", "Redo" }));
115         config.addToolbarLine(toolbars);
116         config.addListenedEvent(EVENT_GET_MAGNOLIA_LINK);
117         config.setResizeEnabled(false);
118 
119         richTextEditor = new MagnoliaRichTextField(config) {
120             @Override
121             public void attach() {
122                 super.attach();
123                 String path = VaadinService.getCurrentRequest().getContextPath();
124                 config.addPlugin(PLUGIN_NAME_MAGNOLIALINK, path + PLUGIN_PATH_MAGNOLIALINK);
125 
126                 WebBrowser browser = getSession().getBrowser();
127                 if (browser.isTouchDevice()) {
128                     // MGNLUI-1528: Workaround.
129                     richTextEditor.setEnabled(false);
130                     richTextEditor.setReadOnly(true);
131                     richTextEditor.addStyleName("richtextfield-disabled");
132                 }
133 
134             }
135         };
136 
137         richTextEditor.addListener(new MagnoliaRichTextField.PluginListener() {
138 
139             @Override
140             public void onPluginEvent(String eventName, String value) {
141 
142                 if (eventName.equals(EVENT_GET_MAGNOLIA_LINK)) {
143                     try {
144                         Gson gson = new Gson();
145                         PluginData pluginData = gson.fromJson(value, PluginData.class);
146                         openLinkDialog(pluginData.path, pluginData.workspace);
147                     } catch (Exception e) {
148                         log.error("openLinkDialog failed", e);
149                         richTextEditor.firePluginEvent(EVENT_CANCEL_LINK, i18n.translate("ui-form.richtexteditorexception.opentargetappfailure"));
150                     }
151                 }
152             }
153         });
154 
155         return richTextEditor;
156     }
157 
158     private static class PluginData {
159         public String workspace;
160         public String path;
161     }
162 
163     private String mapWorkSpaceToApp(String workspace) {
164         if (workspace.equalsIgnoreCase("dam")) {
165             return "assets";
166         } else if (workspace.equalsIgnoreCase("website")) {
167             return "pages";
168         }
169 
170         return "";
171     }
172 
173     private void openLinkDialog(String path, String workspace) {
174 
175         appController.openChooseDialog(mapWorkSpaceToApp(workspace), uiContext, null, new ChooseDialogCallback() {
176 
177             @Override
178             public void onItemChosen(String actionName, Item chosenValue) {
179                 if (!(chosenValue instanceof JcrItemAdapter)) {
180                     richTextEditor
181                             .firePluginEvent(EVENT_CANCEL_LINK);
182                     return;
183                 }
184 
185                 try {
186 
187                     javax.jcr.Item jcrItem = ((JcrItemAdapter) chosenValue).getJcrItem();
188 
189                     if (!jcrItem.isNode()) {
190                         return;
191                     }
192 
193                     final Node selected = (Node) jcrItem;
194                     Gson gson = new Gson();
195                     MagnoliaLink mlink = new MagnoliaLink();
196                     mlink.identifier = selected.getIdentifier();
197                     mlink.repository = selected.getSession().getWorkspace().getName();
198                     mlink.path = selected.getPath();
199                     if (selected.hasProperty("title")) {
200                         mlink.caption = selected.getProperty("title").getString();
201                     } else {
202                         mlink.caption = selected.getName();
203                     }
204 
205                     richTextEditor.firePluginEvent(EVENT_SEND_MAGNOLIA_LINK, gson.toJson(mlink));
206                 } catch (Exception e) {
207                     String error = i18n.translate("ui-form.richtexteditorexception.cannotaccessselecteditem");
208                     log.error(error, e);
209                     richTextEditor.firePluginEvent(EVENT_CANCEL_LINK, error);
210                 }
211             }
212 
213             @Override
214             public void onCancel() {
215                 richTextEditor.firePluginEvent(EVENT_CANCEL_LINK);
216             }
217         });
218     }
219 
220     private static class MagnoliaLink {
221         @SuppressWarnings("unused")
222         public String identifier;
223         @SuppressWarnings("unused")
224         public String repository;
225         @SuppressWarnings("unused")
226         public String path;
227         @SuppressWarnings("unused")
228         public String caption;
229     }
230 }