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