facebook-workplaceoutlookemailmicrosoft-teamsdiscordmessengercustom-servicesmacoslinuxwindowsinboxwhatsappicloudtweetdeckhipchattelegramhangoutsslackgmailskype
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
925 lines
30 KiB
925 lines
30 KiB
9 years ago
|
/**
|
||
|
* A specialized panel intended for use as an application window. Windows are floated, {@link #resizable}, and
|
||
|
* {@link #cfg-draggable} by default. Windows can be {@link #maximizable maximized} to fill the viewport, restored to
|
||
|
* their prior size, and can be {@link #method-minimize}d.
|
||
|
*
|
||
|
* Windows can also be linked to a {@link Ext.ZIndexManager} or managed by the {@link Ext.WindowManager} to provide
|
||
|
* grouping, activation, to front, to back and other application-specific behavior.
|
||
|
*
|
||
|
* By default, Windows will be rendered to document.body. To {@link #constrain} a Window to another element specify
|
||
|
* {@link Ext.Component#renderTo renderTo}.
|
||
|
*
|
||
|
* **As with all {@link Ext.container.Container Container}s, it is important to consider how you want the Window to size
|
||
|
* and arrange any child Components. Choose an appropriate {@link #layout} configuration which lays out child Components
|
||
|
* in the required manner.**
|
||
|
*
|
||
|
* @example
|
||
|
* Ext.create('Ext.window.Window', {
|
||
|
* title: 'Hello',
|
||
|
* height: 200,
|
||
|
* width: 400,
|
||
|
* layout: 'fit',
|
||
|
* items: { // Let's put an empty grid in just to illustrate fit layout
|
||
|
* xtype: 'grid',
|
||
|
* border: false,
|
||
|
* columns: [{header: 'World'}], // One header just for show. There's no data,
|
||
|
* store: Ext.create('Ext.data.ArrayStore', {}) // A dummy empty data store
|
||
|
* }
|
||
|
* }).show();
|
||
|
*/
|
||
|
Ext.define('Ext.window.Window', {
|
||
|
extend: 'Ext.panel.Panel',
|
||
|
|
||
|
alternateClassName: 'Ext.Window',
|
||
|
|
||
|
requires: ['Ext.util.ComponentDragger', 'Ext.util.Region'],
|
||
|
|
||
|
alias: 'widget.window',
|
||
|
|
||
|
/**
|
||
|
* @cfg {Number} x
|
||
|
* The X position of the left edge of the window on initial showing. Defaults to centering the Window within the
|
||
|
* width of the Window's container {@link Ext.dom.Element Element} (The Element that the Window is rendered to).
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @cfg {Number} y
|
||
|
* The Y position of the top edge of the window on initial showing. Defaults to centering the Window within the
|
||
|
* height of the Window's container {@link Ext.dom.Element Element} (The Element that the Window is rendered to).
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @cfg {String/Ext.dom.Element} [animateTarget=null]
|
||
|
* Id or element from which the window should animate while opening.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean/Function} ghost
|
||
|
* Set to false to disable the ghost panel during dragging the window.
|
||
|
* Do note that you should not set this to true, by default it is a function.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @cfg {String/Number/Ext.Component} defaultFocus
|
||
|
* Specifies a Component to receive focus when this Window is focused.
|
||
|
*
|
||
|
* If a String is provided, the Component will be resolved using the {@link #down} method which uses {@link Ext.ComponentQuery}.
|
||
|
* If the string begins with an alphanumeric value, it will first attempt to find the Component based on the {@link Ext.Component#id} or {@link Ext.Component#itemId}.
|
||
|
* If a matching component is not found via id, then an attempt to do a query to find a matching component.
|
||
|
*
|
||
|
* An example of finding the Component with an id/itemId:
|
||
|
*
|
||
|
* Ext.create('Ext.window.Window', {
|
||
|
* autoShow : true,
|
||
|
* width : 300,
|
||
|
* title : 'Login',
|
||
|
* defaultFocus : 'username',
|
||
|
* items : [
|
||
|
* {
|
||
|
* xtype : 'textfield',
|
||
|
* fieldLabel : 'Username',
|
||
|
* itemId : 'username',
|
||
|
* name : 'username'
|
||
|
* },
|
||
|
* {
|
||
|
* xtype : 'textfield',
|
||
|
* inputType : 'password',
|
||
|
* fieldLabel : 'Password',
|
||
|
* itemId : 'password',
|
||
|
* name : 'password'
|
||
|
* }
|
||
|
* ]
|
||
|
* });
|
||
|
*
|
||
|
* If a Number is provided, this will resolve an {@link Ext.button.Button} at that index. This is very useful if
|
||
|
* the window has buttons in the {@link #buttons} config and you want to provide default focus to one of them.
|
||
|
*
|
||
|
* An example of this would be:
|
||
|
*
|
||
|
* Ext.create('Ext.window.Window', {
|
||
|
* autoShow : true,
|
||
|
* width : 300,
|
||
|
* title : 'Login',
|
||
|
* defaultFocus : 1,
|
||
|
* items : [
|
||
|
* {
|
||
|
* xtype : 'textfield',
|
||
|
* fieldLabel : 'Username',
|
||
|
* name : 'username'
|
||
|
* },
|
||
|
* {
|
||
|
* xtype : 'textfield',
|
||
|
* inputType : 'password',
|
||
|
* fieldLabel : 'Password',
|
||
|
* name : 'password'
|
||
|
* }
|
||
|
* ],
|
||
|
* buttons : [
|
||
|
* {
|
||
|
* text : 'Cancel'
|
||
|
* },
|
||
|
* {
|
||
|
* text : 'Login'
|
||
|
* }
|
||
|
* ]
|
||
|
* });
|
||
|
*
|
||
|
* In summary, defaultFocus may be one of:
|
||
|
*
|
||
|
* - The index of a footer Button.
|
||
|
* - The id or {@link Ext.Component#itemId} of a descendant Component.
|
||
|
* - A {@link Ext.ComponentQuery query} to find a {@link Ext.Component}.
|
||
|
* - A descendant {@link Ext.Component}.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @cfg {Function} onEsc
|
||
|
* Allows override of the built-in processing for the escape key. Default action is to close the Window (performing
|
||
|
* whatever action is specified in {@link #closeAction}. To prevent the Window closing when the escape key is
|
||
|
* pressed, specify this as {@link Ext#emptyFn Ext.emptyFn}.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean} [collapsed=false]
|
||
|
* True to render the window collapsed, false to render it expanded. Note that if {@link #expandOnShow}
|
||
|
* is true (the default) it will override the `collapsed` config and the window will always be
|
||
|
* expanded when shown.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean} [maximized=false]
|
||
|
* True to initially display the window in a maximized state.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean} [hideShadowOnDeactivate=false]
|
||
|
* True to hide this Window's shadow when another floating item in the same z-index stack is activated.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @cfg {String} [baseCls='x-window']
|
||
|
* The base CSS class to apply to this panel's element.
|
||
|
*/
|
||
|
baseCls: Ext.baseCSSPrefix + 'window',
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean/Object} resizable
|
||
|
* Specify as `true` to allow user resizing at each edge and corner of the window, false to disable resizing.
|
||
|
*
|
||
|
* This may also be specified as a config object to Ext.resizer.Resizer
|
||
|
*/
|
||
|
resizable: true,
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean} draggable
|
||
|
* True to allow the window to be dragged by the header bar, false to disable dragging. Note that
|
||
|
* by default the window will be centered in the viewport, so if dragging is disabled the window may need to be
|
||
|
* positioned programmatically after render (e.g., `myWindow.setPosition(100, 100);`).
|
||
|
*/
|
||
|
draggable: true,
|
||
|
|
||
|
/**
|
||
|
* @override
|
||
|
* @cfg {Boolean} constrain
|
||
|
* True to constrain the window within its containing element, false to allow it to fall outside of its containing
|
||
|
* element. By default the window will be rendered to `document.body`. To render and constrain the window within
|
||
|
* another element specify {@link #renderTo}. Optionally the header only can be constrained
|
||
|
* using {@link #constrainHeader}.
|
||
|
*/
|
||
|
constrain: false,
|
||
|
|
||
|
/**
|
||
|
* @override
|
||
|
* @cfg {Boolean} constrainHeader
|
||
|
* True to constrain the window header within its containing element (allowing the window body to fall outside of
|
||
|
* its containing element) or false to allow the header to fall outside its containing element.
|
||
|
* Optionally the entire window can be constrained using {@link #constrain}.
|
||
|
*/
|
||
|
constrainHeader: false,
|
||
|
|
||
|
/**
|
||
|
* @cfg simpleDrag
|
||
|
* @hide
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean} plain
|
||
|
* True to render the window body with a transparent background so that it will blend into the framing elements,
|
||
|
* false to add a lighter background color to visually highlight the body element and separate it more distinctly
|
||
|
* from the surrounding frame.
|
||
|
*/
|
||
|
plain: false,
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean} minimizable
|
||
|
* True to display the 'minimize' tool button and allow the user to minimize the window, false to hide the button
|
||
|
* and disallow minimizing the window. Note that this button provides no implementation -- the
|
||
|
* behavior of minimizing a window is implementation-specific, so the minimize event must be handled and a custom
|
||
|
* minimize behavior implemented for this option to be useful.
|
||
|
*/
|
||
|
minimizable: false,
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean} maximizable
|
||
|
* True to display the 'maximize' tool button and allow the user to maximize the window, false to hide the button
|
||
|
* and disallow maximizing the window. Note that when a window is maximized, the tool button
|
||
|
* will automatically change to a 'restore' button with the appropriate behavior already built-in that will restore
|
||
|
* the window to its previous size.
|
||
|
*/
|
||
|
maximizable: false,
|
||
|
|
||
|
// inherit docs
|
||
|
minHeight: 50,
|
||
|
|
||
|
// inherit docs
|
||
|
minWidth: 50,
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean} expandOnShow
|
||
|
* True to always expand the window when it is displayed, false to keep it in its current state (which may be
|
||
|
* {@link #collapsed}) when displayed.
|
||
|
*/
|
||
|
expandOnShow: true,
|
||
|
|
||
|
// inherited docs, same default
|
||
|
collapsible: false,
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean} closable
|
||
|
* True to display the 'close' tool button and allow the user to close the window, false to hide the button and
|
||
|
* disallow closing the window.
|
||
|
*
|
||
|
* By default, when close is requested by either clicking the close button in the header or pressing ESC when the
|
||
|
* Window has focus, the {@link #method-close} method will be called. This will _{@link Ext.Component#method-destroy destroy}_ the
|
||
|
* Window and its content meaning that it may not be reused.
|
||
|
*
|
||
|
* To make closing a Window _hide_ the Window so that it may be reused, set {@link #closeAction} to 'hide'.
|
||
|
*/
|
||
|
closable: true,
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean} monitorResize
|
||
|
* `true` to listen to the viewport resize event and perform any layout updating if necessary.
|
||
|
* This is useful if using sizes as percentages for the window.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean} hidden
|
||
|
* Render this Window hidden. If `true`, the {@link #method-hide} method will be called internally.
|
||
|
*/
|
||
|
hidden: true,
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean}
|
||
|
* @inheritdoc
|
||
|
* Windows render to the body on first show.
|
||
|
*/
|
||
|
autoRender: true,
|
||
|
|
||
|
/**
|
||
|
* @cfg {String}
|
||
|
* @inheritdoc
|
||
|
* Windows hide using offsets in order to preserve the scroll positions of their descendants. You may review
|
||
|
* other configuration options here: {@link Ext.Component#hideMode}.
|
||
|
*/
|
||
|
hideMode: 'offsets',
|
||
|
|
||
|
// Windows are always floating.
|
||
|
floating: true,
|
||
|
|
||
|
itemCls: Ext.baseCSSPrefix + 'window-item',
|
||
|
|
||
|
overlapHeader: true,
|
||
|
|
||
|
ignoreHeaderBorderManagement: true,
|
||
|
|
||
|
// Flag to Renderable to always look up the framing styles for this Component
|
||
|
alwaysFramed: true,
|
||
|
|
||
|
// Buffer this so we don't recreate the same object
|
||
|
isRootCfg: {
|
||
|
isRoot: true
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @property {Boolean} isWindow
|
||
|
* `true` in this class to identify an object as an instantiated Window, or subclass thereof.
|
||
|
*/
|
||
|
isWindow: true,
|
||
|
|
||
|
ariaRole: 'dialog',
|
||
|
|
||
|
/**
|
||
|
* @event activate
|
||
|
* Fires after the window has been visually activated via {@link #setActive}.
|
||
|
* @param {Ext.window.Window} this
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @event deactivate
|
||
|
* Fires after the window has been visually deactivated via {@link #setActive}.
|
||
|
* @param {Ext.window.Window} this
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @event resize
|
||
|
* Fires after the window has been resized.
|
||
|
* @param {Ext.window.Window} this
|
||
|
* @param {Number} width The window's new width
|
||
|
* @param {Number} height The window's new height
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @event maximize
|
||
|
* Fires after the window has been maximized.
|
||
|
* @param {Ext.window.Window} this
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @event minimize
|
||
|
* Fires after the window has been minimized.
|
||
|
* @param {Ext.window.Window} this
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @event restore
|
||
|
* Fires after the window has been restored to its original size after being maximized.
|
||
|
* @param {Ext.window.Window} this
|
||
|
*/
|
||
|
|
||
|
// @private
|
||
|
initComponent: function() {
|
||
|
var me = this;
|
||
|
// Explicitly set frame to false, since alwaysFramed is
|
||
|
// true, we only want to lookup framing in a specific instance
|
||
|
me.frame = false;
|
||
|
me.callParent();
|
||
|
|
||
|
if (me.plain) {
|
||
|
me.addClsWithUI('plain');
|
||
|
}
|
||
|
|
||
|
me.addStateEvents(['maximize', 'restore', 'resize', 'dragend']);
|
||
|
},
|
||
|
|
||
|
getElConfig: function () {
|
||
|
var me = this,
|
||
|
elConfig;
|
||
|
|
||
|
elConfig = me.callParent();
|
||
|
elConfig.tabIndex = -1;
|
||
|
return elConfig;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @protected
|
||
|
* Returns the focus holder element associated with this Window.
|
||
|
* By default, this is the Window's element; this can be overridden
|
||
|
* by setting {@link #defaultFocus} property.
|
||
|
*
|
||
|
* @return {Ext.dom.Element/Ext.Component} the focus holding element or Component.
|
||
|
*/
|
||
|
getFocusEl: function() {
|
||
|
var me = this;
|
||
|
|
||
|
// If the legacy FocusManager is enabled, then we must not focus
|
||
|
// the defaultFocus child. We must focus the Window instead, to
|
||
|
// let FocusManager do its thing.
|
||
|
return Ext.enableFocusManager ? me.el : (me.getDefaultFocus() || me.el);
|
||
|
},
|
||
|
|
||
|
// State Management
|
||
|
|
||
|
// @private
|
||
|
getState: function() {
|
||
|
var me = this,
|
||
|
state = me.callParent() || {},
|
||
|
maximized = !!me.maximized,
|
||
|
ghostBox = me.ghostBox,
|
||
|
pos;
|
||
|
|
||
|
|
||
|
state.maximized = maximized;
|
||
|
if (maximized) {
|
||
|
pos = me.restorePos;
|
||
|
} else if (ghostBox) {
|
||
|
// If we're animating a show, it will be from offscreen, so
|
||
|
// grab the position from the final box
|
||
|
pos = [ghostBox.x, ghostBox.y];
|
||
|
} else {
|
||
|
pos = me.getPosition();
|
||
|
}
|
||
|
Ext.apply(state, {
|
||
|
size: maximized ? me.restoreSize : me.getSize(),
|
||
|
pos: pos
|
||
|
});
|
||
|
return state;
|
||
|
},
|
||
|
|
||
|
applyState: function(state){
|
||
|
var me = this;
|
||
|
|
||
|
if (state) {
|
||
|
me.maximized = state.maximized;
|
||
|
if (me.maximized) {
|
||
|
me.hasSavedRestore = true;
|
||
|
me.restoreSize = state.size;
|
||
|
me.restorePos = state.pos;
|
||
|
} else {
|
||
|
Ext.apply(me, {
|
||
|
width: state.size.width,
|
||
|
height: state.size.height,
|
||
|
x: state.pos[0],
|
||
|
y: state.pos[1]
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// @private
|
||
|
onRender: function(ct, position) {
|
||
|
var me = this;
|
||
|
|
||
|
me.callParent(arguments);
|
||
|
|
||
|
// Single clicking a header will focus the defaultFocus child
|
||
|
if (me.header) {
|
||
|
me.header.on({
|
||
|
scope: me,
|
||
|
click: me.onHeaderClick
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// Double clicking a header will toggleMaximize
|
||
|
if (me.maximizable) {
|
||
|
me.header.on({
|
||
|
scope: me,
|
||
|
dblclick: me.toggleMaximize
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// @private
|
||
|
afterRender: function() {
|
||
|
var me = this,
|
||
|
header = me.header,
|
||
|
keyMap;
|
||
|
|
||
|
// Initialize
|
||
|
if (me.maximized) {
|
||
|
me.maximized = false;
|
||
|
me.maximize();
|
||
|
if (header) {
|
||
|
header.removeCls(header.indicateDragCls);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
me.callParent();
|
||
|
|
||
|
if (me.closable) {
|
||
|
keyMap = me.getKeyMap();
|
||
|
keyMap.on(27, me.onEsc, me);
|
||
|
} else {
|
||
|
keyMap = me.keyMap;
|
||
|
}
|
||
|
if (keyMap && me.hidden) {
|
||
|
keyMap.disable();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// @private
|
||
|
onEsc: function(k, e) {
|
||
|
// hide the dependency from Cmd
|
||
|
var mgr = Ext['FocusManager']; // jshint ignore:line
|
||
|
|
||
|
// Only process ESC if the FocusManager is not doing it
|
||
|
if (!Ext.enableFocusManager || mgr.focusedCmp === this) {
|
||
|
e.stopEvent();
|
||
|
this.close();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// @private
|
||
|
beforeDestroy: function() {
|
||
|
var me = this;
|
||
|
if (me.rendered) {
|
||
|
Ext.un('resize', me.onWindowResize, me);
|
||
|
delete me.animateTarget;
|
||
|
me.hide();
|
||
|
Ext.destroy(
|
||
|
me.keyMap
|
||
|
);
|
||
|
}
|
||
|
me.callParent();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @private
|
||
|
* Contribute class-specific tools to the header.
|
||
|
*
|
||
|
* Called by Panel's initTools at initialization time.
|
||
|
*
|
||
|
* Implementations should jst add new tool config objects to `this.tools`
|
||
|
*/
|
||
|
addTools: function() {
|
||
|
var me = this,
|
||
|
tools = [];
|
||
|
|
||
|
// Call Panel's addTools
|
||
|
me.callParent();
|
||
|
|
||
|
if (me.minimizable) {
|
||
|
tools.push({
|
||
|
type: 'minimize',
|
||
|
handler: 'minimize',
|
||
|
scope: me
|
||
|
});
|
||
|
}
|
||
|
if (me.maximizable) {
|
||
|
tools.push({
|
||
|
type: me.maximized ? 'restore' : 'maximize',
|
||
|
handler: 'toggleMaximize',
|
||
|
scope: me
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if (tools.length) {
|
||
|
me.addTool(tools);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
onShow: function() {
|
||
|
var me = this;
|
||
|
|
||
|
me.callParent(arguments);
|
||
|
if (me.expandOnShow) {
|
||
|
me.expand(false);
|
||
|
}
|
||
|
me.syncMonitorWindowResize();
|
||
|
|
||
|
if (me.keyMap) {
|
||
|
me.keyMap.enable();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// @private
|
||
|
doClose: function() {
|
||
|
var me = this;
|
||
|
|
||
|
// Being called as callback after going through the hide call below
|
||
|
if (me.hidden) {
|
||
|
me.fireEvent('close', me);
|
||
|
if (me.closeAction === 'destroy') {
|
||
|
me.destroy();
|
||
|
}
|
||
|
} else {
|
||
|
// close after hiding
|
||
|
me.hide(me.animateTarget, me.doClose, me);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// @private
|
||
|
afterHide: function() {
|
||
|
var me = this;
|
||
|
|
||
|
// No longer subscribe to resizing now that we're hidden
|
||
|
me.syncMonitorWindowResize();
|
||
|
|
||
|
// Turn off keyboard handling once window is hidden
|
||
|
if (me.keyMap) {
|
||
|
me.keyMap.disable();
|
||
|
}
|
||
|
|
||
|
// Perform superclass's afterHide tasks.
|
||
|
me.callParent(arguments);
|
||
|
},
|
||
|
|
||
|
// @private
|
||
|
onWindowResize: function() {
|
||
|
var me = this,
|
||
|
sizeModel;
|
||
|
|
||
|
// This is called on a timer. Window may have been destroyed in the interval.
|
||
|
if (!me.isDestroyed) {
|
||
|
if (me.maximized) {
|
||
|
me.fitContainer();
|
||
|
} else {
|
||
|
sizeModel = me.getSizeModel();
|
||
|
if (sizeModel.width.natural || sizeModel.height.natural) {
|
||
|
me.updateLayout();
|
||
|
}
|
||
|
me.doConstrain();
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Placeholder method for minimizing the window. By default, this method simply fires the {@link #event-minimize} event
|
||
|
* since the behavior of minimizing a window is application-specific. To implement custom minimize behavior, either
|
||
|
* the minimize event can be handled or this method can be overridden.
|
||
|
* @return {Ext.window.Window} this
|
||
|
*/
|
||
|
minimize: function() {
|
||
|
this.fireEvent('minimize', this);
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
resumeHeaderLayout: function(changed) {
|
||
|
this.header.resumeLayouts(changed ? this.isRootCfg : null);
|
||
|
},
|
||
|
|
||
|
afterCollapse: function() {
|
||
|
var me = this,
|
||
|
header = me.header,
|
||
|
tools = me.tools;
|
||
|
|
||
|
if (header && me.maximizable) {
|
||
|
header.suspendLayouts();
|
||
|
tools.maximize.hide();
|
||
|
this.resumeHeaderLayout(true);
|
||
|
}
|
||
|
if (me.resizer) {
|
||
|
me.resizer.disable();
|
||
|
}
|
||
|
me.callParent(arguments);
|
||
|
},
|
||
|
|
||
|
afterExpand: function() {
|
||
|
var me = this,
|
||
|
header = me.header,
|
||
|
tools = me.tools,
|
||
|
changed;
|
||
|
|
||
|
|
||
|
if (header) {
|
||
|
header.suspendLayouts();
|
||
|
if (me.maximizable) {
|
||
|
tools.maximize.show();
|
||
|
changed = true;
|
||
|
}
|
||
|
this.resumeHeaderLayout(changed);
|
||
|
}
|
||
|
if (me.resizer) {
|
||
|
me.resizer.enable();
|
||
|
}
|
||
|
me.callParent(arguments);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Fits the window within its current container and automatically replaces the {@link #maximizable 'maximize' tool
|
||
|
* button} with the 'restore' tool button. Also see {@link #toggleMaximize}.
|
||
|
* @param {Boolean} [animate=false] Pass `true` to animate this Window to full size.
|
||
|
* @return {Ext.window.Window} this
|
||
|
*/
|
||
|
maximize: function(animate) {
|
||
|
var me = this,
|
||
|
header = me.header,
|
||
|
tools = me.tools,
|
||
|
width = me.width,
|
||
|
height = me.height,
|
||
|
restore, changed;
|
||
|
|
||
|
if (!me.maximized) {
|
||
|
me.expand(false);
|
||
|
if (!me.hasSavedRestore) {
|
||
|
restore = me.restoreSize = {
|
||
|
width: width ? width : null,
|
||
|
height: height ? height : null
|
||
|
};
|
||
|
|
||
|
me.restorePos = me.getPosition();
|
||
|
}
|
||
|
|
||
|
// Manipulate visibility of header tools if there is a header
|
||
|
if (header) {
|
||
|
header.suspendLayouts();
|
||
|
if (tools.maximize) {
|
||
|
tools.maximize.setType('restore');
|
||
|
}
|
||
|
if (me.collapseTool) {
|
||
|
me.collapseTool.hide();
|
||
|
changed = true;
|
||
|
}
|
||
|
me.resumeHeaderLayout(changed);
|
||
|
}
|
||
|
|
||
|
me.el.disableShadow();
|
||
|
|
||
|
if (me.dd) {
|
||
|
me.dd.disable();
|
||
|
if (header) {
|
||
|
header.removeCls(header.indicateDragCls);
|
||
|
}
|
||
|
}
|
||
|
if (me.resizer) {
|
||
|
me.resizer.disable();
|
||
|
}
|
||
|
|
||
|
me.el.addCls(Ext.baseCSSPrefix + 'window-maximized');
|
||
|
me.container.addCls(Ext.baseCSSPrefix + 'window-maximized-ct');
|
||
|
|
||
|
me.syncMonitorWindowResize();
|
||
|
me.fitContainer(animate = (animate || !!me.animateTarget) ? {
|
||
|
callback: function() {
|
||
|
me.maximized = true;
|
||
|
me.fireEvent('maximize', me);
|
||
|
}
|
||
|
} : null);
|
||
|
if (!animate) {
|
||
|
me.maximized = true;
|
||
|
me.fireEvent('maximize', me);
|
||
|
}
|
||
|
}
|
||
|
return me;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Restores a {@link #maximizable maximized} window back to its original size and position prior to being maximized
|
||
|
* and also replaces the 'restore' tool button with the 'maximize' tool button. Also see {@link #toggleMaximize}.
|
||
|
* @param {Boolean} [animate=false] Pass `true` to animate the restore.
|
||
|
* @return {Ext.window.Window} this
|
||
|
*/
|
||
|
restore: function(animate) {
|
||
|
var me = this,
|
||
|
tools = me.tools,
|
||
|
header = me.header,
|
||
|
newBox = me.restoreSize,
|
||
|
changed;
|
||
|
|
||
|
if (me.maximized) {
|
||
|
me.hasSavedRestore = null;
|
||
|
me.removeCls(Ext.baseCSSPrefix + 'window-maximized');
|
||
|
|
||
|
// Manipulate visibility of header tools if there is a header
|
||
|
if (header) {
|
||
|
header.suspendLayouts();
|
||
|
if (tools.maximize) {
|
||
|
tools.maximize.setType('maximize');
|
||
|
}
|
||
|
if (me.collapseTool) {
|
||
|
me.collapseTool.show();
|
||
|
changed = true;
|
||
|
}
|
||
|
me.resumeHeaderLayout(changed);
|
||
|
}
|
||
|
|
||
|
// Restore the position/sizing
|
||
|
newBox.x = me.restorePos[0];
|
||
|
newBox.y = me.restorePos[1];
|
||
|
me.setBox(newBox, animate = (animate || !!me.animateTarget) ? {
|
||
|
callback: function() {
|
||
|
me.el.enableShadow(null, true);
|
||
|
me.maximized = false;
|
||
|
me.fireEvent('restore', me);
|
||
|
}
|
||
|
} : null);
|
||
|
|
||
|
// Unset old position/sizing
|
||
|
me.restorePos = me.restoreSize = null;
|
||
|
|
||
|
// Allow users to drag and drop again
|
||
|
if (me.dd) {
|
||
|
me.dd.enable();
|
||
|
if (header) {
|
||
|
header.addCls(header.indicateDragCls);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (me.resizer) {
|
||
|
me.resizer.enable();
|
||
|
}
|
||
|
|
||
|
me.container.removeCls(Ext.baseCSSPrefix + 'window-maximized-ct');
|
||
|
|
||
|
me.syncMonitorWindowResize();
|
||
|
|
||
|
if (!animate) {
|
||
|
me.el.enableShadow(null, true);
|
||
|
me.maximized = false;
|
||
|
me.fireEvent('restore', me);
|
||
|
}
|
||
|
}
|
||
|
return me;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Synchronizes the presence of our listener for window resize events. This method
|
||
|
* should be called whenever this status might change.
|
||
|
* @private
|
||
|
*/
|
||
|
syncMonitorWindowResize: function () {
|
||
|
var me = this,
|
||
|
currentlyMonitoring = me._monitoringResize,
|
||
|
// all the states where we should be listening to window resize:
|
||
|
yes = me.monitorResize || me.constrain || me.constrainHeader || me.maximized,
|
||
|
// all the states where we veto this:
|
||
|
veto = me.hidden || me.destroying || me.isDestroyed;
|
||
|
|
||
|
if (yes && !veto) {
|
||
|
// we should be listening...
|
||
|
if (!currentlyMonitoring) {
|
||
|
// but we aren't, so set it up.
|
||
|
// Delay so that we jump over any Viewport resize activity
|
||
|
Ext.on('resize', me.onWindowResize, me, {buffer: 1});
|
||
|
me._monitoringResize = true;
|
||
|
}
|
||
|
} else if (currentlyMonitoring) {
|
||
|
// we should not be listening, but we are, so tear it down
|
||
|
Ext.un('resize', me.onWindowResize, me);
|
||
|
me._monitoringResize = false;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* A shortcut method for toggling between {@link #method-maximize} and {@link #method-restore} based on the current maximized
|
||
|
* state of the window.
|
||
|
* @return {Ext.window.Window} this
|
||
|
*/
|
||
|
toggleMaximize: function() {
|
||
|
return this[this.maximized ? 'restore': 'maximize']();
|
||
|
},
|
||
|
|
||
|
createGhost: function() {
|
||
|
var ghost = this.callParent(arguments);
|
||
|
ghost.xtype = 'window';
|
||
|
return ghost;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Gets the configured default focus item. If a {@link #defaultFocus} is set, it will
|
||
|
* receive focus when the Window's `focus` method is called, otherwise the
|
||
|
* Window itself will receive focus.
|
||
|
*/
|
||
|
getDefaultFocus: function() {
|
||
|
var me = this,
|
||
|
result,
|
||
|
defaultComp = me.defaultButton || me.defaultFocus,
|
||
|
selector;
|
||
|
|
||
|
if (defaultComp !== undefined) {
|
||
|
// Number is index of Button
|
||
|
if (Ext.isNumber(defaultComp)) {
|
||
|
result = me.query('button')[defaultComp];
|
||
|
}
|
||
|
// String is ID or CQ selector
|
||
|
else if (Ext.isString(defaultComp)) {
|
||
|
selector = defaultComp;
|
||
|
|
||
|
// Try id/itemId match if selector begins with alphanumeric
|
||
|
// and is not compound xtype/id selector with # in the middle
|
||
|
// (https://sencha.jira.com/browse/EXTJS-14925)
|
||
|
if (Ext.validIdRe.test(selector)) {
|
||
|
result = me.down(Ext.makeIdSelector(selector));
|
||
|
}
|
||
|
// If not found, use as selector
|
||
|
if (!result) {
|
||
|
result = me.down(selector);
|
||
|
}
|
||
|
}
|
||
|
// Otherwise, if it's got a focus method, use it
|
||
|
else if (defaultComp.focus) {
|
||
|
result = defaultComp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
},
|
||
|
|
||
|
privates: {
|
||
|
// Override. Windows are always simple draggable, they do not use Ext.Panel.DDs
|
||
|
// The dd property in a Window is always a ComponentDragger
|
||
|
initDraggable: function() {
|
||
|
/**
|
||
|
* @property {Ext.util.ComponentDragger} dd
|
||
|
* If this Window is configured {@link #cfg-draggable}, this property will contain an instance of
|
||
|
* {@link Ext.util.ComponentDragger} (A subclass of {@link Ext.dd.DragTracker DragTracker}) which handles dragging
|
||
|
* the Window's DOM Element, and constraining according to the {@link #constrain} and {@link #constrainHeader} .
|
||
|
*
|
||
|
* This has implementations of `onBeforeStart`, `onDrag` and `onEnd` which perform the dragging action. If
|
||
|
* extra logic is needed at these points, use {@link Ext.Function#createInterceptor createInterceptor} or
|
||
|
* {@link Ext.Function#createSequence createSequence} to augment the existing implementations.
|
||
|
*/
|
||
|
this.initSimpleDraggable();
|
||
|
},
|
||
|
|
||
|
onHeaderClick: function(header, e) {
|
||
|
var delegate;
|
||
|
|
||
|
if (header.el.contains(e.getTarget())) {
|
||
|
delegate = this.getDefaultFocus();
|
||
|
|
||
|
if (delegate) {
|
||
|
delegate.focus();
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
initResizable: function(){
|
||
|
this.callParent(arguments);
|
||
|
if (this.maximized) {
|
||
|
this.resizer.disable();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|