3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.window.Window
17 * @extends Ext.panel.Panel
18 * <p>A specialized panel intended for use as an application window. Windows are floated, {@link #resizable}, and
19 * {@link #draggable} by default. Windows can be {@link #maximizable maximized} to fill the viewport,
20 * restored to their prior size, and can be {@link #minimize}d.</p>
21 * <p>Windows can also be linked to a {@link Ext.ZIndexManager} or managed by the {@link Ext.WindowManager} to provide
22 * grouping, activation, to front, to back and other application-specific behavior.</p>
23 * <p>By default, Windows will be rendered to document.body. To {@link #constrain} a Window to another element
24 * specify {@link Ext.Component#renderTo renderTo}.</p>
25 * <p><b>As with all {@link Ext.container.Container Container}s, it is important to consider how you want the Window
26 * to size and arrange any child Components. Choose an appropriate {@link #layout} configuration which lays out
27 * child Components in the required manner.</b></p>
28 * {@img Ext.window.Window/Ext.window.Window.png Window component}
30 Ext.create('Ext.window.Window', {
35 items: { // Let's put an empty grid in just to illustrate fit layout
38 columns: [{header: 'World'}], // One header just for show. There's no data,
39 store: Ext.create('Ext.data.ArrayStore', {}) // A dummy empty data store
44 Ext.define('Ext.window.Window', {
45 extend: 'Ext.panel.Panel',
47 alternateClassName: 'Ext.Window',
49 requires: ['Ext.util.ComponentDragger', 'Ext.util.Region', 'Ext.EventManager'],
51 alias: 'widget.window',
55 * The X position of the left edge of the window on initial showing. Defaults to centering the Window within
56 * the width of the Window's container {@link Ext.core.Element Element) (The Element that the Window is rendered to).
60 * The Y position of the top edge of the window on initial showing. Defaults to centering the Window within
61 * the height of the Window's container {@link Ext.core.Element Element) (The Element that the Window is rendered to).
64 * @cfg {Boolean} modal
65 * True to make the window modal and mask everything behind it when displayed, false to display it without
66 * restricting access to other UI elements (defaults to false).
69 * @cfg {String/Element} animateTarget
70 * Id or element from which the window should animate while opening (defaults to null with no animation).
73 * @cfg {String/Number/Component} defaultFocus
74 * <p>Specifies a Component to receive focus when this Window is focused.</p>
75 * <p>This may be one of:</p><div class="mdetail-params"><ul>
76 * <li>The index of a footer Button.</li>
77 * <li>The id or {@link Ext.AbstractComponent#itemId} of a descendant Component.</li>
78 * <li>A Component.</li>
82 * @cfg {Function} onEsc
83 * Allows override of the built-in processing for the escape key. Default action
84 * is to close the Window (performing whatever action is specified in {@link #closeAction}.
85 * To prevent the Window closing when the escape key is pressed, specify this as
86 * Ext.emptyFn (See {@link Ext#emptyFn Ext.emptyFn}).
89 * @cfg {Boolean} collapsed
90 * True to render the window collapsed, false to render it expanded (defaults to false). Note that if
91 * {@link #expandOnShow} is true (the default) it will override the <code>collapsed</code> config and the window
92 * will always be expanded when shown.
95 * @cfg {Boolean} maximized
96 * True to initially display the window in a maximized state. (Defaults to false).
100 * @cfg {String} baseCls
101 * The base CSS class to apply to this panel's element (defaults to 'x-window').
103 baseCls: Ext.baseCSSPrefix + 'window',
106 * @cfg {Mixed} resizable
107 * <p>Specify as <code>true</code> to allow user resizing at each edge and corner of the window, false to disable
108 * resizing (defaults to true).</p>
109 * <p>This may also be specified as a config object to </p>
114 * @cfg {Boolean} draggable
115 * <p>True to allow the window to be dragged by the header bar, false to disable dragging (defaults to true). Note
116 * that by default the window will be centered in the viewport, so if dragging is disabled the window may need
117 * to be positioned programmatically after render (e.g., myWindow.setPosition(100, 100);).<p>
122 * @cfg {Boolean} constrain
123 * True to constrain the window within its containing element, false to allow it to fall outside of its
124 * containing element. By default the window will be rendered to document.body. To render and constrain the
125 * window within another element specify {@link #renderTo}.
126 * (defaults to false). Optionally the header only can be constrained using {@link #constrainHeader}.
131 * @cfg {Boolean} constrainHeader
132 * True to constrain the window header within its containing element (allowing the window body to fall outside
133 * of its containing element) or false to allow the header to fall outside its containing element (defaults to
134 * false). Optionally the entire window can be constrained using {@link #constrain}.
136 constrainHeader: false,
139 * @cfg {Boolean} plain
140 * True to render the window body with a transparent background so that it will blend into the framing
141 * elements, false to add a lighter background color to visually highlight the body element and separate it
142 * more distinctly from the surrounding frame (defaults to false).
147 * @cfg {Boolean} minimizable
148 * True to display the 'minimize' tool button and allow the user to minimize the window, false to hide the button
149 * and disallow minimizing the window (defaults to false). Note that this button provides no implementation --
150 * the behavior of minimizing a window is implementation-specific, so the minimize event must be handled and a
151 * custom minimize behavior implemented for this option to be useful.
156 * @cfg {Boolean} maximizable
157 * True to display the 'maximize' tool button and allow the user to maximize the window, false to hide the button
158 * and disallow maximizing the window (defaults to false). Note that when a window is maximized, the tool button
159 * will automatically change to a 'restore' button with the appropriate behavior already built-in that will
160 * restore the window to its previous size.
171 * @cfg {Boolean} expandOnShow
172 * True to always expand the window when it is displayed, false to keep it in its current state (which may be
173 * {@link #collapsed}) when displayed (defaults to true).
177 // inherited docs, same default
181 * @cfg {Boolean} closable
182 * <p>True to display the 'close' tool button and allow the user to close the window, false to
183 * hide the button and disallow closing the window (defaults to <code>true</code>).</p>
184 * <p>By default, when close is requested by either clicking the close button in the header
185 * or pressing ESC when the Window has focus, the {@link #close} method will be called. This
186 * will <i>{@link Ext.Component#destroy destroy}</i> the Window and its content meaning that
187 * it may not be reused.</p>
188 * <p>To make closing a Window <i>hide</i> the Window so that it may be reused, set
189 * {@link #closeAction} to 'hide'.</p>
194 * @cfg {Boolean} hidden
195 * Render this Window hidden (default is <code>true</code>). If <code>true</code>, the
196 * {@link #hide} method will be called internally.
200 // Inherit docs from Component. Windows render to the body on first show.
203 // Inherit docs from Component. Windows hide using visibility.
204 hideMode: 'visibility',
206 /** @cfg {Boolean} floating @hide Windows are always floating*/
209 ariaRole: 'alertdialog',
211 itemCls: 'x-window-item',
215 ignoreHeaderBorderManagement: true,
218 initComponent: function() {
224 * Fires after the window has been visually activated via {@link #setActive}.
225 * @param {Ext.window.Window} this
229 * Fires after the window has been visually deactivated via {@link #setActive}.
230 * @param {Ext.window.Window} this
234 * Fires after the window has been resized.
235 * @param {Ext.window.Window} this
236 * @param {Number} width The window's new width
237 * @param {Number} height The window's new height
242 * Fires after the window has been maximized.
243 * @param {Ext.window.Window} this
248 * Fires after the window has been minimized.
249 * @param {Ext.window.Window} this
254 * Fires after the window has been restored to its original size after being maximized.
255 * @param {Ext.window.Window} this
261 me.addClsWithUI('plain');
265 me.ariaRole = 'dialog';
272 initStateEvents: function(){
273 var events = this.stateEvents;
274 // push on stateEvents if they don't exist
275 Ext.each(['maximize', 'restore', 'resize', 'dragend'], function(event){
276 if (Ext.Array.indexOf(events, event)) {
283 getState: function() {
285 state = me.callParent() || {},
286 maximized = !!me.maximized;
288 state.maximized = maximized;
290 size: maximized ? me.restoreSize : me.getSize(),
291 pos: maximized ? me.restorePos : me.getPosition()
296 applyState: function(state){
300 me.maximized = state.maximized;
302 me.hasSavedRestore = true;
303 me.restoreSize = state.size;
304 me.restorePos = state.pos;
307 width: state.size.width,
308 height: state.size.height,
317 onMouseDown: function () {
324 onRender: function(ct, position) {
326 me.callParent(arguments);
329 // Double clicking a header will toggleMaximize
330 if (me.maximizable) {
333 fn: me.toggleMaximize,
342 afterRender: function() {
348 // Component's afterRender sizes and positions the Component
352 // Create the proxy after the size has been applied in Component.afterRender
353 me.proxy = me.getProxy();
356 me.mon(me.el, 'mousedown', me.onMouseDown, me);
360 me.maximized = false;
365 keyMap = me.getKeyMap();
366 keyMap.on(27, me.onEsc, me);
368 //if (hidden) { ? would be consistent w/before/afterShow...
374 me.syncMonitorWindowResize();
382 * Override Component.initDraggable.
383 * Window uses the header element as the delegate.
385 initDraggable: function() {
390 me.updateHeader(true);
394 * Check the header here again. If for whatever reason it wasn't created in
395 * updateHeader (preventHeader) then we'll just ignore the rest since the
396 * header acts as the drag handle.
399 ddConfig = Ext.applyIf({
401 delegate: '#' + me.header.id
404 // Add extra configs if Window is specified to be constrained
405 if (me.constrain || me.constrainHeader) {
406 ddConfig.constrain = me.constrain;
407 ddConfig.constrainDelegate = me.constrainHeader;
408 ddConfig.constrainTo = me.constrainTo || me.container;
412 * <p>If this Window is configured {@link #draggable}, this property will contain
413 * an instance of {@link Ext.util.ComponentDragger} (A subclass of {@link Ext.dd.DragTracker DragTracker})
414 * which handles dragging the Window's DOM Element, and constraining according to the {@link #constrain}
415 * and {@link #constrainHeader} .</p>
416 * <p>This has implementations of <code>onBeforeStart</code>, <code>onDrag</code> and <code>onEnd</code>
417 * which perform the dragging action. If extra logic is needed at these points, use
418 * {@link Ext.Function#createInterceptor createInterceptor} or {@link Ext.Function#createSequence createSequence} to
419 * augment the existing implementations.</p>
420 * @type Ext.util.ComponentDragger
423 me.dd = Ext.create('Ext.util.ComponentDragger', this, ddConfig);
424 me.relayEvents(me.dd, ['dragstart', 'drag', 'dragend']);
429 onEsc: function(k, e) {
431 this[this.closeAction]();
435 beforeDestroy: function() {
438 delete this.animateTarget;
450 * Contribute class-specific tools to the header.
451 * Called by Panel's initTools.
453 addTools: function() {
456 // Call Panel's initTools
459 if (me.minimizable) {
462 handler: Ext.Function.bind(me.minimize, me, [])
465 if (me.maximizable) {
468 handler: Ext.Function.bind(me.maximize, me, [])
472 handler: Ext.Function.bind(me.restore, me, []),
479 * Gets the configured default focus item. If a {@link #defaultFocus} is set, it will receive focus, otherwise the
480 * Container itself will receive focus.
482 getFocusEl: function() {
485 defaultComp = me.defaultButton || me.defaultFocus,
490 if (Ext.isDefined(defaultComp)) {
491 if (Ext.isNumber(defaultComp)) {
492 f = me.query('button')[defaultComp];
493 } else if (Ext.isString(defaultComp)) {
494 f = me.down('#' + defaultComp);
499 return f || me.focusEl;
503 beforeShow: function() {
506 if (this.expandOnShow) {
512 afterShow: function(animateTarget) {
514 animating = animateTarget || me.animateTarget;
519 * If we're animating, constrain the positioning before calling the
520 * superclass, otherwise we'll be animating to the unconstrained
525 // Perform superclass's afterShow tasks
526 // Which might include animating a proxy from an animTarget
527 me.callParent(arguments);
533 me.syncMonitorWindowResize();
544 doClose: function() {
549 me.fireEvent('close', me);
550 me[me.closeAction]();
552 // close after hiding
553 me.hide(me.animTarget, me.doClose, me);
558 afterHide: function() {
561 // No longer subscribe to resizing now that we're hidden
562 me.syncMonitorWindowResize();
564 // Turn off keyboard handling once window is hidden
569 // Perform superclass's afterHide tasks.
570 me.callParent(arguments);
574 onWindowResize: function() {
575 if (this.maximized) {
582 * Placeholder method for minimizing the window. By default, this method simply fires the {@link #minimize} event
583 * since the behavior of minimizing a window is application-specific. To implement custom minimize behavior,
584 * either the minimize event can be handled or this method can be overridden.
585 * @return {Ext.window.Window} this
587 minimize: function() {
588 this.fireEvent('minimize', this);
592 afterCollapse: function() {
595 if (me.maximizable) {
596 me.tools.maximize.hide();
597 me.tools.restore.hide();
600 me.resizer.disable();
602 me.callParent(arguments);
605 afterExpand: function() {
609 me.tools.restore.show();
610 } else if (me.maximizable) {
611 me.tools.maximize.show();
616 me.callParent(arguments);
620 * Fits the window within its current container and automatically replaces
621 * the {@link #maximizable 'maximize' tool button} with the 'restore' tool button.
622 * Also see {@link #toggleMaximize}.
623 * @return {Ext.window.Window} this
625 maximize: function() {
630 if (!me.hasSavedRestore) {
631 me.restoreSize = me.getSize();
632 me.restorePos = me.getPosition(true);
634 if (me.maximizable) {
635 me.tools.maximize.hide();
636 me.tools.restore.show();
639 me.el.disableShadow();
644 if (me.collapseTool) {
645 me.collapseTool.hide();
647 me.el.addCls(Ext.baseCSSPrefix + 'window-maximized');
648 me.container.addCls(Ext.baseCSSPrefix + 'window-maximized-ct');
650 me.syncMonitorWindowResize();
651 me.setPosition(0, 0);
653 me.fireEvent('maximize', me);
659 * Restores a {@link #maximizable maximized} window back to its original
660 * size and position prior to being maximized and also replaces
661 * the 'restore' tool button with the 'maximize' tool button.
662 * Also see {@link #toggleMaximize}.
663 * @return {Ext.window.Window} this
665 restore: function() {
670 delete me.hasSavedRestore;
671 me.removeCls(Ext.baseCSSPrefix + 'window-maximized');
673 // Toggle tool visibility
675 tools.restore.hide();
677 if (tools.maximize) {
678 tools.maximize.show();
680 if (me.collapseTool) {
681 me.collapseTool.show();
684 // Restore the position/sizing
685 me.setPosition(me.restorePos);
686 me.setSize(me.restoreSize);
688 // Unset old position/sizing
689 delete me.restorePos;
690 delete me.restoreSize;
692 me.maximized = false;
694 me.el.enableShadow(true);
696 // Allow users to drag and drop again
701 me.container.removeCls(Ext.baseCSSPrefix + 'window-maximized-ct');
703 me.syncMonitorWindowResize();
705 me.fireEvent('restore', me);
711 * Synchronizes the presence of our listener for window resize events. This method
712 * should be called whenever this status might change.
715 syncMonitorWindowResize: function () {
717 currentlyMonitoring = me._monitoringResize,
718 // all the states where we should be listening to window resize:
719 yes = me.monitorResize || me.constrain || me.constrainHeader || me.maximized,
720 // all the states where we veto this:
721 veto = me.hidden || me.destroying || me.isDestroyed;
724 // we should be listening...
725 if (!currentlyMonitoring) {
726 // but we aren't, so set it up
727 Ext.EventManager.onWindowResize(me.onWindowResize, me);
728 me._monitoringResize = true;
730 } else if (currentlyMonitoring) {
731 // we should not be listening, but we are, so tear it down
732 Ext.EventManager.removeResizeListener(me.onWindowResize, me);
733 me._monitoringResize = false;
738 * A shortcut method for toggling between {@link #maximize} and {@link #restore} based on the current maximized
739 * state of the window.
740 * @return {Ext.window.Window} this
742 toggleMaximize: function() {
743 return this[this.maximized ? 'restore': 'maximize']();
747 * @cfg {Boolean} autoWidth @hide
748 * Absolute positioned element and therefore cannot support autoWidth.
749 * A width is a required configuration.