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: */
017: package org.apache.wicket.extensions.ajax.markup.html.modal;
018:
019: import org.apache.wicket.Component;
020: import org.apache.wicket.IClusterable;
021: import org.apache.wicket.IPageMap;
022: import org.apache.wicket.Page;
023: import org.apache.wicket.RequestCycle;
024: import org.apache.wicket.ResourceReference;
025: import org.apache.wicket.Session;
026: import org.apache.wicket.WicketRuntimeException;
027: import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
028: import org.apache.wicket.ajax.AjaxRequestTarget;
029: import org.apache.wicket.ajax.IAjaxCallDecorator;
030: import org.apache.wicket.ajax.calldecorator.CancelEventIfNoAjaxDecorator;
031: import org.apache.wicket.behavior.HeaderContributor;
032: import org.apache.wicket.markup.ComponentTag;
033: import org.apache.wicket.markup.html.WebMarkupContainer;
034: import org.apache.wicket.markup.html.panel.Panel;
035: import org.apache.wicket.markup.html.resources.CompressedResourceReference;
036: import org.apache.wicket.markup.html.resources.JavascriptResourceReference;
037: import org.apache.wicket.request.RequestParameters;
038: import org.apache.wicket.settings.IPageSettings;
039: import org.apache.wicket.util.lang.EnumeratedType;
040: import org.apache.wicket.util.string.AppendingStringBuffer;
041: import org.apache.wicket.util.string.Strings;
042:
043: /**
044: * Modal window component.
045: * <p>
046: * Modal window is a draggable window (with either div or iframe content) that
047: * prevent user from interacting the rest of page (using a mask) until the
048: * window is closed.
049: * <p>
050: * If you want this to work under IE, don't attach this component to a
051: * <span> tag, make sure you use a <div>.
052: * <p>
053: * The window is draggable and optionally resizable. The content can be either
054: * <ul>
055: * <li><b>a component</b> - you need to add the component to modal window
056: * (with id obtained using <code>{@link #getContentId()}</code>, or
057: * <li><b>a page</b> - you need to pass a <code>{@link PageCreator}</code>
058: * instance to a <code>{@link #setPageCreator(ModalWindow.PageCreator)}</code>
059: * method.
060: * </ul>
061: * In case the content is a component, it is not rendered until the window is
062: * shown (method <code>{@link #show(AjaxRequestTarget)})</code>. In case the
063: * content is another page, you can set the desired pagemap name using
064: * <code>{@link #setPageMapName(String)}</code>. Setting pagemap is only
065: * needed when wicket multiwindow support is on.
066: * <p>
067: * The window can be made visible from an ajax handler using
068: * <code>{@link #show(AjaxRequestTarget)}</code>.
069: * <p>
070: * To close the window there are multiple options. Static method
071: * <code>{@link #close(AjaxRequestTarget)}</code> can be used to close the
072: * window from a handler of ajax link inside the window. By default the close
073: * button in the upper right corner of the window closes it. This behavior can
074: * be altered using
075: * <code>{@link #setCloseButtonCallback(ModalWindow.CloseButtonCallback)}</code>.
076: * If you want to be notified when the window is closed (either using the close
077: * button or calling <code>{@link #close(AjaxRequestTarget)})</code>, you
078: * can use
079: * <code>{@link #setWindowClosedCallback(ModalWindow.WindowClosedCallback)}</code>.
080: * <p>
081: * Title is specified using {@link #setTitle(String)}. If the content is a page
082: * (iframe), the title can remain unset, in that case title from the page inside
083: * window will be shown.
084: * <p>
085: * There are several options to specify the visual properties of the window. In
086: * all methods where size is expected, width refers to width of entire window
087: * (including frame), height refers to the height of window content (without
088: * frame).
089: * <p>
090: * <ul>
091: * <li><code>{@link #setResizable(boolean)}</code> specifies, whether the
092: * window can be resized.
093: * <li><code>{@link #setInitialWidth(int)}</code> and
094: * <code>{@link #setInitialHeight(int)}</code> specify the initial width and
095: * height of window. If the window is resizable, the unit of these dimensions is
096: * always "px". If the window is not resizable, the unit can be specified using
097: * <code>{@link #setWidthUnit(String)}</code> and
098: * <code>{@link #setHeightUnit(String)}</code>. If the window is not
099: * resizable and the content is a component (not a page), the initial height
100: * value can be ignored and the actual height can be determined from the height
101: * of the content. To enable this behavior use
102: * <code>{@link #setUseInitialHeight(boolean)}</code>.
103: * <li>The window position (and size if the window is resizable) can be stored
104: * in a cookie, so that it is preserved when window is close. The name of the
105: * cookie is specified via <code>{@link #setCookieName(String)}</code>. If
106: * the name is <code>null</code>, position is not stored (initial width and
107: * height are always used). Default cookie name is null (position is not
108: * stored).
109: * <li><code>{@link #setMinimalWidth(int)}</code> and
110: * <code>{@link #setMinimalHeight(int)}</code> set the minimal dimensions of
111: * resizable window.
112: * <li>Modal window can chose between two colors of frame.
113: * <code>{@link #setCssClassName(String)}</code> sets the dialog css class,
114: * possible values are <code>{@link #CSS_CLASS_BLUE}</code> for blue frame and
115: * <code>{@link #CSS_CLASS_GRAY}</code> for gray frame.
116: * <li>Mask (element that prevents user from interacting the rest of the page)
117: * can be either transparent or semitransparent.
118: * <code>{@link #setMaskType(ModalWindow.MaskType)}</code> alters this.
119: * </ul>
120: *
121: * @see IPageSettings#setAutomaticMultiWindowSupport(boolean)
122: * @author Matej Knopp
123: */
124: public class ModalWindow extends Panel {
125: private static final long serialVersionUID = 1L;
126:
127: private static ResourceReference JAVASCRIPT = new JavascriptResourceReference(
128: ModalWindow.class, "res/modal.js");
129:
130: private static ResourceReference CSS = new CompressedResourceReference(
131: ModalWindow.class, "res/modal.css");
132:
133: /**
134: * Creates a new modal window component.
135: *
136: * @param id
137: * Id of component
138: */
139: public ModalWindow(String id) {
140: super (id);
141: setVersioned(false);
142: this .cookieName = null;
143: add(empty = new WebMarkupContainer(getContentId()));
144:
145: add(new CloseButtonBehavior());
146: add(new WindowClosedBehavior());
147: add(HeaderContributor.forJavaScript(JAVASCRIPT));
148: add(HeaderContributor.forCss(CSS));
149: }
150:
151: /**
152: * Interface for lazy page creation. The advantage of creating page using
153: * this interface over just passing a page instance is that page created in
154: * <code>{@link #createPage()}</code> will have the pagemap automatically
155: * set to the pagemap specified for <code>{@link ModalWindow}</code>.
156: *
157: * @author Matej Knopp
158: */
159: public static interface PageCreator extends IClusterable {
160: /**
161: * Creates a new instance of content page.
162: *
163: * @return new page instance
164: */
165: public Page createPage();
166: }
167:
168: /**
169: * Callback for close button that contains a method that is invoked after
170: * the button has been clicked. If no callback instance is specified using
171: * <code>{@link #setCloseButtonCallback(ModalWindow.CloseButtonCallback)}</code>,
172: * no ajax request will be fired. Clicking the button will just close the
173: * window.
174: *
175: * @author Matej Knopp
176: */
177: public static interface CloseButtonCallback extends IClusterable {
178: /**
179: * Methods invoked after the button has been clicked. The invokation is
180: * done using an ajax call, so <code>{@link AjaxRequestTarget}</code>
181: * instance is available.
182: *
183: * @param target
184: * <code>{@link AjaxRequestTarget}</code> instance bound
185: * with the ajax reuqest.
186: *
187: * @return True if the window can be closed (will close the window),
188: * false otherwise
189: */
190: public boolean onCloseButtonClicked(AjaxRequestTarget target);
191: }
192:
193: /**
194: * Callback called after the window has been closed. If no callback instance
195: * is specified using
196: * {@link ModalWindow#setWindowClosedCallback(ModalWindow.WindowClosedCallback)},
197: * no ajax request will be fired.
198: *
199: * @author Matej Knopp
200: */
201: public static interface WindowClosedCallback extends IClusterable {
202: /**
203: * Called after the window has been closed.
204: *
205: * @param target
206: * <code>{@link AjaxRequestTarget}</code> instance bound
207: * with the ajax reuqest.
208: */
209: public void onClose(AjaxRequestTarget target);
210: }
211:
212: /**
213: * Is this window currently showing.
214: *
215: * @return the shown
216: */
217: public boolean isShown() {
218: return shown;
219: }
220:
221: /**
222: * Sets the name of the page ma for the content page. This makes only sense
223: * when the content is a page, not a component and if wicket multiwindow
224: * support is turned on.
225: *
226: * @param pageMapName
227: * Name of the page map
228: */
229: public void setPageMapName(String pageMapName) {
230: this .pageMapName = pageMapName;
231: }
232:
233: /**
234: * Returns the page map name.
235: *
236: * @return The page map name.
237: */
238: public String getPageMapName() {
239: return pageMapName;
240: }
241:
242: /**
243: * Sets the <code>{@link PageCreator}</code> instance. The instance is
244: * only used when no custom component has been added to the dialog.
245: *
246: * @param creator
247: * <code>{@link PageCreator}</code> instance
248: */
249: public void setPageCreator(PageCreator creator) {
250: this .pageCreator = creator;
251: }
252:
253: /**
254: * Sets the <code>{@link CloseButtonCallback}</code> instance.
255: *
256: * @param callback
257: * Callback instance
258: */
259: public void setCloseButtonCallback(CloseButtonCallback callback) {
260: this .closeButtonCallback = callback;
261: }
262:
263: /**
264: * Sets the <code>@{link {@link WindowClosedCallback}</code> instance.
265: *
266: * @param callback
267: * Callback instance
268: */
269: public void setWindowClosedCallback(WindowClosedCallback callback) {
270: this .windowClosedCallback = callback;
271: }
272:
273: /**
274: * Shows the modal window.
275: *
276: * @param target
277: * Request target associated with current ajax request.
278: */
279: public void show(AjaxRequestTarget target) {
280: if (shown == false) {
281: target.addComponent(this );
282: target.appendJavascript(getWindowOpenJavascript());
283: shown = true;
284: }
285: }
286:
287: /**
288: * Hides the modal window.
289: * This can be called from within the modal window, however, the
290: * modal window must have configured WindowClosedCallback. Otherwise
291: * use the {@link #close(AjaxRequestTarget)} method.
292: *
293: * @param target
294: * Request target associated with current ajax request.
295: */
296: public static final void closeCurrent(AjaxRequestTarget target) {
297: target.appendJavascript(getCloseJavacript());
298: }
299:
300: /**
301: * Closes the modal window.
302: *
303: * @param target
304: * Request target associated with current ajax request.
305: */
306: public void close(AjaxRequestTarget target) {
307: target.appendJavascript(getCloseJavacript());
308: shown = false;
309: }
310:
311: /**
312: * @return javascript that closes current modal window
313: */
314: private static String getCloseJavacript() {
315: return "var win;\n" //
316: + "try {\n"
317: + " win = window.parent.Wicket.Window;\n"
318: + "} catch (ignore) {\n"
319: + "}\n"
320: + "if (typeof(win) == \"undefined\" || typeof(win.current) == \"undefined\") {\n"
321: + " try {\n"
322: + " win = window.Wicket.Window;\n"
323: + " } catch (ignore) {\n"
324: + " }\n"
325: + "}\n"
326: + "if (typeof(win) != \"undefined\" && typeof(win.current) != \"undefined\") {\n"
327: + " window.parent.setTimeout(function() {\n"
328: + " win.current.close();\n" + " }, 0);\n" + "}";
329: }
330:
331: /**
332: * Returns the id of content component.
333: *
334: * <pre>
335: * ModalWindow window = new ModalWindow(parent, "window");
336: * new MyPanel(window, window.getContentId());
337: * </pre>
338: *
339: * @return Id of content component.
340: */
341: public String getContentId() {
342: return "content";
343: }
344:
345: /**
346: * Sets the minimal width of window. This value is only used if the window
347: * is resizable. The width is specified in pixels and it is the width of
348: * entire window (including frame).
349: *
350: * @param minimalWidth
351: * Minimal window width.
352: */
353: public void setMinimalWidth(int minimalWidth) {
354: this .minimalWidth = minimalWidth;
355: }
356:
357: /**
358: * Returns the minimal width of window (in pixels).
359: *
360: * @return Minimal width of window
361: */
362: public int getMinimalWidth() {
363: return minimalWidth;
364: }
365:
366: /**
367: * Sets the minimal height of window. This value is only used if window is
368: * resizable. The height is specified in pixels and it is the height of
369: * window content (without frame).
370: *
371: * @param minimalHeight
372: * Minimal height
373: */
374: public void setMinimalHeight(int minimalHeight) {
375: this .minimalHeight = minimalHeight;
376: }
377:
378: /**
379: * Returns the minimal height of window (in pixels).
380: *
381: * @return Minimal height of window
382: */
383: public int getMinimalHeight() {
384: return minimalHeight;
385: }
386:
387: /**
388: * CSS class for window with blue border.
389: */
390: public final static String CSS_CLASS_BLUE = "w_blue";
391:
392: /**
393: * CSS class for window with gray border.
394: */
395: public final static String CSS_CLASS_GRAY = "w_silver";
396:
397: /**
398: * Sets the CSS class name for this window. This class affects the look of
399: * window frame. Possible values (if you don't make your style sheet) are
400: * <code>{@link #CSS_CLASS_BLUE}</code> and
401: * <code>{@link #CSS_CLASS_GRAY}</code>.
402: *
403: * @param cssClassName
404: */
405: public void setCssClassName(String cssClassName) {
406: this .cssClassName = cssClassName;
407: }
408:
409: /**
410: * Returns the CSS class name for this window.
411: *
412: * @return CSS class name
413: */
414: public String getCssClassName() {
415: return cssClassName;
416: }
417:
418: /**
419: * Sets the initial width of the window. The width refers to the width of
420: * entire window (including frame). If the window is resizable, the width
421: * unit is always "px". If the window is not resizable, the unit can be
422: * specified using {@link #setWidthUnit(String)}. If cookie name is set and
423: * window is resizable, the initial width may be ignored in favor of width
424: * stored in cookie.
425: *
426: * @param initialWidth
427: * Initial width of the window
428: */
429: public void setInitialWidth(int initialWidth) {
430: this .initialWidth = initialWidth;
431: }
432:
433: /**
434: * Returns the initial width of the window.
435: *
436: * @return Initial height of the window
437: */
438: public int getInitialWidth() {
439: return initialWidth;
440: }
441:
442: /**
443: * Sets the initial height of the window. The height refers to the height of
444: * window content (without frame). If the window is resizable, the height
445: * unit is always "px". If the window is not resizable, the unit can be
446: * specified using {@link #setHeightUnit(String)}. If cookie name is set
447: * and window is resizable, the initial height may be ignred in favor of
448: * height stored in cookie.
449: *
450: * @param initialHeight
451: * Initial height of the window
452: */
453: public void setInitialHeight(int initialHeight) {
454: this .initialHeight = initialHeight;
455: }
456:
457: /**
458: * Returns the initial height of the window.
459: *
460: * @return Initial height of the window
461: */
462: public int getInitialHeight() {
463: return initialHeight;
464: }
465:
466: /**
467: * Sets whether to use initial height or preserve the real content height.
468: * This can only be used if the content is a component (not a page) and the
469: * window is not resizable.
470: *
471: * @param useInitialHeight
472: * Whether to use initial height instead of preserving content
473: * height instead of using initial height
474: */
475: public void setUseInitialHeight(boolean useInitialHeight) {
476: this .useInitialHeight = useInitialHeight;
477: }
478:
479: /**
480: * Returns true if the initial height should be used (in favour of
481: * preserving real content height).
482: *
483: * @return True if initial height should be used, false is real content
484: * height should be preserved (valid only if the window is not
485: * resizable and the content is a component (not a page)
486: */
487: public boolean isUseInitialHeight() {
488: return useInitialHeight;
489: }
490:
491: /**
492: * Sets whether the user will be able to resize the window.
493: *
494: * @param resizable
495: * Whether the window is resizable
496: */
497: public void setResizable(boolean resizable) {
498: this .resizable = resizable;
499: }
500:
501: /**
502: * Returns whether the window is resizable.
503: *
504: * @return True if the window is resizable, false otherwise
505: */
506: public boolean isResizable() {
507: return resizable;
508: }
509:
510: /**
511: * Sets the CSS unit used for initial window width. This is only applicable
512: * when the window is not resizable.
513: *
514: * @param widthUnit
515: * CSS unit for initial window width.
516: */
517: public void setWidthUnit(String widthUnit) {
518: this .widthUnit = widthUnit;
519: }
520:
521: /**
522: * Returns the CSS unit for initial window width.
523: *
524: * @return CSS unit for initial window width.
525: */
526: public String getWidthUnit() {
527: return widthUnit;
528: }
529:
530: /**
531: * Sets the CSS unit used for initial window height. This is only applicable
532: * when the window is not resizable.
533: *
534: * @param heightUnit
535: * CSS unit for initial window height.
536: */
537: public void setHeightUnit(String heightUnit) {
538: this .heightUnit = heightUnit;
539: }
540:
541: /**
542: * Retrns the CSS unit for initial window height.
543: *
544: * @return CSS unit for initial window height.
545: */
546: public String getHeightUnit() {
547: return heightUnit;
548: }
549:
550: /**
551: * Sets the name of the cookie that is used to remeber window position (and
552: * size if the window is resizable).
553: *
554: * @param cookieName
555: * Name of the cookie
556: */
557: public void setCookieName(String cookieName) {
558: this .cookieName = cookieName;
559: }
560:
561: /**
562: * Returns the name of cookie that is used to remebember window position
563: * (and size if the window is resizable).
564: *
565: * @return Name of the cookie
566: */
567: public String getCookieName() {
568: return cookieName;
569: }
570:
571: /**
572: * Sets the title of window. If the window is a page, title can be
573: * <code>null</code>. In that case it will display the title document
574: * inside the window.
575: *
576: * @param title
577: * Title of the window
578: */
579: public void setTitle(String title) {
580: this .title = title;
581: }
582:
583: /**
584: * Returns the title of the window.
585: *
586: * @return Title of the window
587: */
588: public String getTitle() {
589: return title;
590: }
591:
592: /**
593: * Mask is the element behind the window, that prevents user from
594: * interacting the rest of page. Mask can be either
595: * <ul>
596: * <li><code>{@link #TRANSPARENT}</code> - the mask is invisible
597: * <li><code>{@link #SEMI_TRANSPARENT}</code> - the mask is black with
598: * small opacity (10%)
599: * </ul>
600: *
601: * @author Matej Knopp
602: */
603: public static final class MaskType extends EnumeratedType {
604:
605: private static final long serialVersionUID = 1L;
606:
607: /**
608: * Transparent mask (not visible).
609: */
610: public static final MaskType TRANSPARENT = new MaskType(
611: "TRANSPARENT");
612:
613: /**
614: * Visible mask (black with low opacity).
615: */
616: public static final MaskType SEMI_TRANSPARENT = new MaskType(
617: "SEMI_TRANSPARENT");
618:
619: /**
620: * Constructor.
621: *
622: * @param name
623: */
624: public MaskType(String name) {
625: super (name);
626: }
627: };
628:
629: /**
630: * Sets the mask type of the window.
631: *
632: * @param mask
633: * The mask type
634: */
635: public void setMaskType(MaskType mask) {
636: this .maskType = mask;
637: }
638:
639: /**
640: * Returns the mask type of the window
641: *
642: * @return The mask type
643: */
644: public MaskType getMaskType() {
645: return maskType;
646: }
647:
648: /**
649: * Creates the page.
650: *
651: * @return Page instance or null if page couldn't be created.
652: */
653: private Page createPage() {
654: if (pageCreator == null) {
655: return null;
656: } else {
657: RequestParameters parameters = RequestCycle.get()
658: .getRequest().getRequestParameters();
659: String oldPageMapName = parameters.getPageMapName();
660:
661: // if there is a pagemap name specified and multiwindow support is
662: // on
663: if (getPageMapName() != null) {
664: // try to find out whether the pagemap already exists
665: Session session = Session.get();
666: if (session.pageMapForName(getPageMapName(), false) == null) {
667: deletePageMap = true;
668: }
669: parameters.setPageMapName(getPageMapName());
670: }
671: try {
672: Page page = pageCreator.createPage();
673: return page;
674: } finally {
675: parameters.setPageMapName(oldPageMapName);
676: }
677: }
678: }
679:
680: /**
681: * @see org.apache.wicket.Component#onBeforeRender()
682: */
683: protected void onBeforeRender() {
684: super .onBeforeRender();
685: getContent().setOutputMarkupId(true);
686: getContent().setVisible(shown);
687: }
688:
689: /**
690: * @see org.apache.wicket.markup.html.panel.Panel#onComponentTag(org.apache.wicket.markup.ComponentTag)
691: */
692: protected void onComponentTag(ComponentTag tag) {
693: super .onComponentTag(tag);
694: tag.put("style", "display:none");
695: }
696:
697: /**
698: * Returns a content component. In case user haven't specified any content
699: * component, it returns an empty WebMarkupContainer.
700: *
701: * @return Content component
702: */
703: private Component getContent() {
704: return get(getContentId());
705: }
706:
707: /**
708: * Returns true if user has added own component to the window.
709: *
710: * @return True if user has added own component to the window, false
711: * otherwise.
712: */
713: private boolean isCustomComponent() {
714: return getContent() != empty;
715: }
716:
717: /**
718: * @see org.apache.wicket.MarkupContainer#remove(org.apache.wicket.Component)
719: */
720: public void remove(Component component) {
721: super .remove(component);
722: if (component.getId().equals(getContentId())) {
723: add(empty = new WebMarkupContainer(getContentId()));
724: }
725: }
726:
727: /**
728: * Sets the content of the modal window.
729: *
730: * @param component
731: */
732: public void setContent(Component component) {
733: if (component.getId().equals(getContentId()) == false) {
734: throw new WicketRuntimeException(
735: "Modal window content id is wrong.");
736: }
737: replace(component);
738: shown = false;
739: }
740:
741: /**
742: * @author Matej Knopp
743: */
744: private class WindowClosedBehavior extends
745: AbstractDefaultAjaxBehavior {
746: private static final long serialVersionUID = 1L;
747:
748: protected void respond(AjaxRequestTarget target) {
749: shown = false;
750:
751: // should we cleanup the pagemap?
752: if (deletePageMap == true) {
753: // get the pagemap
754: Session session = Session.get();
755: IPageMap pageMap = session.pageMapForName(
756: getPageMapName(), false);
757:
758: // if there is any remove it
759: if (pageMap != null) {
760: session.removePageMap(pageMap);
761: deletePageMap = false;
762: }
763: }
764:
765: if (windowClosedCallback != null) {
766: windowClosedCallback.onClose(target);
767: }
768: }
769:
770: protected CharSequence getCallbackScript() {
771: return super .getCallbackScript();
772: }
773: };
774:
775: /**
776: * @author Matej Knopp
777: */
778: private class CloseButtonBehavior extends
779: AbstractDefaultAjaxBehavior {
780: private static final long serialVersionUID = 1L;
781:
782: protected void respond(AjaxRequestTarget target) {
783: if (closeButtonCallback == null
784: || closeButtonCallback.onCloseButtonClicked(target) == true) {
785: close(target);
786: }
787: }
788:
789: protected IAjaxCallDecorator getAjaxCallDecorator() {
790: return new CancelEventIfNoAjaxDecorator(super
791: .getAjaxCallDecorator());
792: }
793:
794: protected CharSequence getCallbackScript() {
795: return super .getCallbackScript();
796: }
797: }
798:
799: /**
800: * Returns the markup id of the component.
801: *
802: * @return component id
803: */
804: private String getContentMarkupId() {
805: return getContent().getMarkupId();
806: }
807:
808: /**
809: * Replaces all occurences of " in string with \".
810: *
811: * @param string
812: * String to be escaped.
813: *
814: * @return escaped string
815: */
816: private String escapeQuotes(String string) {
817: if (string.indexOf('"') != -1) {
818: string = Strings.replaceAll(string, "\"", "\\\"")
819: .toString();
820: }
821: return string;
822: }
823:
824: /**
825: * Returns the javascript used to open the window.
826: *
827: * @return javascript that opens the window
828: */
829: private String getWindowOpenJavascript() {
830: AppendingStringBuffer buffer = new AppendingStringBuffer();
831:
832: if (isCustomComponent() == true) {
833: buffer.append("var element = document.getElementById(\""
834: + getContentMarkupId() + "\");\n");
835: }
836:
837: buffer.append("var settings = new Object();\n");
838: buffer.append("settings.minWidth=" + getMinimalWidth() + ";\n");
839: buffer.append("settings.minHeight=" + getMinimalHeight()
840: + ";\n");
841: buffer.append("settings.className=\"" + getCssClassName()
842: + "\";\n");
843: buffer
844: .append("settings.width=\"" + getInitialWidth()
845: + "\";\n");
846:
847: if (isUseInitialHeight() == true
848: || isCustomComponent() == false)
849: buffer.append("settings.height=\"" + getInitialHeight()
850: + "\";\n");
851: else
852: buffer.append("settings.height=null;\n");
853:
854: buffer.append("settings.resizable="
855: + Boolean.toString(isResizable()) + ";\n");
856:
857: if (isResizable() == false) {
858: buffer.append("settings.widthUnit=\"" + getWidthUnit()
859: + "\";\n");
860: buffer.append("settings.heightUnit=\"" + getHeightUnit()
861: + "\";\n");
862: }
863:
864: if (isCustomComponent() == false) {
865: Page page = createPage();
866: if (page == null) {
867: throw new WicketRuntimeException(
868: "Error creating page for modal dialog.");
869: }
870: buffer.append("settings.src=\""
871: + RequestCycle.get().urlFor(page) + "\";\n");
872:
873: if (getPageMapName() != null) {
874: buffer.append("settings.iframeName=\""
875: + getPageMapName() + "\";\n");
876: }
877: } else {
878: buffer.append("settings.element = element;\n");
879: }
880:
881: if (getCookieName() != null) {
882: buffer.append("settings.cookieId=\"" + getCookieName()
883: + "\";\n");
884: }
885:
886: if (getTitle() != null) {
887: buffer.append("settings.title=\""
888: + escapeQuotes(getTitle()) + "\";\n");
889: }
890:
891: if (getMaskType() == MaskType.TRANSPARENT) {
892: buffer.append("settings.mask=\"transparent\";\n");
893: } else if (getMaskType() == MaskType.SEMI_TRANSPARENT) {
894: buffer.append("settings.mask=\"semi-transparent\";\n");
895: }
896:
897: // set true if we set a windowclosedcallback
898: boolean haveCloseCallback = false;
899:
900: // in case user is interested in window close callback or we have a pagemap to clean
901: // attach notification request
902: if ((isCustomComponent() == false && deletePageMap)
903: || windowClosedCallback != null) {
904: WindowClosedBehavior behavior = (WindowClosedBehavior) getBehaviors(
905: WindowClosedBehavior.class).get(0);
906: buffer.append("settings.onClose = function() { "
907: + behavior.getCallbackScript() + " };\n");
908:
909: haveCloseCallback = true;
910: }
911:
912: // in case we didn't set windowclosecallback, we need at least callback on close button,
913: // to close window property (thus cleaning the shown flag)
914: if (closeButtonCallback != null || haveCloseCallback == false) {
915: CloseButtonBehavior behavior = (CloseButtonBehavior) getBehaviors(
916: CloseButtonBehavior.class).get(0);
917: buffer.append("settings.onCloseButton = function() { "
918: + behavior.getCallbackScript() + "};\n");
919: }
920:
921: postProcessSettings(buffer);
922:
923: buffer.append("Wicket.Window.create(settings).show();\n");
924:
925: return buffer.toString();
926: }
927:
928: /**
929: * Method that allows tweaking the settings
930: * @param settings
931: * @return settings javascript
932: */
933: protected AppendingStringBuffer postProcessSettings(
934: AppendingStringBuffer settings) {
935: return settings;
936: }
937:
938: private boolean deletePageMap = false;
939: private boolean shown = false;
940:
941: // empty container - used when no component is added
942: private WebMarkupContainer empty;
943:
944: private int minimalWidth = 200;
945: private int minimalHeight = 200;
946: private String cssClassName = CSS_CLASS_BLUE;
947: private int initialWidth = 600;
948: private int initialHeight = 400;
949: private boolean useInitialHeight = true;
950: private boolean resizable = true;
951: private String widthUnit = "px";
952: private String heightUnit = "px";
953: private String cookieName;
954: private String title = null;
955: private MaskType maskType = MaskType.SEMI_TRANSPARENT;
956:
957: private String pageMapName = "modal-dialog-pagemap";
958:
959: private PageCreator pageCreator = null;
960: private CloseButtonCallback closeButtonCallback = null;
961: private WindowClosedCallback windowClosedCallback = null;
962: }
|