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