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