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.templating.editor.client;
35
36
37 import info.magnolia.templating.editor.client.PreviewChannelWidget.Orientation;
38 import info.magnolia.templating.editor.client.dom.CMSComment;
39 import info.magnolia.templating.editor.client.dom.Comment;
40 import info.magnolia.templating.editor.client.dom.MgnlElement;
41 import info.magnolia.templating.editor.client.jsni.LegacyJavascript;
42 import info.magnolia.templating.editor.client.model.ModelStorage;
43
44 import java.util.Iterator;
45 import java.util.LinkedList;
46 import java.util.List;
47
48
49 import com.google.gwt.core.client.EntryPoint;
50 import com.google.gwt.core.client.GWT;
51 import com.google.gwt.dom.client.AnchorElement;
52 import com.google.gwt.dom.client.Document;
53 import com.google.gwt.dom.client.Element;
54 import com.google.gwt.dom.client.Node;
55 import com.google.gwt.dom.client.NodeList;
56 import com.google.gwt.event.dom.client.MouseDownEvent;
57 import com.google.gwt.event.dom.client.MouseDownHandler;
58 import com.google.gwt.event.dom.client.MouseUpEvent;
59 import com.google.gwt.event.dom.client.MouseUpHandler;
60 import com.google.gwt.http.client.Request;
61 import com.google.gwt.http.client.RequestBuilder;
62 import com.google.gwt.http.client.RequestCallback;
63 import com.google.gwt.http.client.RequestException;
64 import com.google.gwt.http.client.Response;
65 import com.google.gwt.http.client.URL;
66 import com.google.gwt.http.client.UrlBuilder;
67 import com.google.gwt.user.client.Event;
68 import com.google.gwt.user.client.Window;
69 import com.google.gwt.user.client.ui.HTML;
70 import com.google.gwt.user.client.ui.RootPanel;
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 public class PageEditor extends HTML implements EntryPoint {
91
92 public static final String SKIP_PAGE_EDITOR_DOM_PROCESSING = "skipPageEditorDOMProcessing";
93
94 private boolean pageEditBarAlreadyProcessed = false;
95 private String locale;
96 static ModelStorage model = ModelStorage.getInstance();
97 private LinkedList<MgnlElement> mgnlElements = new LinkedList<MgnlElement>();
98
99
100 private boolean process = true;
101
102 @Override
103 public void onModuleLoad() {
104
105 if(Window.Location.getParameter(SKIP_PAGE_EDITOR_DOM_PROCESSING) != null) {
106 GWT.log("Found " + SKIP_PAGE_EDITOR_DOM_PROCESSING + " in request, skipping DOM processing...");
107 postProcessLinksOnMobilePreview(Document.get().getDocumentElement());
108 return;
109 }
110
111 locale = LegacyJavascript.detectCurrentLocale();
112
113 long startTime = System.currentTimeMillis();
114 processDocument(Document.get().getDocumentElement(), null);
115
116 processMgnlElements();
117 GWT.log("Time spent to process cms comments: " + (System.currentTimeMillis() - startTime) + "ms");
118
119 model.getFocusModel().reset();
120
121 RootPanel.get().addDomHandler(new MouseUpHandler() {
122 @Override
123 public void onMouseUp(MouseUpEvent event) {
124
125 model.getFocusModel().onMouseUp((Element)event.getNativeEvent().getEventTarget().cast());
126 event.stopPropagation();
127 }
128 }, MouseUpEvent.getType());
129
130 RootPanel.get().addDomHandler(new MouseDownHandler() {
131 @Override
132 public void onMouseDown(MouseDownEvent event) {
133
134 model.getFocusModel().onMouseDown((Element)event.getNativeEvent().getEventTarget().cast());
135 event.stopPropagation();
136 }
137 }, MouseDownEvent.getType());
138
139 GWT.log("Trying to run onPageEditorReady callbacks...");
140 onPageEditorReady();
141 }
142
143 @Override
144 public void onBrowserEvent(Event event) {
145 super.onBrowserEvent(event);
146 }
147
148
149
150
151 public void openDialog(String dialog, String workspace, String path, String collectionName, String nodeName) {
152 if (collectionName == null) {
153 collectionName = "";
154 }
155 if (nodeName == null) {
156 nodeName = "";
157 }
158
159 LegacyJavascript.mgnlOpenDialog(path, collectionName, nodeName, dialog, workspace, "", "", "", locale);
160 }
161
162 public void moveComponentStart(String id) {
163 LegacyJavascript.mgnlMoveNodeStart(id);
164 }
165
166 public void moveComponentEnd(AbstractBarWidget source, String path) {
167 LegacyJavascript.mgnlMoveNodeEnd(source.getElement(), path);
168 }
169
170 public void moveComponentOver(AbstractBarWidget source) {
171 LegacyJavascript.mgnlMoveNodeHigh(source.getElement());
172 }
173
174 public void moveComponentOut(AbstractBarWidget source) {
175 LegacyJavascript.mgnlMoveNodeReset(source.getElement());
176 }
177
178 public void deleteComponent(String path) {
179 LegacyJavascript.mgnlDeleteNode(path);
180 }
181
182 public void addComponent(String workspace, String path, String nodeName, String availableComponents) {
183
184
185 String collectionName = null;
186
187 if (nodeName == null) {
188 nodeName = "mgnlNew";
189 }
190 if (availableComponents == null) {
191 availableComponents = "";
192 }
193 LegacyJavascript.mgnlOpenDialog(path, collectionName, nodeName, availableComponents, workspace, ".magnolia/dialogs/selectParagraph.html", "", "", locale);
194 }
195
196 public void preview(boolean isPreview) {
197 LegacyJavascript.mgnlPreview(isPreview);
198 }
199
200 public void showTree(String workspace, String path) {
201 LegacyJavascript.showTree(workspace, path);
202
203 }
204
205 public void createComponent(String workspace, String path, String itemType) {
206 GWT.log("Creating [" + itemType + "] in workspace [" + workspace + "] at path [" + path + "]");
207
208 final StringBuilder url = new StringBuilder();
209 url.append(LegacyJavascript.getContextPath() + ".magnolia/pageeditor/PageEditorServlet");
210 url.append("?action=create");
211 url.append("&workspace=" + workspace);
212 url.append("&path=" + path);
213 url.append("&itemType=" + itemType);
214
215 RequestBuilder req = new RequestBuilder(RequestBuilder.GET, URL.encode(url.toString()));
216 req.setCallback(new RequestCallback() {
217
218 @Override
219 public void onResponseReceived(Request request, Response response) {
220 int status = response.getStatusCode();
221 String responseText = "";
222 boolean reload = false;
223
224 switch (status) {
225 case Response.SC_OK:
226 reload = true;
227 break;
228 case Response.SC_UNAUTHORIZED:
229 responseText = "Is your session expired? Please, try to login again.";
230 break;
231 default:
232 responseText = "See logs for more details.";
233 }
234
235 if (reload) {
236 UrlBuilder urlBuilder = Window.Location.createUrlBuilder();
237
238 urlBuilder.removeParameter("mgnlIntercept");
239 urlBuilder.removeParameter("mgnlPath");
240
241 Window.Location.replace(urlBuilder.buildString());
242 } else {
243 Window.alert("An error occurred on the server: response status code is " + status + "\n" + responseText);
244 }
245 }
246
247 @Override
248 public void onError(Request request, Throwable exception) {
249 Window.alert(exception.getMessage());
250 }
251 });
252 try {
253 req.send();
254 } catch (RequestException e) {
255 Window.alert("An error occurred while trying to send a request to the server: " + e.getMessage());
256 }
257
258 }
259
260 public void createChannelPreview(final String channelType, final String deviceType, final Orientation orientation) {
261 GWT.log("Creating preview for channel type [" + channelType + "] ");
262 final UrlBuilder urlBuilder = Window.Location.createUrlBuilder();
263 urlBuilder.setParameter("mgnlChannel", channelType);
264 urlBuilder.setParameter(SKIP_PAGE_EDITOR_DOM_PROCESSING, "true");
265 final PreviewChannelWidget previewChannelWidget = new PreviewChannelWidget(urlBuilder.buildString(), orientation, deviceType);
266
267 previewChannelWidget.center();
268 }
269
270 private void processDocument(Node node, MgnlElement mgnlElement) {
271 if(this.process) {
272 for (int i = 0; i < node.getChildCount(); i++) {
273 Node childNode = node.getChild(i);
274 if (childNode.getNodeType() == Comment.COMMENT_NODE) {
275
276 try {
277 mgnlElement = processCmsComment(childNode, mgnlElement);
278
279 }
280 catch (IllegalArgumentException e) {
281 GWT.log("Not CMSComment element, skipping: " + e.toString());
282
283 }
284 catch (Exception e) {
285 GWT.log("Caught undefined exception: " + e.toString());
286 }
287 }
288 else if (childNode.getNodeType() == Node.ELEMENT_NODE && mgnlElement != null) {
289 processElement(childNode, mgnlElement);
290 }
291
292 processDocument(childNode, mgnlElement);
293 }
294 }
295 }
296
297 private MgnlElement processCmsComment(Node node, MgnlElement mgnlElement) throws Exception {
298
299 CMSComment comment = new CMSComment((Comment)node.cast());
300
301 GWT.log("processing comment " + comment);
302
303 if (!comment.isClosing()) {
304
305 if (comment.getTagName().equals("cms:page")) {
306 GWT.log("element was detected as page edit bar. Injecting it...");
307 PageBarWidget pageBarWidget = new PageBarWidget(this, comment);
308 pageBarWidget.attach();
309 pageEditBarAlreadyProcessed = true;
310
311 if (pageBarWidget.isPreviewState()) {
312
313 GWT.log("We're in preview mode, stop processing DOM.");
314 this.process = false;
315 }
316 }
317
318 else {
319 try {
320 mgnlElement = new MgnlElement(comment, mgnlElement);
321
322 if (mgnlElement.getParent() == null) {
323 model.addRoot(mgnlElement);
324 }
325 else {
326 mgnlElement.getParent().getChildren().add(mgnlElement);
327 }
328
329 }
330 catch (IllegalArgumentException e) {
331 GWT.log("Not MgnlElement, skipping: " + e.toString());
332 }
333 }
334 }
335
336 else if (mgnlElement != null) {
337 mgnlElement = mgnlElement.getParent();
338 }
339
340 return mgnlElement;
341
342 }
343
344 private void processElement(Node node, MgnlElement mgnlElement) {
345 Element element = node.cast();
346 if (element.hasTagName("A")) {
347 disableLink(element);
348 }
349 model.addElement(mgnlElement, element);
350
351 if (mgnlElement.getFirstElement() == null) {
352 mgnlElement.setFirstElement(element);
353 }
354
355 if (mgnlElement.getLastElement() == null || !mgnlElement.getLastElement().isOrHasChild(element)) {
356 mgnlElement.setLastElement(element);
357 }
358
359 if (mgnlElement.isComponent()) {
360 MgnlElement area = mgnlElement.getParentArea();
361
362 if (area != null) {
363 if (area.getFirstElement() == null) {
364 area.setFirstElement(element);
365 }
366 if (area.getLastElement() == null || !area.getLastElement().isOrHasChild(element)) {
367 area.setLastElement(element);
368 }
369 }
370 }
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407 }
408
409 private void processMgnlElements() {
410 List<MgnlElement> deleteElements = new LinkedList<MgnlElement>();
411 List<MgnlElement> addElements = new LinkedList<MgnlElement>();
412
413 for (MgnlElement root :model.getRootElements()) {
414 LinkedList<MgnlElement> els = new LinkedList<MgnlElement>();
415 els.add(root);
416 els.addAll(root.getDescendants());
417 for (MgnlElement mgnlElement : els) {
418 if (model.getEditBar(mgnlElement) == null) {
419 if (mgnlElement.isArea()) {
420
421 boolean injected = AreaInjector.inject(this, mgnlElement);
422
423
424 if (!injected) {
425
426 MgnlElement parent = mgnlElement.getParent();
427
428
429 if (parent == null) {
430 deleteElements.add(mgnlElement);
431 }
432
433 for (MgnlElement child : mgnlElement.getChildren()) {
434 if (parent == null) {
435 addElements.add(child);
436 }
437 else {
438 parent.getChildren().add(child);
439 }
440 child.setParent(parent);
441
442 }
443 model.removeMgnlElement(mgnlElement);
444 }
445 }
446 else if (mgnlElement.isComponent()) {
447 GWT.log("element is edit bar placeholder. Injecting it...");
448 EditBarWidget editBarWidget = new EditBarWidget(mgnlElement, this);
449
450 model.addEditBar(mgnlElement, editBarWidget);
451 }
452 }
453 }
454 }
455 model.rootElements.removeAll(deleteElements);
456 model.rootElements.addAll(addElements);
457
458
459 }
460
461
462 private void postProcessLinksOnMobilePreview(Element root) {
463 NodeList<Element> anchors = root.getElementsByTagName("a");
464 String mobilePreviewParams = "mgnlChannel=mobile&skipPageEditorDOMProcessing=true";
465 for (int i = 0; i < anchors.getLength(); i++) {
466 AnchorElement anchor = AnchorElement.as(anchors.getItem(i));
467
468 GWT.log("Starting to process link " + anchor.getHref());
469
470 if(LegacyJavascript.isEmpty(anchor.getHref())) {
471 continue;
472 }
473 String manipulatedHref = anchor.getHref().replaceFirst(Window.Location.getProtocol() + "//" + Window.Location.getHost(), "");
474 String queryString = Window.Location.getQueryString() != null ? Window.Location.getQueryString() : "";
475
476 GWT.log("query string is " + queryString);
477
478 String queryStringRegex = queryString.replaceFirst("\\?", "\\\\?");
479 manipulatedHref = manipulatedHref.replaceFirst(queryStringRegex, "");
480 int indexOfHash = manipulatedHref.indexOf("#");
481
482 if(indexOfHash != -1) {
483 manipulatedHref = manipulatedHref.substring(indexOfHash);
484 } else {
485 if(queryString.startsWith("?")) {
486 queryString += "&" + mobilePreviewParams;
487 } else {
488 queryString = "?" + mobilePreviewParams;
489 }
490 manipulatedHref += queryString;
491 }
492 GWT.log("Resulting link is " + manipulatedHref);
493 anchor.setHref(manipulatedHref);
494 }
495
496
497
498
499
500
501 }
502
503
504 public native void disableLink(Element element)
505
506
507
508
509
510 ;
511
512 private void cleanRootElements() {
513
514 List<MgnlElement> newRoots = new LinkedList<MgnlElement>();
515 GWT.log(String.valueOf(model.rootElements.size()));
516 Iterator<MgnlElement> it = model.rootElements.iterator();
517 while (it.hasNext()) {
518 MgnlElement root = it.next();
519 if (model.getEditBar(root) == null) {
520 for (MgnlElement child : root.getChildren()) {
521 child.setParent(null);
522 newRoots.add(child);
523 }
524 it.remove();
525 }
526 }
527 GWT.log(String.valueOf(model.rootElements.size()));
528
529 model.rootElements.addAll(newRoots);
530 GWT.log(String.valueOf(model.rootElements.size()));
531
532 }
533
534 private native void onPageEditorReady()
535
536
537
538
539
540
541 ;
542
543 }