/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.wicket.extensions.ajax.markup.html.modal; import com.github.openjson.JSONObject; import org.apache.wicket.Component; import org.apache.wicket.Page; import org.apache.wicket.WicketRuntimeException; import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.json.JSONFunction; import org.apache.wicket.core.request.handler.IPartialPageRequestHandler; import org.apache.wicket.core.request.handler.PageProvider; import org.apache.wicket.core.request.handler.RenderPageRequestHandler; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.head.CssHeaderItem; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.JavaScriptHeaderItem; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.markup.repeater.AbstractRepeater; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.request.IRequestHandler; import org.apache.wicket.request.cycle.RequestCycle; import org.apache.wicket.request.resource.CssResourceReference; import org.apache.wicket.request.resource.JavaScriptResourceReference; import org.apache.wicket.request.resource.ResourceReference; import org.apache.wicket.resource.CoreLibrariesContributor; import org.apache.wicket.util.io.IClusterable; import org.apache.wicket.util.lang.EnumeratedType; import org.apache.wicket.util.string.AppendingStringBuffer; /** * Modal window component. * <p> * Modal window is a draggable window (with either div or iframe content) that prevent user from * interacting the rest of page (using a mask) until the window is closed. * <p> * If you want this to work under IE, don't attach this component to a <span> tag, make sure * you use a <div>. * <p> * The window is draggable and optionally resizable. The content can be either * <ul> * <li><b>a component</b> - you need to add the component to modal window (with id obtained using * <code>{@link #getContentId()}</code>, or * <li><b>a page</b> - you need to pass a <code>{@link PageCreator}</code> instance to a * <code>{@link #setPageCreator(ModalWindow.PageCreator)}</code> method. * </ul> * In case the content is a component, it is not rendered until the window is shown (method * <code>{@link #show(IPartialPageRequestHandler)})</code>. The window can be made * visible from an ajax handler using * <code>{@link #show(IPartialPageRequestHandler)}</code>. * <p> * To close the window there are multiple options. Static method * <code>{@link #close(IPartialPageRequestHandler)}</code> can be used to close the * window from a handler of ajax link inside the window. By default the close button in the upper * right corner of the window closes it. This behavior can be altered using * <code>{@link #setCloseButtonCallback(ModalWindow.CloseButtonCallback)}</code>. If you want to be * notified when the window is closed (either using the close button or calling * <code>{@link #close(IPartialPageRequestHandler)})</code>, you can use * <code>{@link #setWindowClosedCallback(ModalWindow.WindowClosedCallback)}</code>. * <p> * Title is specified using {@link #setTitle(String)}. Pass <code>true</code> to * <code>{@link #setEscapeModelStrings(boolean)}</code> to use unencoded markup in the title. * <br> * If the content is a page (iframe), the title can remain unset, in that case title from the page * inside window will be shown. * <p> * There are several options to specify the visual properties of the window. In all methods where * size is expected, width refers to width of entire window (including frame), height refers to the * height of window content (without frame). * <p> * <ul> * <li><code>{@link #setResizable(boolean)}</code> specifies, whether the window can be resized. * <li><code>{@link #setInitialWidth(int)}</code> and <code>{@link #setInitialHeight(int)}</code> * specify the initial width and height of window. If the window is resizable, the unit of these * dimensions is always "px". If the window is not resizable, the unit can be specified using * <code>{@link #setWidthUnit(String)}</code> and <code>{@link #setHeightUnit(String)}</code>. If * the window is not resizable and the content is a component (not a page), the initial height value * can be ignored and the actual height can be determined from the height of the content. To enable * this behavior use <code>{@link #setUseInitialHeight(boolean)}</code>. * <li>The window position (and size if the window is resizable) can be stored in a cookie, so that * it is preserved when window is close. The name of the cookie is specified via * <code>{@link #setCookieName(String)}</code>. If the name is <code>null</code>, position is not * stored (initial width and height are always used). Default cookie name is null (position is not * stored). * <li><code>{@link #setMinimalWidth(int)}</code> and <code>{@link #setMinimalHeight(int)}</code> * set the minimal dimensions of resizable window. * <li><code>{@link #setAutoSize(boolean)}</code> sets whether window size will be automatically * adjusted on opening to fit content's width and height. Default is false.<span * style="text-decoration: underline"> Doesn't work on IE 6.</span></li> * <li>Modal window can chose between two colors of frame. * <code>{@link #setCssClassName(String)}</code> sets the dialog css class, possible values are * <code>{@link #CSS_CLASS_BLUE}</code> for blue frame and <code>{@link #CSS_CLASS_GRAY}</code> for * gray frame. * <li>Mask (element that prevents user from interacting the rest of the page) can be either * transparent or semitransparent. <code>{@link #setMaskType(ModalWindow.MaskType)}</code> alters * this. * </ul> * Also it is recommended to put the modal window component in markup before any component (i.e. * AjaxLink or AjaxButton) that shows it. * <p> * If you want to use form in modal window component make sure that you put the modal window itself * in another form (nesting forms is legal in Wicket) and that the form on modal window is submitted * before the window get closed. * * @author Matej Knopp */ public class ModalWindow extends Panel { private static final long serialVersionUID = 1L; /** CSS class for window with blue border. */ public final static String CSS_CLASS_BLUE = "w_blue"; /** CSS class for window with gray border. */ public final static String CSS_CLASS_GRAY = "w_silver"; private static final ResourceReference JAVASCRIPT = new JavaScriptResourceReference( ModalWindow.class, "res/modal.js"); private static final ResourceReference CSS = new CssResourceReference(ModalWindow.class, "res/modal.css"); /** the default id of the content component */ public static final String CONTENT_ID = "content"; /** True while the ModalWindows is showing */ private boolean shown = false; /** empty container - used when no component is added */ private WebMarkupContainer empty; private int minimalWidth = 200; private int minimalHeight = 200; private String cssClassName = CSS_CLASS_BLUE; private int initialWidth = 600; private int initialHeight = 400; private boolean useInitialHeight = true; private boolean resizable = true; private String widthUnit = "px"; private String heightUnit = "px"; private String cookieName; private IModel<String> title = null; private MaskType maskType = MaskType.SEMI_TRANSPARENT; private boolean autoSize = false; private boolean unloadConfirmation = true; private PageCreator pageCreator = null; private CloseButtonCallback closeButtonCallback = null; private WindowClosedCallback windowClosedCallback = null; /** * Interface for lazy page creation. The advantage of creating page using this interface over * just passing a page instance is that page created in <code>{@link #createPage()}</code> will * have the pagemap automatically set to the pagemap specified for * <code>{@link ModalWindow}</code>. * * @author Matej Knopp */ public interface PageCreator extends IClusterable { /** * Creates a new instance of content page. * * @return new page instance */ Page createPage(); } /** * Callback for close button that contains a method that is invoked after the button has been * clicked. If no callback instance is specified using * <code>{@link ModalWindow#setCloseButtonCallback(ModalWindow.CloseButtonCallback)}</code>, no * ajax request will be fired. Clicking the button will just close the window. * * @author Matej Knopp */ public interface CloseButtonCallback extends IClusterable { /** * Methods invoked after the button has been clicked. The invocation is done using an ajax * call, so <code>{@link org.apache.wicket.ajax.AjaxRequestTarget}</code> instance is * available. * * @param target * <code>{@link org.apache.wicket.ajax.AjaxRequestTarget}</code> instance bound * with the ajax request. * * @return True if the window can be closed (will close the window), false otherwise */ boolean onCloseButtonClicked(AjaxRequestTarget target); } /** * Callback called after the window has been closed. If no callback instance is specified using * {@link ModalWindow#setWindowClosedCallback(ModalWindow.WindowClosedCallback)}, no ajax * request will be fired. * * @author Matej Knopp */ public interface WindowClosedCallback extends IClusterable { /** * Called after the window has been closed. * * @param target * <code>{@link org.apache.wicket.ajax.AjaxRequestTarget}</code> instance bound * with the ajax request. */ void onClose(AjaxRequestTarget target); } /** * Creates a new modal window component. * * @param id * Id of component */ public ModalWindow(final String id) { super(id); init(); } /** * Creates a new modal window component. * * @param id * Id of component * @param model * Model */ public ModalWindow(final String id, final IModel<?> model) { super(id, model); init(); } /** * Initialize */ private void init() { setVersioned(false); cookieName = null; add(empty = new WebMarkupContainer(getContentId())); add(newCloseButtonBehavior()); add(new WindowClosedBehavior()); // install a default callback that will force // WindowClosedBehavior to be executed setWindowClosedCallback((WindowClosedCallback) target -> { // noop }); } @Override public void renderHead(final IHeaderResponse response) { super.renderHead(response); CoreLibrariesContributor.contributeAjax(getApplication(), response); response.render(JavaScriptHeaderItem.forReference(JAVASCRIPT)); ResourceReference cssResource = newCssResource(); if (cssResource != null) { response.render(CssHeaderItem.forReference(cssResource)); } } /** * Allows to override CSS contribution. Returning null means the CSS will be contributed via * other sources, e.g. a global CSS resource. * * @return The CSS resource reference or null if CSS is contributed via other means. * @see #setCssClassName(String) */ protected ResourceReference newCssResource() { return CSS; } /** * Is this window currently showing. * * @return the shown */ public boolean isShown() { return shown; } /** * Sets the <code>{@link PageCreator}</code> instance. The instance is only used when no custom * component has been added to the dialog. * * @param creator * <code>{@link PageCreator}</code> instance * @return this */ public ModalWindow setPageCreator(final PageCreator creator) { setContent(empty); pageCreator = creator; return this; } /** * Sets the <code>{@link CloseButtonCallback}</code> instance. * * @param callback * Callback instance * @return this */ public ModalWindow setCloseButtonCallback(final CloseButtonCallback callback) { closeButtonCallback = callback; return this; } /** * Sets the <code>@{link {@link WindowClosedCallback}</code> instance. * * @param callback * Callback instance * @return this */ public ModalWindow setWindowClosedCallback(final WindowClosedCallback callback) { windowClosedCallback = callback; return this; } /** * Shows the modal window. * * @param target * Request target associated with current ajax request. */ public void show(final IPartialPageRequestHandler target) { if (shown == false) { getContent().setVisible(true); target.add(this); target.appendJavaScript(getWindowOpenJavaScript()); shown = true; } } /** * Hides the modal window. This can be called from within the modal window, however, the modal * window must have configured WindowClosedCallback. Otherwise use the * {@link #close(IPartialPageRequestHandler)} method. * * @param target * Request target associated with current ajax request. */ public static void closeCurrent(final IPartialPageRequestHandler target) { target.appendJavaScript(getCloseJavacriptInternal()); } /** * Closes the modal window. * * @param target * Request target associated with current ajax request. */ public void close(final IPartialPageRequestHandler target) { getContent().setVisible(false); if (isCustomComponent()) { target.add(getContent()); } target.appendJavaScript(getCloseJavacript()); shown = false; } /** * Method that allows alternate script for showing the window. * * @return the script that actually shows the window. */ protected CharSequence getShowJavaScript() { return "window.setTimeout(function(){\n" + " Wicket.Window.create(settings).show();\n" + "}, 0);\n"; } private static String getCloseJavacriptInternal() { return "var win;\n" // + "try {\n" + " win = window.parent.Wicket.Window;\n" + "} catch (ignore) {\n" + "}\n" + "if (typeof(win) == \"undefined\" || typeof(win.current) == \"undefined\") {\n" + " try {\n" + " win = window.Wicket.Window;\n" + " } catch (ignore) {\n" + " }\n" + "}\n" + "if (win && win.current) {\n" + " var close = function(w) { w.setTimeout(function() {\n" + " win.current.close();\n" + " }, 0); };\n" + " try { close(window.parent); } catch (ignore) { close(window); }\n" + "}"; } /** * Method that allows alternate script for closing the window. * * @return the script that actually closes the window. */ protected String getCloseJavacript() { return getCloseJavacriptInternal(); } /** * Returns the id of content component. * * <pre> * ModalWindow window = new ModalWindow(parent, "window"); * new MyPanel(window, window.getContentId()); * </pre> * * @return Id of content component. */ public String getContentId() { return CONTENT_ID; } /** * Sets the minimal width of window. This value is only used if the window is resizable. The * width is specified in pixels and it is the width of entire window (including frame). * * @param minimalWidth * Minimal window width. * @return this */ public ModalWindow setMinimalWidth(final int minimalWidth) { this.minimalWidth = minimalWidth; return this; } /** * Returns the minimal width of window (in pixels). * * @return Minimal width of window */ public int getMinimalWidth() { return minimalWidth; } /** * Sets the minimal height of window. This value is only used if window is resizable. The height * is specified in pixels and it is the height of window content (without frame). * * @param minimalHeight * Minimal height * @return this */ public ModalWindow setMinimalHeight(final int minimalHeight) { this.minimalHeight = minimalHeight; return this; } /** * Returns the minimal height of window (in pixels). * * @return Minimal height of window */ public int getMinimalHeight() { return minimalHeight; } /** * Sets the CSS class name for this window. This class affects the look of window frame. * Possible values (if you don't make your style sheet) are <code>{@link #CSS_CLASS_BLUE}</code> * and <code>{@link #CSS_CLASS_GRAY}</code>. * * @param cssClassName * @return this * @see #newCssResource() */ public ModalWindow setCssClassName(final String cssClassName) { this.cssClassName = cssClassName; return this; } /** * Returns the CSS class name for this window. * * @return CSS class name */ public String getCssClassName() { return cssClassName; } /** * Sets the initial width of the window. The width refers to the width of entire window * (including frame). If the window is resizable, the width unit is always "px". If the window * is not resizable, the unit can be specified using {@link #setWidthUnit(String)}. If cookie * name is set and window is resizable, the initial width may be ignored in favor of width * stored in cookie. * * @param initialWidth * Initial width of the window * @return this */ public ModalWindow setInitialWidth(final int initialWidth) { this.initialWidth = initialWidth; return this; } /** * Returns the initial width of the window. * * @return Initial height of the window */ public int getInitialWidth() { return initialWidth; } /** * Sets the initial height of the window. The height refers to the height of window content * (without frame). If the window is resizable, the height unit is always "px". If the window is * not resizable, the unit can be specified using {@link #setHeightUnit(String)}. If cookie name * is set and window is resizable, the initial height may be ignored in favor of height stored * in cookie. * * @param initialHeight * Initial height of the window * @return this */ public ModalWindow setInitialHeight(final int initialHeight) { this.initialHeight = initialHeight; return this; } /** * Returns the initial height of the window. * * @return Initial height of the window */ public int getInitialHeight() { return initialHeight; } /** * Sets whether to use initial height or preserve the real content height. This can only be used * if the content is a component (not a page) and the window is not resizable. * * @param useInitialHeight * Whether to use initial height instead of preserving content height instead of * using initial height * @return this */ public ModalWindow setUseInitialHeight(final boolean useInitialHeight) { this.useInitialHeight = useInitialHeight; return this; } /** * Returns true if the initial height should be used (in favor of preserving real content * height). * * @return True if initial height should be used, false is real content height should be * preserved (valid only if the window is not resizable and the content is a component * (not a page) */ public boolean isUseInitialHeight() { return useInitialHeight; } /** * Sets whether the user will be able to resize the window. * * @param resizable * Whether the window is resizable * @return this */ public ModalWindow setResizable(final boolean resizable) { this.resizable = resizable; return this; } /** * Returns whether the window is resizable. * * @return True if the window is resizable, false otherwise */ public boolean isResizable() { return resizable; } /** * Sets a flag whether to ask the user before leaving the page. * * @param unloadConfirmation * a flag whether to ask the user before leaving the page * @return {@code this} instance, for chaining */ public ModalWindow showUnloadConfirmation(final boolean unloadConfirmation) { this.unloadConfirmation = unloadConfirmation; return this; } /** * Returns whether the user should be asked before leaving the page. * * @return {@code true} if the user should be asked if the last action causes leaving the page, * {@code false} otherwise */ public boolean showUnloadConfirmation() { return unloadConfirmation; } /** * Sets the CSS unit used for initial window width. This is only applicable when the window is * not resizable. * * @param widthUnit * CSS unit for initial window width. * @return this */ public ModalWindow setWidthUnit(final String widthUnit) { this.widthUnit = widthUnit; return this; } /** * Returns the CSS unit for initial window width. * * @return CSS unit for initial window width. */ public String getWidthUnit() { return widthUnit; } /** * Sets the CSS unit used for initial window height. This is only applicable when the window is * not resizable. * * @param heightUnit * CSS unit for initial window height. * @return this */ public ModalWindow setHeightUnit(final String heightUnit) { this.heightUnit = heightUnit; return this; } /** * Retrns the CSS unit for initial window height. * * @return CSS unit for initial window height. */ public String getHeightUnit() { return heightUnit; } /** * Sets the name of the cookie that is used to remember window position (and size if the window * is resizable). * * @param cookieName * Name of the cookie * @return this */ public ModalWindow setCookieName(final String cookieName) { if ((cookieName != null) && (cookieName.contains(",") || cookieName.contains("|"))) { throw new IllegalArgumentException("Cookie name may not contain ',' or '|' characters."); } this.cookieName = cookieName; return this; } /** * Returns the name of cookie that is used to remember window position (and size if the window * is resizable). * * @return Name of the cookie */ public String getCookieName() { return cookieName; } /** * Sets the title of window. If the window is a page, title can be <code>null</code>. In that * case it will display the title document inside the window. * * @param title * Title of the window * @return this */ public ModalWindow setTitle(final String title) { this.title = new Model<>(title); return this; } /** * Sets the title of window. If the window is a page, title can be <code>null</code>. In that * case it will display the title document inside the window. * * @param title * Title of the window * @return this */ public ModalWindow setTitle(IModel<String> title) { title = wrap(title); this.title = title; return this; } /** * Returns the title of the window. * * @return Title of the window */ public IModel<String> getTitle() { return title; } /** * Mask is the element behind the window, that prevents user from interacting the rest of page. * Mask can be either * <ul> * <li><code>{@link #TRANSPARENT}</code> - the mask is invisible * <li><code>{@link #SEMI_TRANSPARENT}</code> - the mask is black with small opacity (10%) * </ul> * * @author Matej Knopp */ public static final class MaskType extends EnumeratedType { private static final long serialVersionUID = 1L; /** Transparent mask (not visible). */ public static final MaskType TRANSPARENT = new MaskType("TRANSPARENT"); /** Visible mask (black with low opacity). */ public static final MaskType SEMI_TRANSPARENT = new MaskType("SEMI_TRANSPARENT"); /** * Constructor. * * @param name */ public MaskType(final String name) { super(name); } } /** * Sets the mask type of the window. * * @param mask * The mask type * @return this */ public ModalWindow setMaskType(final MaskType mask) { maskType = mask; return this; } /** * Returns the mask type of the window * * @return The mask type */ public MaskType getMaskType() { return maskType; } /** * Creates the page. * * @return Page instance or null if page couldn't be created. */ private Page createPage() { if (pageCreator == null) { return null; } else { return pageCreator.createPage(); } } /** * @see org.apache.wicket.Component#onBeforeRender() */ @Override protected void onBeforeRender() { shown = makeContentVisible(); getContent().setOutputMarkupId(true); getContent().setVisible(shown); super.onBeforeRender(); } /** * You may subclass this method in case you don't want to show up the window on normal page * refresh. * * @return true, if the window shall be shown */ protected boolean makeContentVisible() { // if user is refreshing whole page, the window will not be shown if (getWebRequest().isAjax() == false) { return false; } else { return shown; } } /** * @see org.apache.wicket.markup.html.panel.Panel#onComponentTag(org.apache.wicket.markup.ComponentTag) */ @Override protected void onComponentTag(final ComponentTag tag) { super.onComponentTag(tag); tag.put("style", "display:none"); } /** * Returns a content component. In case user haven't specified any content component, it returns * an empty WebMarkupContainer. * * @return Content component */ protected final Component getContent() { return get(getContentId()); } /** * Returns true if user has added own component to the window. * * @return True if user has added own component to the window, false otherwise. */ protected boolean isCustomComponent() { return getContent() != empty; } /** * @see org.apache.wicket.MarkupContainer#remove(org.apache.wicket.Component) */ @Override public ModalWindow remove(final Component component) { super.remove(component); if (component.getId().equals(getContentId())) { add(empty = new WebMarkupContainer(getContentId())); } return this; } /** * Sets the content of the modal window. * * @param component * @return this; */ public ModalWindow setContent(final Component component) { if (component.getId().equals(getContentId()) == false) { throw new WicketRuntimeException("Modal window content id is wrong. Component ID:" + component.getId() + "; content ID: " + getContentId()); } else if (component instanceof AbstractRepeater) { throw new WicketRuntimeException( "A repeater component cannot be used as the content of a modal window, please use repeater's parent"); } component.setOutputMarkupPlaceholderTag(true); component.setVisible(false); replace(component); shown = false; pageCreator = null; return this; } /** * @author Matej Knopp */ private class WindowClosedBehavior extends AbstractDefaultAjaxBehavior { private static final long serialVersionUID = 1L; @Override protected void respond(final AjaxRequestTarget target) { shown = false; if (windowClosedCallback != null) { windowClosedCallback.onClose(target); } } } /** * @author Matej Knopp */ protected class CloseButtonBehavior extends AbstractDefaultAjaxBehavior { private static final long serialVersionUID = 1L; public CloseButtonBehavior() { } @Override protected final void respond(final AjaxRequestTarget target) { if ((closeButtonCallback == null) || (closeButtonCallback.onCloseButtonClicked(target))) { close(target); } } } /** * Returns the markup id of the component. * * @return component id */ private String getContentMarkupId() { return getContent().getMarkupId(); } /** * Returns the javascript used to open the window. Subclass * {@link #postProcessSettings(AppendingStringBuffer)} to modify the JavaScript if needed. * * See WICKET-12 * * @return javascript that opens the window */ protected final String getWindowOpenJavaScript() { JSONObject settings = new JSONObject(); settings.put("minWidth", getMinimalWidth()); settings.put("minHeight", getMinimalHeight()); settings.put("className", getCssClassName()); settings.put("width", getInitialWidth()); if ((isUseInitialHeight() == true) || (isCustomComponent() == false)) { settings.put("height", getInitialHeight()); } else { settings.put("height", (Object)null); } settings.put("resizable", isResizable()); if (isResizable() == false) { settings.put("widthUnit", getWidthUnit()); settings.put("heightUnit", getHeightUnit()); } if (isCustomComponent() == false) { Page page = createPage(); if (page == null) { throw new WicketRuntimeException("Error creating page for modal dialog."); } CharSequence pageUrl; RequestCycle requestCycle = RequestCycle.get(); page.getSession().getPageManager().touchPage(page); if (page.isPageStateless()) { pageUrl = requestCycle.urlFor(page.getClass(), page.getPageParameters()); } else { IRequestHandler handler = new RenderPageRequestHandler(new PageProvider(page)); pageUrl = requestCycle.urlFor(handler); } settings.put("src", pageUrl); } else { settings.put("element", new JSONFunction("document.getElementById(\"" + getContentMarkupId() + "\")")); } if (getCookieName() != null) { settings.put("cookieId", getCookieName()); } String title = getTitle() != null ? getTitle().getObject() : null; if (title != null) { settings.put("title", getDefaultModelObjectAsString(title)); } if (getMaskType() == MaskType.TRANSPARENT) { settings.put("mask", "transparent"); } else if (getMaskType() == MaskType.SEMI_TRANSPARENT) { settings.put("mask", "semi-transparent"); } settings.put("autoSize", autoSize); settings.put("unloadConfirmation", showUnloadConfirmation()); // set true if we set a windowclosedcallback boolean haveCloseCallback = false; // in case user is interested in window close callback or we have a pagemap to clean attach // notification request if (windowClosedCallback != null) { WindowClosedBehavior behavior = getBehaviors(WindowClosedBehavior.class).get(0); settings.put("onClose", new JSONFunction("function() { " + behavior.getCallbackScript() + " }")); haveCloseCallback = true; } // in case we didn't set windowclosecallback, we need at least callback on close button, to // close window property (thus cleaning the shown flag) if ((closeButtonCallback != null) || (haveCloseCallback == false)) { CloseButtonBehavior behavior = getBehaviors(CloseButtonBehavior.class).get(0); settings.put("onCloseButton", new JSONFunction("function() { " + behavior.getCallbackScript() + "; return false; }")); } postProcessSettings(settings); AppendingStringBuffer buffer = new AppendingStringBuffer(500); buffer.append("var settings = "); buffer.append(settings.toString()); buffer.append(";"); buffer.append(getShowJavaScript()); return buffer.toString(); } /** * Method that allows tweaking the settings * * @param settings * @return settings json */ protected void postProcessSettings(JSONObject settings) { } /** * Detach the 'title' model * * @see org.apache.wicket.Component#onDetach() */ @Override protected void onDetach() { super.onDetach(); if (title != null) { title.detach(); } } /** * Sets whether window size will be automatically adjusted on opening to fit content's width and * height. <span style="text-decoration: underline">Doesn't work on IE 6.</span> * * @param autoSize * Whether window size will be automatically adjusted * @return this */ public ModalWindow setAutoSize(final boolean autoSize) { this.autoSize = autoSize; return this; } /** * Returns whether window will be opened in autosize mode. * * @return True if the window will be opened open in autosize mode, false otherwise */ public boolean isAutoSize() { return autoSize; } /** * Gives the possibility to provide custom * {@link org.apache.wicket.ajax.attributes.IAjaxCallListener} * * @return the behavior that should be used for the window close button */ protected CloseButtonBehavior newCloseButtonBehavior() { return new CloseButtonBehavior(); } }