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