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.sitemap.client.attributes;
029
030import org.opencms.ade.sitemap.client.CmsSitemapView;
031import org.opencms.ade.sitemap.client.Messages;
032import org.opencms.ade.sitemap.shared.CmsSitemapAttributeData;
033import org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapServiceAsync;
034import org.opencms.gwt.client.rpc.CmsRpcAction;
035import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
036import org.opencms.gwt.client.ui.input.I_CmsFormField;
037import org.opencms.gwt.client.ui.input.I_CmsFormWidget;
038import org.opencms.gwt.client.ui.input.form.A_CmsFormFieldPanel;
039import org.opencms.gwt.client.ui.input.form.CmsBasicFormField;
040import org.opencms.gwt.client.ui.input.form.CmsDialogFormHandler;
041import org.opencms.gwt.client.ui.input.form.CmsForm;
042import org.opencms.gwt.client.ui.input.form.CmsFormDialog;
043import org.opencms.gwt.client.ui.input.form.CmsFormRow;
044import org.opencms.gwt.client.ui.input.form.CmsInfoBoxFormFieldPanel;
045import org.opencms.gwt.client.ui.input.form.CmsWidgetFactoryRegistry;
046import org.opencms.gwt.client.ui.input.form.I_CmsFormSubmitHandler;
047import org.opencms.gwt.client.ui.input.form.I_CmsFormWidgetMultiFactory;
048import org.opencms.gwt.shared.CmsListInfoBean;
049import org.opencms.util.CmsUUID;
050import org.opencms.xml.content.CmsXmlContentProperty;
051
052import java.util.Collections;
053import java.util.Map;
054import java.util.Set;
055
056import com.google.common.base.Optional;
057import com.google.gwt.event.logical.shared.AttachEvent;
058import com.google.gwt.event.shared.HandlerRegistration;
059import com.google.gwt.user.client.Window;
060import com.google.gwt.user.client.ui.Widget;
061
062import jsinterop.annotations.JsMethod;
063
064/**
065 * Sitemap attribute editor dialog.
066 */
067public class CmsAttributesDialog extends CmsFormDialog {
068
069    /**
070     * Field panel for the form fields.
071     */
072    public static class FieldPanel extends CmsInfoBoxFormFieldPanel {
073
074        /**
075         * Creates a new instance.
076         *
077         * @param info the list info bean for the sitemap configuration file
078         */
079        public FieldPanel(CmsListInfoBean info) {
080
081            super(info);
082        }
083
084        /**
085         * @see org.opencms.gwt.client.ui.input.form.A_CmsFormFieldPanel#createRow(org.opencms.gwt.client.ui.input.I_CmsFormField)
086         */
087        @Override
088        protected CmsFormRow createRow(I_CmsFormField field) {
089
090            // show description on help icons instead of the title
091            CmsFormRow row = createRow(
092                field.getLabel(),
093                A_CmsFormFieldPanel.NO_DESCRIPTION,
094                (Widget)field.getWidget(),
095                field.getDescription(),
096                true);
097            return row;
098        }
099
100    }
101
102    /** The sitemap attribute data. */
103    private CmsSitemapAttributeData m_data;
104
105    /** The registration for the WindowClose handler registered by this dialog. */
106    private HandlerRegistration m_windowCloseRegistration;
107
108    /**
109     * Creates a new instance.
110     *
111     * @param data the sitemap attribute data
112     */
113    public CmsAttributesDialog(CmsSitemapAttributeData data) {
114
115        super(Messages.get().key(Messages.GUI_EDIT_ATTRIBUTES_0), new CmsForm(false), null);
116        setAnimationEnabled(false);
117        setUseAnimation(false);
118        addStyleName(I_CmsLayoutBundle.INSTANCE.attributeEditorCss().attributeEditor());
119        m_data = data;
120
121        I_CmsFormSubmitHandler submitHandler = new I_CmsFormSubmitHandler() {
122
123            /**
124             * @see org.opencms.gwt.client.ui.input.form.I_CmsFormSubmitHandler#onSubmitForm(org.opencms.gwt.client.ui.input.form.CmsForm, java.util.Map, java.util.Set)
125             */
126            public void onSubmitForm(
127                CmsForm formParam,
128                final Map<String, String> fieldValues,
129                Set<String> editedFields) {
130
131                final I_CmsSitemapServiceAsync service = CmsSitemapView.getInstance().getController().getService();
132                CmsRpcAction<Void> action = new CmsRpcAction<Void>() {
133
134                    @Override
135                    public void execute() {
136
137                        start(0, true);
138                        CmsUUID rootId = CmsSitemapView.getInstance().getController().getData().getRoot().getId();
139                        // We need to send all values to the server, not just the edited ones, because when an inherited
140                        // value from a parent sitemap has changed to match the value explicitly set in a child sitemap, we want
141                        // to clear the value from the child sitemap even if the user hasn't edited it just now.
142                        service.saveSitemapAttributes(rootId, fieldValues, this);
143                    }
144
145                    @SuppressWarnings("synthetic-access")
146                    @Override
147                    protected void onResponse(Void result) {
148
149                        stop(false);
150                        sendUnlockRequest();
151                    }
152                };
153                action.execute();
154            }
155        };
156        CmsDialogFormHandler formHandler = new CmsDialogFormHandler();
157        formHandler.setSubmitHandler(submitHandler);
158        getForm().setWidget(new FieldPanel(data.getInfo()));
159        getForm().setFormHandler(formHandler);
160        formHandler.setDialog(this);
161        for (Map.Entry<String, CmsXmlContentProperty> attrEntry : m_data.getAttributeDefinitions().entrySet()) {
162            String attrName = attrEntry.getKey();
163            CmsXmlContentProperty definition = attrEntry.getValue();
164            CmsBasicFormField field = CmsBasicFormField.createField(
165                definition,
166                definition.getName(),
167                new I_CmsFormWidgetMultiFactory() {
168
169                    public I_CmsFormWidget createFormWidget(
170                        String widgetName,
171                        Map<String, String> widgetParams,
172                        Optional<String> defaultValue) {
173
174                        return CmsWidgetFactoryRegistry.instance().createFormWidget(
175                            widgetName,
176                            widgetParams,
177                            defaultValue);
178                    }
179                },
180                Collections.<String, String> emptyMap(),
181                false);
182            getForm().addField(field, m_data.getAttributeValues().get(attrName));
183        }
184        addAttachHandler(event -> handleAttach(event));
185        getForm().render();
186    }
187
188    /**
189     * Native method - navigator.sendBeacon().
190     *
191     * @param target the target URL
192     * @param data the data to send to the target URL
193     */
194    @JsMethod(namespace = "navigator")
195    private static native void sendBeacon(String target, String data);
196
197    /**
198     * @see com.google.gwt.user.client.ui.PopupPanel#setPopupPosition(int, int)
199     */
200    @Override
201    public void setPopupPosition(int left, int top) {
202
203        // handled by CSS
204    }
205
206    /**
207     * @see org.opencms.gwt.client.ui.input.form.CmsFormDialog#show()
208     */
209    @Override
210    public void show() {
211
212        super.show();
213        // positioning handled by CSS
214        getElement().getStyle().clearPosition();
215        getElement().getStyle().clearLeft();
216        getElement().getStyle().clearTop();
217
218    }
219
220    /**
221     * @see org.opencms.gwt.client.ui.input.form.CmsFormDialog#onClickCancel()
222     */
223    @Override
224    protected void onClickCancel() {
225
226        super.onClickCancel();
227        sendUnlockRequest();
228    }
229
230    /**
231     * Handles attach/detach events for the dialog.
232     *
233     * @param event the attach/detach event
234     */
235    private void handleAttach(AttachEvent event) {
236
237        if (event.isAttached()) {
238            m_windowCloseRegistration = Window.addWindowClosingHandler(closingEvent -> sendUnlockRequest());
239        } else {
240            m_windowCloseRegistration.removeHandler();
241        }
242    }
243
244    /**
245     * Tells the server to unlock the sitemap configuration.
246     */
247    private void sendUnlockRequest() {
248
249        sendBeacon(m_data.getUnlockUrl(), "");
250
251    }
252}