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