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.gwt.client.util;
029
030import org.opencms.gwt.client.CmsCoreProvider;
031import org.opencms.gwt.client.I_CmsHasInit;
032import org.opencms.gwt.client.ui.CmsIFrame;
033import org.opencms.gwt.client.ui.contextmenu.I_CmsActionHandler;
034import org.opencms.gwt.client.ui.contextmenu.I_CmsStringSelectHandler;
035import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
036import org.opencms.gwt.shared.CmsGwtConstants;
037import org.opencms.util.CmsStringUtil;
038import org.opencms.util.CmsUUID;
039
040import java.util.ArrayList;
041import java.util.Collections;
042import java.util.HashMap;
043import java.util.List;
044import java.util.Map;
045import java.util.function.Consumer;
046
047import com.google.gwt.core.client.JavaScriptObject;
048import com.google.gwt.core.client.JsArrayString;
049import com.google.gwt.user.client.Command;
050import com.google.gwt.user.client.Timer;
051import com.google.gwt.user.client.Window;
052import com.google.gwt.user.client.ui.RootPanel;
053
054/**
055 * Handler for embedded VAADIN dialogs.<p>
056 */
057public class CmsEmbeddedDialogHandler implements I_CmsHasInit {
058
059    /** The iframe element. */
060    private CmsIFrame m_frame;
061
062    /** The context menu handler. */
063    private I_CmsActionHandler m_handler;
064
065    /** The on close command. */
066    private Command m_onCloseCommand;
067
068    /** The principle select handler. */
069    private I_CmsStringSelectHandler m_stringSelectHandler;
070
071    /**
072     * Constructor.<p>
073     */
074    public CmsEmbeddedDialogHandler() {
075
076        // nothing to do
077    }
078
079    /**
080     * Constructor.<p>
081     *
082     * @param handler the context handler
083     */
084    public CmsEmbeddedDialogHandler(I_CmsActionHandler handler) {
085
086        this();
087        m_handler = handler;
088    }
089
090    /**
091     * Encodes a parameter value for use in a query string.
092     *
093     * @param str the string to encode
094     * @return the encoded string
095     */
096    public static String encodeParam(String str) {
097
098        return com.google.gwt.http.client.URL.encodeQueryString(str);
099
100    }
101
102    /**
103     * Exports native JS function cmsOpenEmbeddedDialog.
104     */
105    public static native void exportNativeFunctions() /*-{
106        $wnd.cmsOpenEmbeddedDialog = function(dialogId, callback, structureIds,
107                params) {
108            @org.opencms.gwt.client.util.CmsEmbeddedDialogHandler::openEmbeddedDialog(Ljava/lang/String;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JsArrayString;Lcom/google/gwt/core/client/JavaScriptObject;)(dialogId, callback, structureIds, params);
109        };
110    }-*/;
111
112    /**
113     * Called on load, exports native functions.
114     */
115    public static void initClass() {
116
117        exportNativeFunctions();
118    }
119
120    /**
121     * Opens the given dialog in an iframe.
122     *
123     * @param dialogId the action class
124     * @param structureIds the structure ids for the action
125     * @param finishCallback the callback to call after the dialog closes
126     */
127    public static void openDialog(String dialogId, List<CmsUUID> structureIds, Consumer<CmsUUID> finishCallback) {
128
129        CmsEmbeddedDialogHandler handler = new CmsEmbeddedDialogHandler(new I_CmsActionHandler() {
130
131            public void leavePage(String targetUri) {
132
133                // TODO Auto-generated method stub
134
135            }
136
137            public void onSiteOrProjectChange(String sitePath, String serverLink) {
138
139                // TODO Auto-generated method stub
140
141            }
142
143            public void refreshResource(CmsUUID structureId) {
144
145                finishCallback.accept(structureId);
146            }
147        });
148        handler.openDialog(dialogId, CmsGwtConstants.CONTEXT_TYPE_FILE_TABLE, structureIds, new HashMap<>());
149    }
150
151    /**
152     * Opens the given dialog in an iframe.
153     *
154     * @param dialogId the action class
155     * @param structureIds the structure ids for the action
156     * @param params additional parameters to pass
157     * @param finishCallback the callback to call after the dialog closes
158     */
159    public static void openDialog(
160        String dialogId,
161        List<CmsUUID> structureIds,
162        Map<String, String> params,
163        Consumer<CmsUUID> finishCallback) {
164
165        CmsEmbeddedDialogHandler handler = new CmsEmbeddedDialogHandler(new I_CmsActionHandler() {
166
167            public void leavePage(String targetUri) {
168
169                // TODO Auto-generated method stub
170
171            }
172
173            public void onSiteOrProjectChange(String sitePath, String serverLink) {
174
175                // TODO Auto-generated method stub
176
177            }
178
179            public void refreshResource(CmsUUID structureId) {
180
181                finishCallback.accept(structureId);
182            }
183        });
184        handler.openDialog(dialogId, CmsGwtConstants.CONTEXT_TYPE_FILE_TABLE, structureIds, params);
185    }
186
187    /**
188     * Opens an embedded dialog.
189     *
190     * @param dialogId the dialog
191     * @param callback the onClose callback
192     * @param structureIds the structure ids
193     * @param params the parameters
194     */
195    public static void openEmbeddedDialog(
196        String dialogId,
197        JavaScriptObject callback,
198        JsArrayString structureIds,
199        JavaScriptObject params) {
200
201        CmsEmbeddedDialogHandler handler = new CmsEmbeddedDialogHandler();
202        if (callback != null) {
203            Command command = CmsJsUtil.convertCallbackToCommand(callback);
204            handler.setOnCloseCommand(command);
205        }
206        Map<String, String> paramsMap = new HashMap<>();
207        if (params != null) {
208            CmsJsUtil.fillStringMapFromJsObject(params, paramsMap);
209        }
210        List<CmsUUID> uuids = new ArrayList<>();
211        if (structureIds != null) {
212            for (int i = 0; i < structureIds.length(); i++) {
213                String uuidStr = structureIds.get(i);
214                try {
215                    uuids.add(new CmsUUID(uuidStr));
216                } catch (Exception e) {
217                    CmsDebugLog.consoleLog(e.getClass() + ":" + e.getLocalizedMessage());
218                }
219            }
220        }
221        handler.openDialog(dialogId, null, uuids, paramsMap);
222    }
223
224    /**
225     * Called on dialog close.<p>
226     *
227     * @param resources the resource ids to update as a ';' separated string.<p>
228     */
229    public void finish(String resources) {
230
231        if (m_frame != null) {
232            m_frame.removeFromParent();
233            m_frame = null;
234        }
235        if (m_handler != null) {
236            List<CmsUUID> resourceIds = parseResources(resources);
237            if (!resourceIds.isEmpty()) {
238                m_handler.refreshResource(resourceIds.get(0));
239            }
240        }
241        if (m_onCloseCommand != null) {
242            m_onCloseCommand.execute();
243        }
244    }
245
246    /**
247     * Returns if the dialog iframe is attached.<p>
248     *
249     * @return <code>true</code> if the dialog iframe is attached
250     */
251    public boolean hasDialogFrame() {
252
253        return m_frame != null;
254    }
255
256    /**
257     * Navigates to the given URI.<p>
258     *
259     * @param targetUri the target URI
260     */
261    public void leavePage(String targetUri) {
262
263        if (m_frame != null) {
264            m_frame.removeFromParent();
265            m_frame = null;
266        }
267        if (m_handler != null) {
268            m_handler.leavePage(targetUri);
269        } else {
270            // the timer is a workaround for weird Safari behavior, just calling Location.assign doesn't work there
271            Timer timer = new Timer() {
272
273                @Override
274                public void run() {
275
276                    Window.Location.assign(targetUri);
277                }
278            };
279            timer.schedule(10);
280        }
281    }
282
283    /**
284     * Called when site and or project have been changed.<p>
285     *
286     * @param sitePath the site path to the resource to display
287     * @param serverLink the server link to the resource to display
288     */
289    public void onSiteOrProjectChange(String sitePath, String serverLink) {
290
291        if (m_frame != null) {
292            m_frame.removeFromParent();
293            m_frame = null;
294        }
295        if (m_handler != null) {
296            m_handler.onSiteOrProjectChange(sitePath, serverLink);
297        } else {
298            Window.Location.assign(serverLink);
299        }
300    }
301
302    /**
303     * Opens the dialog with the given id.<p>
304     *
305     * @param dialogId the dialog id
306     * @param contextType the context type, used to check the action visibility
307     * @param resources the resource to handle
308     */
309    public void openDialog(String dialogId, String contextType, List<CmsUUID> resources) {
310
311        openDialog(dialogId, contextType, resources, null);
312    }
313
314    /**
315     * Opens the dialog with the given id.<p>
316     *
317     * @param dialogId the dialog id
318     * @param contextType the context type, used to check the action visibility
319     * @param resources the resource to handle
320     * @param rawParams additional set of parameters to append to the query string (will not be escaped, therefore 'raw')
321     */
322
323    public void openDialog(
324        String dialogId,
325        String contextType,
326        List<CmsUUID> resources,
327        Map<String, String> rawParams) {
328
329        String resourceIds = "";
330        if (resources != null) {
331            for (CmsUUID id : resources) {
332                resourceIds += id.toString() + ";";
333            }
334        }
335        String url = CmsCoreProvider.get().getEmbeddedDialogsUrl()
336            + dialogId
337            + "?resources="
338            + resourceIds
339            + "&contextType="
340            + contextType;
341
342        if ((rawParams != null) && !rawParams.isEmpty()) {
343            List<String> params = new ArrayList<String>();
344            for (Map.Entry<String, String> entry : rawParams.entrySet()) {
345                params.add(encodeParam(entry.getKey()) + "=" + encodeParam(entry.getValue()));
346            }
347            url = url + "&" + CmsStringUtil.listAsString(params, "&");
348        }
349        m_frame = new CmsIFrame("embeddedDialogFrame", url);
350        m_frame.setStyleName(I_CmsLayoutBundle.INSTANCE.dialogCss().embeddedDialogFrame());
351        RootPanel.get().add(m_frame);
352        initIFrame();
353    }
354
355    /**
356     * Reloads the current page.<p>
357     */
358    public void reload() {
359
360        if (m_handler != null) {
361            String uri = Window.Location.getHref();
362            m_handler.leavePage(uri);
363        } else {
364            Window.Location.reload();
365        }
366    }
367
368    /**
369     * Calls the principle select handler and closes the dialog frame.<p>
370     *
371     * @param principle the principle to select
372     */
373    public void selectString(String principle) {
374
375        if (m_frame != null) {
376            m_frame.removeFromParent();
377            m_frame = null;
378        }
379        if (m_stringSelectHandler != null) {
380            m_stringSelectHandler.selectString(principle);
381        }
382        if (m_onCloseCommand != null) {
383            m_onCloseCommand.execute();
384        }
385    }
386
387    /**
388     * Sets the on close command.<p>
389     *
390     * @param onCloseCommand the on close command
391     */
392    public void setOnCloseCommand(Command onCloseCommand) {
393
394        m_onCloseCommand = onCloseCommand;
395    }
396
397    /**
398     * Sets the principle select handler.<p>
399     *
400     * @param selectHandler the principle select handler
401     */
402    public void setStringSelectHandler(I_CmsStringSelectHandler selectHandler) {
403
404        m_stringSelectHandler = selectHandler;
405    }
406
407    /**
408     * Parses the resources string.<p>
409     *
410     * @param resources the resources
411     *
412     * @return the list of resource ids
413     */
414    protected List<CmsUUID> parseResources(String resources) {
415
416        if (CmsStringUtil.isEmptyOrWhitespaceOnly(resources)) {
417            return Collections.emptyList();
418        } else {
419            List<CmsUUID> result = new ArrayList<CmsUUID>();
420            String[] resArray = resources.trim().split(";");
421            for (int i = 0; i < resArray.length; i++) {
422                result.add(new CmsUUID(resArray[i]));
423            }
424            return result;
425        }
426    }
427
428    /**
429     * Initializes the iFrame element.<p>
430     */
431    private native void initIFrame()/*-{
432        var self = this;
433        $wnd.frames.embeddedDialogFrame.connector = {
434            reload : function() {
435                [email protected]::reload()();
436            },
437            finish : function(resources) {
438                [email protected]::finish(Ljava/lang/String;)(resources);
439            },
440            finishForProjectOrSiteChange : function(sitePath, serverLink) {
441                [email protected]::onSiteOrProjectChange(Ljava/lang/String;Ljava/lang/String;)(sitePath,serverLink)
442            },
443            leavePage : function(targetUri) {
444                [email protected]::leavePage(Ljava/lang/String;)(targetUri);
445            },
446            selectString : function(value) {
447                [email protected]::selectString(Ljava/lang/String;)(value);
448            }
449        };
450    }-*/;
451}