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