001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.markup.html.link;
018
019import org.apache.wicket.util.io.IClusterable;
020import org.slf4j.Logger;
021import org.slf4j.LoggerFactory;
022
023
024/**
025 * A popup specification can be used as a property of the {@link Link}classes to specify that the
026 * link should be rendered with an onClick javascript event handler that opens a new window with the
027 * links' URL.
028 * <p>
029 * You can 'or' display flags together like this:
030 * 
031 * <pre>
032 * new PopupSettings(PopupSettings.RESIZABLE | PopupSettings.SCROLLBARS);
033 * </pre>
034 * 
035 * </p>
036 * 
037 * @author Jonathan Locke
038 * @author Eelco Hillenius
039 */
040public class PopupSettings implements IClusterable
041{
042        /** The log. */
043        private static final Logger log = LoggerFactory.getLogger(PopupSettings.class);
044
045        private static final long serialVersionUID = 1L;
046
047        /** Flag to include location bar */
048        public static final int LOCATION_BAR = 1;
049
050        /** Flag to include menu bar */
051        public static final int MENU_BAR = 2;
052
053        /** Flag to make popup resizable */
054        public static final int RESIZABLE = 4;
055
056        /** Flag to include scrollbars */
057        public static final int SCROLLBARS = 8;
058
059        /** Flag to include status bar */
060        public static final int STATUS_BAR = 16;
061
062        /** Flag to include location bar */
063        public static final int TOOL_BAR = 32;
064
065        /** Display flags */
066        private int displayFlags;
067
068        /** Height of popup window. */
069        private int height = -1;
070
071        /** Left position of popup window. */
072        private int left = -1;
073
074        /**
075         * The target to put in JavaScript. This implementation simply refers to the href attribute, but
076         * clients may want to override this (e.g. when the HTML element is not an anchor).
077         */
078        private String target = "href";
079
080        /** Top position of popup window. */
081        private int top = -1;
082
083        /** Width of popup window. */
084        private int width = -1;
085
086        /**
087         * The logical name of the window. This can be anything you want, although you should use
088         * alphanumeric characters only (no spaces or punctuation). If you have a window already open
089         * and call window.open a second time using the same windowName, the first window will be reused
090         * rather than opening a second window.
091         */
092        private String windowName = null;
093
094        /**
095         * Constructor.
096         */
097        public PopupSettings()
098        {
099        }
100
101        /**
102         * Construct.
103         * 
104         * @param displayFlags
105         *            Display flags
106         */
107        public PopupSettings(final int displayFlags)
108        {
109                this(null, displayFlags);
110        }
111
112        /**
113         * Construct.
114         * 
115         * @param windowName
116         */
117        public PopupSettings(String windowName)
118        {
119                this(windowName, 0);
120        }
121
122        /**
123         * Construct.
124         * 
125         * @param windowName
126         *            The pagemap where this popup must be in. Typically, you should put any popup in a
127         *            separate page map as Wicket holds references to a limited number of pages/
128         *            versions only. If you don't put your popup in a separate page map, the user might
129         *            get page expired exceptions when getting back to the main window again.
130         * @param displayFlags
131         *            Display flags
132         */
133        public PopupSettings(String windowName, final int displayFlags)
134        {
135                this.displayFlags = displayFlags;
136                this.windowName = windowName;
137        }
138
139        /**
140         * Get the onClick javascript event handler.
141         * 
142         * @return the onClick javascript event handler
143         */
144        public String getPopupJavaScript()
145        {
146                String windowTitle = windowName;
147
148                if (windowTitle == null)
149                {
150                        windowTitle = "";
151                }
152                else
153                {
154                        // Fix for IE bug.
155                        windowTitle = windowTitle.replaceAll("\\W", "_");
156                }
157
158            StringBuilder script = new StringBuilder("var w = window.open(" + target + ", '").append(
159                        windowTitle).append("', '");
160
161                script.append("scrollbars=").append(flagToString(SCROLLBARS));
162                script.append(",location=").append(flagToString(LOCATION_BAR));
163                script.append(",menuBar=").append(flagToString(MENU_BAR));
164                script.append(",resizable=").append(flagToString(RESIZABLE));
165                script.append(",status=").append(flagToString(STATUS_BAR));
166                script.append(",toolbar=").append(flagToString(TOOL_BAR));
167
168                if (width != -1)
169                {
170                        script.append(",width=").append(width);
171                }
172
173                if (height != -1)
174                {
175                        script.append(",height=").append(height);
176                }
177
178                if (left != -1)
179                {
180                        script.append(",left=").append(left);
181                }
182
183                if (top != -1)
184                {
185                        script.append(",top=").append(top);
186                }
187
188                script.append("'); try {if (w.blur) w.focus();}catch(ignore){}; return false;");
189
190                return script.toString();
191        }
192
193        /**
194         * Sets the popup window height.
195         * 
196         * @param popupHeight
197         *            the popup window height.
198         * @return This
199         */
200        public PopupSettings setHeight(int popupHeight)
201        {
202                height = popupHeight;
203                return this;
204        }
205
206        /**
207         * Sets the left position of the popup window.
208         * 
209         * @param popupPositionLeft
210         *            the left position of the popup window.
211         * @return This
212         */
213        public PopupSettings setLeft(int popupPositionLeft)
214        {
215                left = popupPositionLeft;
216                return this;
217        }
218
219        /**
220         * Sets the target of the link. The default implementation simply refers to the href attribute of
221         * the anchor element, but clients may want to override this (e.g. when the HTML element is not an anchor) by
222         * setting the target explicitly.
223         *
224         * <strong>Note</strong>: if the target is an url (relative or absolute) then it should be wrapped in
225         * quotes, for example: <code>setTarget("'some/url'")</code>. If the url is delivered with an HTML attribute then
226         * it should be without quotes, for example: <code>setTarget("this.dataset['popup-url']")</code> with markup like:
227         * <pre><code>&lt;a data-popup-url="some/url"&gt;Link&lt;/a&gt;</code></pre>.
228         * 
229         * @param target
230         *            the target of the link
231         */
232        public void setTarget(String target)
233        {
234                this.target = target;
235        }
236
237        /**
238         * Sets the top position of the popup window.
239         * 
240         * @param popupPositionTop
241         *            the top position of the popup window.
242         * @return This
243         */
244        public PopupSettings setTop(int popupPositionTop)
245        {
246                top = popupPositionTop;
247                return this;
248        }
249
250        /**
251         * Sets the popup window width.
252         * 
253         * @param popupWidth
254         *            the popup window width.
255         * @return This
256         */
257        public PopupSettings setWidth(int popupWidth)
258        {
259                width = popupWidth;
260                return this;
261        }
262
263        /**
264         * Sets the window name. The logical name of the window. This can be anything you want, although
265         * you should use alphanumeric characters only (no spaces or punctuation). If you have a window
266         * already open and call window.open a second time using the same windowName, the first window
267         * will be reused rather than opening a second window
268         * 
269         * @param popupWindowName
270         *            window name.
271         * @return This
272         */
273        public PopupSettings setWindowName(String popupWindowName)
274        {
275                if (popupWindowName != null)
276                {
277                        windowName = popupWindowName;
278                }
279                return this;
280        }
281
282        /**
283         * @param flag
284         *            The flag to test
285         * @return Yes or no depending on whether the flag is set
286         */
287        private String flagToString(final int flag)
288        {
289                return (displayFlags & flag) != 0 ? "yes" : "no";
290        }
291}