View Javadoc

1   /**
2    * This file Copyright (c) 2010-2012 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.vaadin.gwt.client.editor;
35  
36  import com.google.gwt.core.client.GWT;
37  import com.google.gwt.dom.client.Document;
38  import com.google.gwt.dom.client.Element;
39  import com.google.gwt.dom.client.HeadElement;
40  import com.google.gwt.dom.client.LinkElement;
41  import com.google.gwt.dom.client.Node;
42  import com.google.gwt.event.shared.EventBus;
43  import com.google.gwt.event.shared.SimpleEventBus;
44  import com.google.gwt.user.client.ui.Composite;
45  import com.vaadin.terminal.gwt.client.ApplicationConnection;
46  import com.vaadin.terminal.gwt.client.Paintable;
47  import com.vaadin.terminal.gwt.client.UIDL;
48  import com.vaadin.terminal.gwt.client.VConsole;
49  
50  import info.magnolia.ui.vaadin.gwt.client.editor.dom.CmsNode;
51  import info.magnolia.ui.vaadin.gwt.client.editor.dom.Comment;
52  import info.magnolia.ui.vaadin.gwt.client.editor.dom.MgnlElement;
53  import info.magnolia.ui.vaadin.gwt.client.editor.dom.processor.AbstractMgnlElementProcessor;
54  import info.magnolia.ui.vaadin.gwt.client.editor.dom.processor.CommentProcessor;
55  import info.magnolia.ui.vaadin.gwt.client.editor.dom.processor.ElementProcessor;
56  import info.magnolia.ui.vaadin.gwt.client.editor.dom.processor.MgnlElementProcessorFactory;
57  import info.magnolia.ui.vaadin.gwt.client.editor.event.DeleteComponentEvent;
58  import info.magnolia.ui.vaadin.gwt.client.editor.event.DeleteComponentEventHandler;
59  import info.magnolia.ui.vaadin.gwt.client.editor.event.EditComponentEvent;
60  import info.magnolia.ui.vaadin.gwt.client.editor.event.EditComponentEventHandler;
61  import info.magnolia.ui.vaadin.gwt.client.editor.event.NewAreaEvent;
62  import info.magnolia.ui.vaadin.gwt.client.editor.event.NewAreaEventHandler;
63  import info.magnolia.ui.vaadin.gwt.client.editor.event.NewComponentEvent;
64  import info.magnolia.ui.vaadin.gwt.client.editor.event.NewComponentEventHandler;
65  import info.magnolia.ui.vaadin.gwt.client.editor.event.SelectElementEvent;
66  import info.magnolia.ui.vaadin.gwt.client.editor.event.SelectElementEventHandler;
67  import info.magnolia.ui.vaadin.gwt.client.editor.event.SortComponentEvent;
68  import info.magnolia.ui.vaadin.gwt.client.editor.event.SortComponentEventHandler;
69  import info.magnolia.ui.vaadin.gwt.client.editor.jsni.event.FrameLoadedEvent;
70  import info.magnolia.ui.vaadin.gwt.client.editor.model.Model;
71  import info.magnolia.ui.vaadin.gwt.client.editor.model.ModelImpl;
72  import info.magnolia.ui.vaadin.gwt.client.editor.model.focus.FocusModel;
73  import info.magnolia.ui.vaadin.gwt.client.editor.model.focus.FocusModelImpl;
74  import info.magnolia.ui.vaadin.gwt.client.editor.widget.controlbar.PageBar;
75  
76  import org.vaadin.rpc.client.ClientSideHandler;
77  import org.vaadin.rpc.client.ClientSideProxy;
78  import org.vaadin.rpc.client.Method;
79  
80  import java.util.List;
81  
82  
83  /**
84   * Vaadin implementation of PageEditor client side.
85   */
86  public class VPageEditor extends Composite implements VPageEditorView.Listener, Paintable, ClientSideHandler {
87  
88  
89      private static final String PAGE_EDITOR_CSS = "/VAADIN/themes/admincentraltheme/pageeditor.css";
90  
91  
92      private final VPageEditorView view;
93      private final Model model;
94      private final EventBus eventBus;
95      private final FocusModel focusModel;
96  
97      protected ApplicationConnection client;
98      private ClientSideProxy proxy;
99      private String paintableId;
100 
101     private VPageEditorParameters pageEditorParameters;
102 
103    
104     public VPageEditor() {
105         this.eventBus = new SimpleEventBus();
106 
107         this.view = new VPageEditorViewImpl(eventBus);
108         this.model = new ModelImpl();
109         this.focusModel = new FocusModelImpl(eventBus, model);
110 
111 
112         initWidget(view.asWidget());
113 
114         view.setListener(this);
115 
116         registerDomEventHandlers();
117         registerEditorEventHandlers();
118 
119 
120         
121         proxy = new ClientSideProxy(this) {
122             {
123                 register("refresh", new Method() {
124                     @Override
125                     public void invoke(String methodName, Object[] params) {
126                         view.reload();
127                     }
128                 });
129 
130                 register("load", new Method() {
131                     @Override
132                     public void invoke(String methodName, Object[] params) {
133                         String json = String.valueOf(params[0]);
134                         pageEditorParameters = VPageEditorParameters.parse(json);
135                         view.setUrl(pageEditorParameters.getContextPath() + pageEditorParameters.getNodePath());
136                     }
137                 });
138             }
139         };
140 
141     }
142 
143     @Override
144     public boolean initWidget(Object[] objects) {
145         return false;
146     }
147 
148     @Override
149     public void handleCallFromServer(String method, Object[] params) {
150         VConsole.error("Unhandled RPC call from server: " + method);
151     }
152 
153     @Override
154     public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
155         this.client = client;
156         this.paintableId = uidl.getId();
157         if (client.updateComponent(this, uidl, true)) {
158             return;
159         }
160 
161         proxy.update(this, uidl, client);
162     }
163 
164     private void registerDomEventHandlers() {
165 
166         eventBus.addHandler(FrameLoadedEvent.TYPE, new FrameLoadedEvent.Handler() {
167 
168             @Override
169             public void handle(FrameLoadedEvent event) {
170                 model.reset();
171                 if (pageEditorParameters.isPreview()) {
172                     return;
173                 }
174 
175                 view.initSelectionListener();
176 
177                 Document document = event.getFrameDocument();
178                 process(event.getFrameDocument());
179 
180                 if (model.getRootPage().getControlBar() != null) {
181                     ((PageBar)model.getRootPage().getControlBar()).setPageTitle(document.getTitle());
182                 }
183                 focusModel.init();
184             }
185 
186         });
187     }
188 
189     private void registerEditorEventHandlers() {
190 
191         eventBus.addHandler(SelectElementEvent.TYPE, new SelectElementEventHandler() {
192 
193             @Override
194             public void onSelectElement(SelectElementEvent selectElementEvent) {
195                 proxy.call("selectElement", selectElementEvent.getType(), selectElementEvent.getJson());
196             }
197 
198         });
199 
200         eventBus.addHandler(NewAreaEvent.TYPE, new NewAreaEventHandler() {
201             @Override
202             public void onNewArea(NewAreaEvent newAreaEvent) {
203                 proxy.call("newArea", newAreaEvent.getWorkSpace(), newAreaEvent.getNodeType(), newAreaEvent.getPath());
204             }
205         });
206 
207         eventBus.addHandler(NewComponentEvent.TYPE, new NewComponentEventHandler() {
208             @Override
209             public void onNewComponent(NewComponentEvent newComponentEvent) {
210                 proxy.call("newComponent", newComponentEvent.getWorkSpace(), newComponentEvent.getPath(), newComponentEvent.getAvailableComponents());
211             }
212         });
213 
214         eventBus.addHandler(EditComponentEvent.TYPE, new EditComponentEventHandler() {
215             @Override
216             public void onEditComponent(EditComponentEvent editComponentEvent) {
217                 proxy.call("editComponent", editComponentEvent.getWorkspace(), editComponentEvent.getPath(), editComponentEvent.getDialog());
218             }
219         });
220 
221         eventBus.addHandler(DeleteComponentEvent.TYPE, new DeleteComponentEventHandler() {
222             @Override
223             public void onDeleteComponent(DeleteComponentEvent deleteComponentEvent) {
224                 proxy.call("deleteComponent", deleteComponentEvent.getWorkspace(), deleteComponentEvent.getPath());
225             }
226         });
227         eventBus.addHandler(SortComponentEvent.TYPE, new SortComponentEventHandler() {
228             @Override
229             public void onSortComponent(SortComponentEvent sortComponentEvent) {
230                 proxy.call("sortComponent", sortComponentEvent.getWorkspace(), sortComponentEvent.getParentPath(), sortComponentEvent.getSourcePath(), sortComponentEvent.getTargetPath(), sortComponentEvent.getOrder());
231             }
232         });
233     }
234 
235     public Model getModel() {
236         return model;
237     }
238 
239     @Override
240     public void selectElement(final Element element) {
241         focusModel.selectElement(element);
242     }
243 
244     private void injectEditorStyles(final Document document) {
245         HeadElement head = HeadElement.as(document.getElementsByTagName("head").getItem(0));
246         LinkElement cssLink = document.createLinkElement();
247         cssLink.setType("text/css");
248         cssLink.setRel("stylesheet");
249         cssLink.setHref(pageEditorParameters.getContextPath() + PAGE_EDITOR_CSS);
250         head.insertFirst(cssLink);
251     }
252 
253     private void process(final Document document) {
254         injectEditorStyles(document);
255 
256         long startTime = System.currentTimeMillis();
257         processDocument(document.getDocumentElement(), null);
258         processMgnlElements();
259 
260         GWT.log("Time spent to process cms comments: " + (System.currentTimeMillis() - startTime) + "ms");
261 
262     }
263 
264     private void processDocument(Node node, MgnlElement mgnlElement) {
265         boolean proceed = true;
266         if (mgnlElement == null && model.getRootPage() != null) {
267             mgnlElement = model.getRootPage();
268         }
269         for (int i = 0; i < node.getChildCount(); i++) {
270             Node childNode = node.getChild(i);
271             if (childNode.getNodeType() == Comment.COMMENT_NODE) {
272 
273                 try {
274                     CommentProcessor processor = new CommentProcessor();
275                     mgnlElement = processor.process(model, childNode, mgnlElement);
276                 } catch (IllegalArgumentException e) {
277                     GWT.log("Not CMSComment element, skipping: " + e.toString());
278                 } catch (Exception e) {
279                     GWT.log("Caught undefined exception: " + e.toString());
280                 }
281             } else if (childNode.getNodeType() == Node.ELEMENT_NODE && mgnlElement != null && !mgnlElement.isPage()) {
282                 proceed = ElementProcessor.process(model, childNode, mgnlElement);
283             }
284             if (proceed) {
285                 processDocument(childNode, mgnlElement);
286             }
287         }
288 
289     }
290 
291     private void processMgnlElements() {
292         CmsNode root = model.getRootPage();
293         List<CmsNode> elements = root.getDescendants();
294         elements.add(root);
295         for (CmsNode element : elements) {
296 
297             try {
298                 AbstractMgnlElementProcessor processor = MgnlElementProcessorFactory.getProcessor(model, eventBus, element.asMgnlElement());
299                 processor.process();
300             } catch (IllegalArgumentException e) {
301                 GWT.log("MgnlFactory could not instantiate class. The element is neither an area nor component.");
302             }
303         }
304     }
305 
306 }