001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.ade.containerpage.client;
029
030import org.opencms.ade.containerpage.client.CmsContainerpageController.I_ReloadHandler;
031import org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer;
032import org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel;
033import org.opencms.ade.containerpage.client.ui.CmsOptionDialog;
034import org.opencms.ade.containerpage.client.ui.I_CmsDropContainer;
035import org.opencms.ade.containerpage.shared.CmsCntPageData;
036import org.opencms.ade.containerpage.shared.CmsDialogOptionsAndInfo;
037import org.opencms.ade.contenteditor.client.CmsContentEditor;
038import org.opencms.ade.contenteditor.client.CmsEditorContext;
039import org.opencms.ade.contenteditor.client.I_CmsEditorCloseHandler;
040import org.opencms.ade.contenteditor.shared.CmsContentDefinition;
041import org.opencms.ade.contenteditor.shared.CmsEditHandlerData;
042import org.opencms.ade.publish.shared.CmsPublishOptions;
043import org.opencms.gwt.client.CmsCoreProvider;
044import org.opencms.gwt.client.CmsEditableData;
045import org.opencms.gwt.client.I_CmsEditableData;
046import org.opencms.gwt.client.ui.contenteditor.CmsContentEditorDialog;
047import org.opencms.gwt.client.ui.contenteditor.CmsContentEditorDialog.DialogOptions;
048import org.opencms.gwt.client.ui.contenteditor.I_CmsContentEditorHandler;
049import org.opencms.gwt.client.util.CmsDebugLog;
050import org.opencms.gwt.client.util.CmsDomUtil;
051import org.opencms.gwt.client.util.I_CmsSimpleCallback;
052import org.opencms.gwt.shared.CmsGwtConstants;
053import org.opencms.util.CmsStringUtil;
054import org.opencms.util.CmsUUID;
055
056import java.util.ArrayList;
057import java.util.HashMap;
058import java.util.List;
059import java.util.Map;
060
061import com.google.gwt.dom.client.Element;
062import com.google.gwt.http.client.URL;
063import com.google.gwt.json.client.JSONBoolean;
064import com.google.gwt.json.client.JSONNumber;
065import com.google.gwt.json.client.JSONObject;
066import com.google.gwt.json.client.JSONString;
067import com.google.gwt.user.client.Command;
068import com.google.gwt.user.client.History;
069import com.google.gwt.user.client.Timer;
070import com.google.gwt.user.client.Window;
071
072import elemental2.dom.DomGlobal;
073import jsinterop.base.Js;
074
075/**
076 * The container-page editor implementation of the XML content editor handler.<p>
077 *
078 * @since 8.0.0
079 */
080public class CmsContentEditorHandler implements I_CmsContentEditorHandler {
081
082    /** Content editor hash key whre a return to the opened editor is not possible. */
083    private static final String EDITOR_FOR_NO_RETURN_HASH_KEY = "cE";
084
085    /** Content editor hash key used for history management. */
086    private static final String EDITOR_HASH_KEY = "cE:";
087
088    /** Saved scroll position. */
089    public static Integer scrollPosition;
090
091    /** The container-page handler. */
092    CmsContainerpageHandler m_handler;
093
094    /** The content element to be replaced by the edited content. */
095    CmsContainerPageElementPanel m_replaceElement;
096
097    /** The currently edited element's id. */
098    private String m_currentElementId;
099
100    /** The depending element's id. */
101    private String m_dependingElementId;
102
103    /** Flag indicating the content editor is currently opened. */
104    private boolean m_editorOpened;
105
106    /**
107     * Constructor.<p>
108     *
109     * @param handler the container-page handler
110     */
111    public CmsContentEditorHandler(CmsContainerpageHandler handler) {
112
113        m_handler = handler;
114    }
115
116    /**
117     * Closes the content editor.<p>
118     */
119    public void closeContentEditor() {
120
121        CmsContentEditor.getInstance().closeEditor();
122        m_editorOpened = false;
123    }
124
125    /**
126     * @see org.opencms.gwt.client.ui.contenteditor.I_CmsContentEditorHandler#onClose(java.lang.String, org.opencms.util.CmsUUID, boolean, boolean, boolean)
127     */
128    public void onClose(
129        String sitePath,
130        CmsUUID structureId,
131        boolean isNew,
132        boolean hasChangedSettings,
133        boolean usedPublishDialog) {
134
135        if (m_currentElementId == null) {
136            m_currentElementId = structureId.toString();
137        }
138        // we keep track of how many reloads are still ongoing - if all of them are done, we can send the edit events
139        final int[] reloadCounter = {0};
140
141        I_ReloadHandler reloadHandler = new I_ReloadHandler() {
142
143            private List<Runnable> m_todo = new ArrayList<>();
144
145            @Override
146            public void finish() {
147
148                if (usedPublishDialog) {
149                    m_handler.m_controller.startPublishLockCheck();
150                }
151                reloadCounter[0] -= 1;
152                if (reloadCounter[0] <= 0) {
153                    m_todo.forEach(item -> item.run());
154                }
155                if (scrollPosition != null) {
156                    final int top = scrollPosition.intValue();
157                    scrollPosition = null;
158                    Timer timer = new Timer() {
159
160                        @Override
161                        public void run() {
162
163                            DomGlobal.document.documentElement.scrollTop = top;
164                        }
165
166                    };
167                    timer.schedule(1);
168                }
169
170            }
171
172            @Override
173            public void onReload(CmsContainerPageElementPanel oldElement, CmsContainerPageElementPanel newElement) {
174
175                m_todo.add(() -> {
176                    m_handler.m_controller.sendElementEditedContent(
177                        newElement,
178                        Js.cast(oldElement.getElement()),
179                        isNew);
180
181                });
182            }
183
184        };
185
186        if (m_replaceElement != null) {
187            if ((m_handler.m_controller.getData().getDetailId() != null)
188                && m_replaceElement.getId().startsWith(m_handler.m_controller.getData().getDetailId().toString())) {
189                Window.Location.assign(
190                    CmsStringUtil.joinPaths(
191                        CmsCoreProvider.get().getVfsPrefix(),
192                        CmsContainerpageController.getCurrentUri(),
193                        CmsContainerpageController.getServerId(m_currentElementId)));
194            }
195            reloadCounter[0] += 1;
196            m_handler.m_controller.replaceElement(m_replaceElement, m_currentElementId, reloadHandler);
197            m_replaceElement = null;
198            if (m_dependingElementId != null) {
199                reloadCounter[0] += 1;
200                m_handler.m_controller.reloadElements(new String[] {m_dependingElementId}, reloadHandler);
201                m_dependingElementId = null;
202            }
203        } else if (m_dependingElementId != null) {
204            reloadCounter[0] += 1;
205            m_handler.m_controller.reloadElements(
206                new String[] {m_currentElementId, m_dependingElementId},
207                reloadHandler);
208            m_dependingElementId = null;
209        } else {
210            reloadCounter[0] += 1;
211            m_handler.m_controller.reloadElements(new String[] {m_currentElementId}, reloadHandler);
212        }
213        if (m_currentElementId != null) {
214            m_handler.addToRecent(m_currentElementId);
215        }
216        m_handler.enableToolbarButtons();
217        m_handler.activateSelection();
218        m_handler.m_controller.setContentEditing(false);
219        m_handler.m_controller.reInitInlineEditing();
220        m_currentElementId = null;
221        if (hasChangedSettings) {
222            m_handler.m_controller.setPageChanged(new Runnable[] {});
223        }
224        m_editorOpened = false;
225    }
226
227    /**
228     * Opens the XML content editor.<p>
229     *
230     * @param element the container element widget
231     * @param inline <code>true</code> to open the in-line editor for the given element if available
232     * @param wasNew <code>true</code> in case this is a newly created element not previously edited
233     */
234    public void openDialog(final CmsContainerPageElementPanel element, final boolean inline, boolean wasNew) {
235
236        if (!inline && element.hasEditHandler()) {
237            m_handler.m_controller.getEditOptions(
238                element.getId(),
239                false,
240                new I_CmsSimpleCallback<CmsDialogOptionsAndInfo>() {
241
242                    public void execute(CmsDialogOptionsAndInfo editOptions) {
243
244                        final I_CmsSimpleCallback<CmsUUID> editCallBack = new I_CmsSimpleCallback<CmsUUID>() {
245
246                            public void execute(CmsUUID arg) {
247
248                                String contentId = element.getId();
249                                if (!element.getId().startsWith(arg.toString())) {
250                                    // the content structure ID has changed, the current element needs to be replaced after editing
251                                    m_replaceElement = element;
252                                    contentId = arg.toString();
253                                }
254                                internalOpenDialog(element, contentId, inline, wasNew);
255                            }
256                        };
257                        if (editOptions == null) {
258                            internalOpenDialog(element, element.getId(), inline, wasNew);
259                        } else if (editOptions.getOptions().getOptions().size() == 1) {
260                            m_handler.m_controller.prepareForEdit(
261                                element.getId(),
262                                editOptions.getOptions().getOptions().get(0).getValue(),
263                                editCallBack);
264                        } else {
265                            CmsOptionDialog dialog = new CmsOptionDialog(
266                                Messages.get().key(Messages.GUI_EDIT_HANDLER_SELECT_EDIT_OPTION_0),
267                                editOptions.getOptions(),
268                                editOptions.getInfo(),
269                                new I_CmsSimpleCallback<String>() {
270
271                                    public void execute(String arg) {
272
273                                        m_handler.m_controller.prepareForEdit(element.getId(), arg, editCallBack);
274                                    }
275                                });
276                            dialog.addDialogClose(new Command() {
277
278                                public void execute() {
279
280                                    cancelEdit();
281                                }
282                            });
283                            dialog.center();
284                        }
285                    }
286                });
287        } else {
288            internalOpenDialog(element, element.getId(), inline, wasNew);
289        }
290    }
291
292    /**
293     * Opens the XML content editor, checking for if an edit handler is configured first.<p>
294     *
295     * @param editableData the data of the element to edit
296     * @param isNew <code>true</code> if a new resource should be created
297     * @param dependingElementId the id of a depending element
298     * @param mode the element creation mode
299     * @param handlerDataForNew the edit handler data, if we are using an edit handler to create a new element; null otherwise
300     */
301    public void openDialog(
302        final I_CmsEditableData editableData,
303        final boolean isNew,
304        final String dependingElementId,
305        final String mode,
306        final CmsEditHandlerData handlerDataForNew) {
307
308        if (!m_editorOpened) {
309            m_editorOpened = true;
310            m_handler.disableToolbarButtons();
311            m_handler.deactivateCurrentButton();
312
313            if (!isNew && (editableData.getStructureId() != null) && editableData.hasEditHandler()) {
314                final String elementId = CmsContentEditor.getClientIdForEditable(editableData);
315                m_handler.m_controller.getEditOptions(
316                    elementId,
317                    true,
318                    new I_CmsSimpleCallback<CmsDialogOptionsAndInfo>() {
319
320                        public void execute(CmsDialogOptionsAndInfo editOptions) {
321
322                            final I_CmsSimpleCallback<CmsUUID> editCallBack = new I_CmsSimpleCallback<CmsUUID>() {
323
324                                public void execute(CmsUUID arg) {
325
326                                    I_CmsEditableData data = editableData;
327                                    if (!data.getStructureId().equals(arg)) {
328                                        // the content structure ID has changed, change the editableData
329                                        data = new CmsEditableData(data);
330                                        ((CmsEditableData)data).setStructureId(arg);
331                                    }
332                                    internalOpenDialog(data, isNew, dependingElementId, mode, null);
333                                }
334                            };
335                            if (editOptions == null) {
336                                internalOpenDialog(editableData, isNew, dependingElementId, mode, null);
337                            } else if (editOptions.getOptions().getOptions().size() == 1) {
338                                m_handler.m_controller.prepareForEdit(
339                                    elementId,
340                                    editOptions.getOptions().getOptions().get(0).getValue(),
341                                    editCallBack);
342                            } else {
343                                CmsOptionDialog dialog = new CmsOptionDialog(
344                                    Messages.get().key(Messages.GUI_EDIT_HANDLER_SELECT_EDIT_OPTION_0),
345                                    editOptions.getOptions(),
346                                    editOptions.getInfo(),
347                                    new I_CmsSimpleCallback<String>() {
348
349                                        public void execute(String arg) {
350
351                                            m_handler.m_controller.prepareForEdit(elementId, arg, editCallBack);
352                                        }
353                                    });
354                                dialog.addDialogClose(new Command() {
355
356                                    public void execute() {
357
358                                        cancelEdit();
359                                    }
360                                });
361                                dialog.center();
362                            }
363                        }
364                    });
365            } else {
366                internalOpenDialog(editableData, isNew, dependingElementId, mode, handlerDataForNew);
367            }
368
369        } else {
370            CmsDebugLog.getInstance().printLine("Editor is already being opened.");
371        }
372    }
373
374    /**
375     * Opens the content editor according to the history hash.<p>
376     *
377     * @param historyHash the history hash
378     */
379    public void openEditorForHistory(String historyHash) {
380
381        if (historyHash.startsWith(EDITOR_HASH_KEY)) {
382            if (!m_editorOpened) {
383                m_editorOpened = true;
384                CmsDebugLog.getInstance().printLine("EditorHandler - Opening editor from history");
385                m_handler.m_controller.setContentEditing(true);
386                String id = historyHash.substring(EDITOR_HASH_KEY.length(), historyHash.indexOf(";"));
387                if (id.contains(",")) {
388                    String[] ids = id.split(",");
389                    m_currentElementId = URL.decodePathSegment(ids[0]);
390                    m_dependingElementId = URL.decodePathSegment(ids[1]);
391                } else {
392                    m_currentElementId = URL.decodePathSegment(id);
393                }
394                I_CmsEditorCloseHandler onClose = new I_CmsEditorCloseHandler() {
395
396                    public void onClose(boolean hasChangedSettings, boolean usedPublishDialog) {
397
398                        addClosedEditorHistoryItem();
399                        CmsContentEditorHandler.this.onClose(
400                            null,
401                            new CmsUUID(getCurrentElementId()),
402                            false,
403                            hasChangedSettings,
404                            usedPublishDialog);
405                    }
406                };
407                String editorLocale = CmsCoreProvider.get().getLocale();
408
409                CmsContentEditor.getInstance().openFormEditor(
410                    getEditorContext(),
411                    editorLocale,
412                    m_currentElementId,
413                    null,
414                    null,
415                    null,
416                    null,
417                    null,
418                    m_handler.m_controller.getData().getMainLocale(),
419                    null,
420                    onClose);
421            }
422        } else {
423            closeContentEditor();
424        }
425    }
426
427    /**
428     * Returns the currently edited element's id.<p>
429     *
430     * @return the currently edited element's id
431     */
432    protected String getCurrentElementId() {
433
434        return m_currentElementId;
435    }
436
437    /**
438     * Adds a history item for the closed editor.<p>
439     */
440    void addClosedEditorHistoryItem() {
441
442        History.newItem("", false);
443    }
444
445    /**
446     * Cancels opening the editor.<p>
447     */
448    void cancelEdit() {
449
450        m_handler.enableToolbarButtons();
451        m_handler.activateSelection();
452        m_handler.m_controller.setContentEditing(false);
453        m_handler.m_controller.reInitInlineEditing();
454        m_replaceElement = null;
455        m_dependingElementId = null;
456        m_currentElementId = null;
457        m_editorOpened = false;
458    }
459
460    /**
461     * Gets the editor context to use for the Acacia editor.<p>
462     *
463     * @return the editor context
464     */
465    CmsEditorContext getEditorContext() {
466
467        CmsEditorContext result = new CmsEditorContext();
468        result.getPublishParameters().put(
469            CmsPublishOptions.PARAM_CONTAINERPAGE,
470            "" + CmsCoreProvider.get().getStructureId());
471        result.getPublishParameters().put(
472            CmsPublishOptions.PARAM_DETAIL,
473            "" + CmsContainerpageController.get().getData().getDetailId());
474        result.getPublishParameters().put(CmsPublishOptions.PARAM_START_WITH_CURRENT_PAGE, "");
475        elemental2.dom.HTMLMetaElement meta = Js.cast(
476            elemental2.dom.DomGlobal.document.querySelector(
477                "meta[name=" + CmsGwtConstants.META_EDITOR_STYLESHEET + "]"));
478        if (meta != null) {
479            result.setEditorStylesheet(meta.content);
480        }
481        return result;
482    }
483
484    /**
485     * Opens the edit dialog.<p>
486     *
487     * @param element the element to edit
488     * @param editContentId the edit content id
489     * @param inline <code>true</code> to edit the content inline
490     * @param wasNew <code>true</code> in case this is a newly created element not previously edited
491     */
492    void internalOpenDialog(
493        final CmsContainerPageElementPanel element,
494        String editContentId,
495        final boolean inline,
496        boolean wasNew) {
497
498        if (!m_editorOpened) {
499            m_editorOpened = true;
500            m_handler.disableToolbarButtons();
501            m_handler.deactivateCurrentButton();
502            m_currentElementId = editContentId;
503            final String serverId = CmsContainerpageController.getServerId(m_currentElementId);
504            final Runnable classicEdit = new Runnable() {
505
506                public void run() {
507
508                    CmsEditableData editableData = new CmsEditableData();
509                    editableData.setElementLanguage(CmsCoreProvider.get().getLocale());
510                    editableData.setStructureId(new CmsUUID(serverId));
511                    editableData.setSitePath(element.getSitePath());
512                    editableData.setMainLanguage(m_handler.m_controller.getData().getMainLocale());
513                    CmsContentEditorDialog.get().openEditDialog(
514                        editableData,
515                        false,
516                        null,
517                        new DialogOptions(),
518                        CmsContentEditorHandler.this);
519                }
520            };
521
522            if (m_handler.m_controller.getData().isUseClassicEditor() || element.isNewEditorDisabled()) {
523                classicEdit.run();
524            } else {
525                String editorLocale = CmsCoreProvider.get().getLocale();
526                final String mainLocale;
527                if (m_handler.m_controller.getData().getMainLocale() == null) {
528                    Element htmlEl = CmsDomUtil.querySelector(
529                        "[" + CmsGwtConstants.ATTR_DATA_ID + "*='" + serverId + "']",
530                        element.getElement());
531                    if (htmlEl != null) {
532                        String entityId = htmlEl.getAttribute(CmsGwtConstants.ATTR_DATA_ID);
533                        mainLocale = CmsContentDefinition.getLocaleFromId(entityId);
534                    } else {
535                        mainLocale = null;
536                    }
537                } else {
538                    mainLocale = m_handler.m_controller.getData().getMainLocale();
539                }
540                I_CmsEditorCloseHandler onClose = new I_CmsEditorCloseHandler() {
541
542                    public void onClose(boolean hasChangedSettings, boolean usedPublishDialog) {
543
544                        addClosedEditorHistoryItem();
545                        CmsContentEditorHandler.this.onClose(
546                            element.getSitePath(),
547                            new CmsUUID(serverId),
548                            wasNew,
549                            hasChangedSettings,
550                            usedPublishDialog);
551
552                    }
553                };
554                if (inline && CmsContentEditor.hasEditable(element.getElement())) {
555                    addEditingHistoryItem(true);
556                    CmsEditorContext context = getEditorContext();
557                    context.setReusedElement(element.isReused());
558                    context.setHtmlContextInfo(getContextInfo(element));
559                    // remove expired style before initializing the editor
560                    element.setReleasedAndNotExpired(true);
561                    // in case of new elements, ignore load time
562                    long loadTime = wasNew ? Long.MAX_VALUE : m_handler.m_controller.getLoadTime();
563                    CmsContentEditor.getInstance().openInlineEditor(
564                        context,
565                        new CmsUUID(serverId),
566                        editorLocale,
567                        element,
568                        mainLocale,
569                        loadTime,
570                        onClose);
571                } else {
572                    addEditingHistoryItem(false);
573                    Map<String, String> settingPresets = new HashMap<String, String>();
574                    CmsEditorContext context = getEditorContext();
575                    context.setReusedElement(element.isReused());
576                    I_CmsDropContainer dropContainer = element.getParentTarget();
577                    if (dropContainer instanceof CmsContainerPageContainer) {
578                        CmsContainerPageContainer container = (CmsContainerPageContainer)dropContainer;
579                        settingPresets.putAll(container.getSettingPresets());
580                    }
581                    context.setSettingPresets(settingPresets);
582
583                    boolean allowSettings = m_handler.m_controller.getData().allowSettingsInEditor()
584                        && !m_handler.m_controller.isEditingDisabled()
585                        && !serverId.equals(String.valueOf(m_handler.m_controller.getData().getDetailId()));
586                    I_CmsSimpleCallback<Boolean> openEditor = new I_CmsSimpleCallback<Boolean>() {
587
588                        public void execute(Boolean lockedPage) {
589
590                            CmsContentEditor.getInstance().openFormEditor(
591                                context,
592                                editorLocale,
593                                serverId,
594                                lockedPage.booleanValue() ? getCurrentElementId() : null,
595                                null,
596                                null,
597                                null,
598                                null,
599                                mainLocale,
600                                null,
601                                onClose);
602                        }
603                    };
604                    if (allowSettings) {
605                        if (m_handler.m_controller.getData().getDetailContainerPage() != null) {
606                            CmsCoreProvider.get().lock(
607                                m_handler.m_controller.getData().getDetailContainerPage(),
608                                m_handler.m_controller.getLoadTime(),
609                                openEditor);
610                        } else {
611                            CmsCoreProvider.get().lock(
612                                CmsCoreProvider.get().getStructureId(),
613                                m_handler.m_controller.getLoadTime(),
614                                openEditor);
615                        }
616                    } else {
617                        openEditor.execute(Boolean.FALSE);
618                    }
619
620                }
621            }
622        } else {
623            CmsDebugLog.getInstance().printLine("Editor is already being opened.");
624        }
625    }
626
627    /**
628     * Opens the XML content editor internally.<p>
629     *
630     * @param editableData the data of the element to edit
631     * @param isNew <code>true</code> if a new resource should be created
632     * @param dependingElementId the id of a depending element
633     * @param mode the element creation mode
634     * @param editHandlerData the edit handler data, if we are using an edit handler to create a new element; null otherwise
635     */
636    void internalOpenDialog(
637        final I_CmsEditableData editableData,
638        final boolean isNew,
639        String dependingElementId,
640        String mode,
641        CmsEditHandlerData editHandlerData) {
642
643        if ((editableData.getStructureId() != null) && !isNew) {
644            m_currentElementId = editableData.getStructureId().toString();
645        } else {
646            m_currentElementId = null;
647        }
648        m_dependingElementId = dependingElementId;
649        if (m_handler.m_controller.getData().isUseClassicEditor()) {
650            CmsContentEditorDialog.get().openEditDialog(editableData, isNew, mode, new DialogOptions(), this);
651        } else {
652            String newLink = null;
653            if (isNew) {
654                newLink = editableData.getNewLink();
655                // the new link is URL encoded twice, decode it
656                newLink = URL.decodeQueryString(newLink);
657                newLink = URL.decodeQueryString(newLink);
658            }
659            addEditingHistoryItem(isNew);
660            CmsContentEditor.getInstance().openFormEditor(
661                getEditorContext(),
662                CmsCoreProvider.get().getLocale(),
663                editableData.getStructureId().toString(),
664                null,
665                newLink,
666                null,
667                editableData.getPostCreateHandler(),
668                mode,
669                m_handler.m_controller.getData().getMainLocale(),
670                editHandlerData,
671                new I_CmsEditorCloseHandler() {
672
673                    public void onClose(boolean hasChangedSettings, boolean usedPublishDialog) {
674
675                        addClosedEditorHistoryItem();
676                        CmsContentEditorHandler.this.onClose(
677                            editableData.getSitePath(),
678                            editableData.getStructureId(),
679                            isNew,
680                            hasChangedSettings,
681                            usedPublishDialog);
682                    }
683                });
684        }
685
686    }
687
688    /**
689     * Adds a history item for the opened editor.<p>
690     * Use the prohibitReturn flag to deny a return to the opened editor through the browser history.
691     * Use this feature for inline editing or when opening the editor for new resources.<p>
692     *
693     * @param prohibitReturn if <code>true</code> returning to the opened editor through the browser history is denied
694     */
695    private void addEditingHistoryItem(boolean prohibitReturn) {
696
697        if (prohibitReturn) {
698            History.newItem(EDITOR_FOR_NO_RETURN_HASH_KEY, false);
699        } else {
700            History.newItem(
701                EDITOR_HASH_KEY
702                    + CmsContainerpageController.getServerId(getCurrentElementId())
703                    + (m_dependingElementId != null ? "," + m_dependingElementId + ";" : ";"),
704                false);
705        }
706    }
707
708    /**
709     * Returns the HTML context info for the given element.<p>
710     *
711     * @param element the edited element
712     *
713     * @return the JSON string
714     */
715    private String getContextInfo(CmsContainerPageElementPanel element) {
716
717        CmsContainerPageContainer container;
718        if (m_handler.m_controller.isGroupcontainerEditing()) {
719            container = (CmsContainerPageContainer)((CmsContainerPageElementPanel)element.getParentTarget()).getParentTarget();
720        } else {
721            container = (CmsContainerPageContainer)element.getParentTarget();
722        }
723        JSONObject result = new JSONObject();
724        putString(result, CmsCntPageData.JSONKEY_ELEMENT_ID, element.getId());
725        CmsUUID detailId = m_handler.m_controller.getData().getDetailId();
726        if (detailId != null) {
727            putString(result, CmsCntPageData.JSONKEY_DETAIL_ELEMENT_ID, "" + detailId);
728        }
729        putString(result, CmsCntPageData.JSONKEY_NAME, "" + container.getContainerId());
730        putString(result, CmsCntPageData.JSONKEY_TYPE, "" + container.getContainerType());
731        result.put(CmsCntPageData.JSONKEY_WIDTH, new JSONNumber(container.getConfiguredWidth()));
732        result.put(CmsCntPageData.JSONKEY_DETAILVIEW, JSONBoolean.getInstance(container.isDetailView()));
733        result.put(
734            CmsCntPageData.JSONKEY_ISDETAILVIEWCONTAINER,
735            JSONBoolean.getInstance(container.isDetailViewContainer()));
736        result.put(CmsCntPageData.JSONKEY_DETAILONLY, JSONBoolean.getInstance(container.isDetailOnly()));
737        result.put(CmsCntPageData.JSONKEY_MAXELEMENTS, new JSONNumber(1));
738        JSONObject presets = new JSONObject();
739        Map<String, String> presetsMap = container.getSettingPresets();
740        for (Map.Entry<String, String> entry : presetsMap.entrySet()) {
741            presets.put(entry.getKey(), new JSONString(entry.getValue()));
742        }
743        result.put(CmsCntPageData.JSONKEY_PRESETS, presets);
744        return result.toString();
745    }
746
747    /**
748     * Adds a String value to the JSON object.<p>
749     *
750     * @param obj the object to manipulate
751     * @param key the key
752     * @param val the value
753     */
754    private void putString(JSONObject obj, String key, String val) {
755
756        obj.put(key, new JSONString(val));
757    }
758
759}