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.dom.Comment;
38 import info.magnolia.templating.editor.client.dom.MgnlElement;
39 import info.magnolia.templating.editor.client.dom.processor.CommentProcessor;
40 import info.magnolia.templating.editor.client.dom.processor.ElementProcessor;
41 import info.magnolia.templating.editor.client.dom.processor.MgnlElementProcessor;
42 import info.magnolia.templating.editor.client.dom.processor.MgnlElementProcessorFactory;
43 import info.magnolia.templating.editor.client.jsni.JavascriptUtils;
44 import info.magnolia.templating.editor.client.model.ModelStorage;
45 import info.magnolia.templating.editor.client.widget.PreviewChannel;
46 import info.magnolia.templating.editor.client.widget.PreviewChannel.Orientation;
47 import info.magnolia.templating.editor.client.widget.dnd.LegacyDragAndDrop;
48
49 import java.util.LinkedList;
50 import java.util.List;
51
52 import com.google.gwt.core.client.EntryPoint;
53 import com.google.gwt.core.client.GWT;
54 import com.google.gwt.dom.client.AnchorElement;
55 import com.google.gwt.dom.client.Document;
56 import com.google.gwt.dom.client.Element;
57 import com.google.gwt.dom.client.FormElement;
58 import com.google.gwt.dom.client.Node;
59 import com.google.gwt.dom.client.NodeList;
60 import com.google.gwt.dom.client.Style.Unit;
61 import com.google.gwt.event.dom.client.ClickEvent;
62 import com.google.gwt.event.dom.client.ClickHandler;
63 import com.google.gwt.event.dom.client.KeyCodes;
64 import com.google.gwt.event.dom.client.KeyDownEvent;
65 import com.google.gwt.event.dom.client.KeyDownHandler;
66 import com.google.gwt.event.dom.client.MouseMoveEvent;
67 import com.google.gwt.event.dom.client.MouseMoveHandler;
68 import com.google.gwt.http.client.Request;
69 import com.google.gwt.http.client.RequestBuilder;
70 import com.google.gwt.http.client.RequestCallback;
71 import com.google.gwt.http.client.RequestException;
72 import com.google.gwt.http.client.Response;
73 import com.google.gwt.http.client.URL;
74 import com.google.gwt.http.client.UrlBuilder;
75 import com.google.gwt.user.client.Window;
76 import com.google.gwt.user.client.Window.ScrollEvent;
77 import com.google.gwt.user.client.Window.ScrollHandler;
78 import com.google.gwt.user.client.ui.HTML;
79 import com.google.gwt.user.client.ui.RootPanel;
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99 public class PageEditor extends HTML implements EntryPoint {
100
101 private static final String MGNL_CHANNEL_PARAMETER = "mgnlChannel";
102 private static final String MGNL_PREVIEW_PARAMETER = "mgnlPreview";
103 private static final String MGNL_INTERCEPT_PARAMETER = "mgnlIntercept";
104 private static final String MGNL_VERSION_PARAMETER = "mgnlVersion";
105
106 private static String locale;
107 public final static ModelStorage model = ModelStorage.getInstance();
108 private final LinkedList<MgnlElement> mgnlElements = new LinkedList<MgnlElement>();
109
110
111 public static boolean process = true;
112 private static boolean isPreview = false;
113
114
115 @Override
116 public void onModuleLoad() {
117
118 String mgnlVersion = Window.Location.getParameter(MGNL_VERSION_PARAMETER);
119 if(mgnlVersion != null) {
120 return;
121 }
122
123 String preview = Window.Location.getParameter(MGNL_PREVIEW_PARAMETER);
124 if(preview != null) {
125 setPreview(Boolean.parseBoolean(preview));
126 }
127
128 String mgnlChannel = Window.Location.getParameter(MGNL_CHANNEL_PARAMETER);
129 boolean isMobile = "smartphone".equals(mgnlChannel) || "tablet".equals(mgnlChannel);
130
131 if(isMobile) {
132 GWT.log("Found " + mgnlChannel + " in request, post processing links...");
133 postProcessLinksOnMobilePreview(Document.get().getDocumentElement(), mgnlChannel);
134 return;
135 }
136
137 JavascriptUtils.setWindowLocation(Window.Location.getPath());
138
139 Window.addWindowScrollHandler(new ScrollHandler() {
140
141 @Override
142 public void onWindowScroll(ScrollEvent event) {
143 String value = event.getScrollLeft() + ":" + event.getScrollTop();
144 JavascriptUtils.setEditorPositionCookie(value);
145 }
146 });
147
148 JavascriptUtils.getCookiePosition();
149
150 locale = JavascriptUtils.detectCurrentLocale();
151
152 long startTime = System.currentTimeMillis();
153 processDocument(Document.get().getDocumentElement(), null);
154 processMgnlElements();
155
156 GWT.log("Time spent to process cms comments: " + (System.currentTimeMillis() - startTime) + "ms");
157
158 JavascriptUtils.getCookieContentId();
159
160 if (!isPreview()) {
161 RootPanel.get().addDomHandler(new ClickHandler() {
162 @Override
163 public void onClick(ClickEvent event) {
164
165 model.getFocusModel().onMouseUp((Element) event.getNativeEvent().getEventTarget().cast());
166 event.stopPropagation();
167 }
168 }, ClickEvent.getType());
169
170 RootPanel.get().addDomHandler(new MouseMoveHandler() {
171
172 @Override
173 public void onMouseMove(MouseMoveEvent event) {
174
175 Element moveElement = Document.get().getElementById("mgnlEditorMoveDiv");
176
177 if (moveElement != null) {
178 int x = event.getClientX() + Window.getScrollLeft();
179 int y = event.getClientY() + 15 + Window.getScrollTop();
180 moveElement.getStyle().setTop(y, Unit.PX);
181 moveElement.getStyle().setLeft(x, Unit.PX);
182 }
183 }
184 }, MouseMoveEvent.getType());
185 }
186
187 RootPanel.get().addDomHandler(new KeyDownHandler() {
188 @Override
189 public void onKeyDown(KeyDownEvent event) {
190 if (event.getNativeKeyCode() == KeyCodes.KEY_ESCAPE) {
191
192 if(LegacyDragAndDrop.isMoving()) {
193 LegacyDragAndDrop.moveComponentReset();
194 } else {
195 PageEditor.enablePreview(!isPreview);
196 }
197 event.preventDefault();
198 }
199 }
200 }, KeyDownEvent.getType());
201
202 JavascriptUtils.resetEditorCookies();
203
204 GWT.log("Running onPageEditorReady callbacks...");
205 onPageEditorReady();
206 }
207
208 public static void openDialog(String dialog, String workspace, String path) {
209 JavascriptUtils.mgnlOpenDialog(path, "", "", dialog, workspace, "", "", "", locale);
210 }
211
212 public static void deleteComponent(String path) {
213 JavascriptUtils.mgnlDeleteNode(path);
214 }
215
216 public static void addComponent(String workspace, String path, String nodeName, String availableComponents) {
217
218 String collectionName = null;
219
220 if (nodeName == null) {
221 nodeName = "mgnlNew";
222 }
223 if (availableComponents == null) {
224 availableComponents = "";
225 }
226 if (availableComponents.contains(",")) {
227 JavascriptUtils.mgnlOpenDialog(path, collectionName, nodeName, availableComponents, workspace, ".magnolia/dialogs/selectParagraph.html", "", "", locale);
228 } else if (!availableComponents.isEmpty()) {
229 JavascriptUtils.mgnlOpenDialog(path, collectionName, nodeName, availableComponents, workspace, ".magnolia/dialogs/editParagraph.html", "", "", locale);
230 }
231 }
232
233 public static void showTree(String workspace, String path) {
234 JavascriptUtils.showTree(workspace, path);
235
236 }
237
238 public static void createComponent(String workspace, String path, String itemType) {
239 GWT.log("Creating [" + itemType + "] in workspace [" + workspace + "] at path [" + path + "]");
240
241 final StringBuilder url = new StringBuilder();
242 url.append(JavascriptUtils.getContextPath() + ".magnolia/pageeditor/PageEditorServlet");
243 url.append("?action=create");
244 url.append("&workspace=" + workspace);
245 url.append("&path=" + path);
246 url.append("&itemType=" + itemType);
247
248 RequestBuilder req = new RequestBuilder(RequestBuilder.GET, URL.encode(url.toString()));
249 req.setCallback(new RequestCallback() {
250
251 @Override
252 public void onResponseReceived(Request request, Response response) {
253 int status = response.getStatusCode();
254 String responseText = "";
255 boolean reload = false;
256
257 switch (status) {
258 case Response.SC_OK:
259 reload = true;
260 break;
261 case Response.SC_UNAUTHORIZED:
262 responseText = "Is your session expired? Please, try to login again.";
263 break;
264 default:
265 responseText = "See logs for more details.";
266 }
267
268 if (reload) {
269 UrlBuilder urlBuilder = Window.Location.createUrlBuilder();
270
271 urlBuilder.removeParameter("mgnlIntercept");
272 urlBuilder.removeParameter("mgnlPath");
273
274 Window.Location.replace(urlBuilder.buildString());
275 } else {
276 Window.alert("An error occurred on the server: response status code is " + status + "\n" + responseText);
277 }
278 }
279
280 @Override
281 public void onError(Request request, Throwable exception) {
282 Window.alert(exception.getMessage());
283 }
284 });
285 try {
286 req.send();
287 } catch (RequestException e) {
288 Window.alert("An error occurred while trying to send a request to the server: " + e.getMessage());
289 }
290
291 }
292
293 public static void createChannelPreview(final String channelName, final Orientation orientation) {
294 setPreview(true);
295 GWT.log("Creating preview for channel type [" + channelName + "] ");
296
297 final UrlBuilder urlBuilder = Window.Location.createUrlBuilder();
298
299
300 urlBuilder.removeParameter(MGNL_PREVIEW_PARAMETER);
301 urlBuilder.removeParameter(MGNL_INTERCEPT_PARAMETER);
302 urlBuilder.removeParameter(MGNL_CHANNEL_PARAMETER);
303
304 urlBuilder.setParameter(MGNL_PREVIEW_PARAMETER, String.valueOf(isPreview()));
305 urlBuilder.setParameter(MGNL_CHANNEL_PARAMETER, channelName);
306 final PreviewChannel previewChannelWidget = new PreviewChannel(urlBuilder.buildString(), orientation, channelName);
307
308 previewChannelWidget.center();
309 }
310
311 private void processDocument(Node node, MgnlElement mgnlElement) {
312 if(!process) {
313 return;
314 }
315 boolean proceed = true;
316 for (int i = 0; i < node.getChildCount(); i++) {
317 Node childNode = node.getChild(i);
318 if (childNode.getNodeType() == Comment.COMMENT_NODE) {
319 try {
320 mgnlElement = CommentProcessor.process(childNode, mgnlElement);
321 }
322 catch (IllegalArgumentException e) {
323 GWT.log("Not CMSComment element, skipping: " + e.toString());
324 }
325 catch (Exception e) {
326 GWT.log("Caught undefined exception: " + e.toString());
327 consoleLog(e.getMessage());
328 }
329 }
330 else if (childNode.getNodeType() == Node.ELEMENT_NODE && mgnlElement != null) {
331 proceed = ElementProcessor.process(childNode, mgnlElement);
332 }
333 if (proceed) {
334 processDocument(childNode, mgnlElement);
335 }
336 }
337 }
338
339 private void processMgnlElements() {
340 List<MgnlElement> rootElements = new LinkedList<MgnlElement>(model.getRootElements());
341 for (MgnlElement root : rootElements) {
342 LinkedList<MgnlElement> elements = new LinkedList<MgnlElement>();
343 elements.add(root);
344 elements.addAll(root.getDescendants());
345
346 for (MgnlElement mgnlElement : elements) {
347 try {
348 MgnlElementProcessor processor = MgnlElementProcessorFactory.getProcessor(mgnlElement);
349 processor.process();
350 } catch (IllegalArgumentException e) {
351 GWT.log("MgnlFactory could not instantiate class. The element is neither an area nor component.");
352 } catch (IllegalStateException e) {
353 GWT.log(e.getMessage());
354 consoleLog(e.getMessage());
355 } catch (Exception e) {
356 GWT.log("Caught undefined exception: " + e.toString());
357 consoleLog("Caught undefined exception: " + e.toString());
358 }
359 }
360 }
361
362 }
363
364
365 private void postProcessLinksOnMobilePreview(Element root, String channel) {
366 NodeList<Element> anchors = root.getElementsByTagName("a");
367
368 final String mobilePreviewParams = MGNL_CHANNEL_PARAMETER+"="+channel+"&"+ MGNL_PREVIEW_PARAMETER+"=true";
369
370 for (int i = 0; i < anchors.getLength(); i++) {
371 AnchorElement anchor = AnchorElement.as(anchors.getItem(i));
372
373 GWT.log("Starting to process link " + anchor.getHref());
374
375 if(JavascriptUtils.isEmpty(anchor.getHref())) {
376 continue;
377 }
378 String manipulatedHref = anchor.getHref().replaceFirst(Window.Location.getProtocol() + "//" + Window.Location.getHost(), "");
379 String queryString = Window.Location.getQueryString() != null ? Window.Location.getQueryString() : "";
380
381 GWT.log("query string is " + queryString);
382
383 String queryStringRegex = queryString.replaceFirst("\\?", "\\\\?");
384 manipulatedHref = manipulatedHref.replaceFirst(queryStringRegex, "");
385 int indexOfHash = manipulatedHref.indexOf("#");
386
387 if(indexOfHash != -1) {
388 manipulatedHref = manipulatedHref.substring(indexOfHash);
389 } else {
390 if(!queryString.contains(mobilePreviewParams)) {
391 if(queryString.startsWith("?")) {
392 queryString += "&" + mobilePreviewParams;
393 } else {
394 queryString = "?" + mobilePreviewParams;
395 }
396 }
397 manipulatedHref += queryString;
398 }
399 GWT.log("Resulting link is " + manipulatedHref);
400 anchor.setHref(manipulatedHref);
401 }
402 NodeList<Element> forms = root.getElementsByTagName("form");
403
404 for (int i = 0; i < forms.getLength(); i++) {
405 FormElement form = FormElement.as(forms.getItem(i));
406 form.setAction(form.getAction().concat("?"+ mobilePreviewParams));
407 }
408 }
409
410
411 private native void onPageEditorReady()
412
413
414
415
416
417
418 ;
419
420
421
422
423 public static void enablePreview(boolean preview) {
424 setPreview(preview);
425 final UrlBuilder urlBuilder = Window.Location.createUrlBuilder();
426 GWT.log("Current url is [" + urlBuilder.buildString() + "], setting preview to " + isPreview());
427
428
429 urlBuilder.removeParameter(MGNL_PREVIEW_PARAMETER);
430 urlBuilder.removeParameter(MGNL_INTERCEPT_PARAMETER);
431 urlBuilder.removeParameter(MGNL_CHANNEL_PARAMETER);
432
433 urlBuilder.setParameter(MGNL_INTERCEPT_PARAMETER, "PREVIEW");
434 urlBuilder.setParameter(MGNL_PREVIEW_PARAMETER, String.valueOf(isPreview()));
435
436 if(isPreview()) {
437 urlBuilder.setParameter(MGNL_CHANNEL_PARAMETER, "desktop");
438 } else {
439 urlBuilder.setParameter(MGNL_CHANNEL_PARAMETER, "all");
440 }
441
442
443 final String newUrl = URL.decode(urlBuilder.buildString());
444 GWT.log("New url is [" + newUrl + "]");
445
446 Window.Location.replace(newUrl);
447 }
448
449
450
451
452 public static boolean isPreview() {
453 return isPreview;
454 }
455
456 public static void setPreview(boolean preview) {
457 isPreview = preview;
458 }
459
460 native void consoleLog(String message)
461
462
463
464 ;
465 }