/** * @class Ext.ZIndexManager *

A class that manages a group of {@link Ext.Component#floating} Components and provides z-order management, * and Component activation behavior, including masking below the active (topmost) Component.

*

{@link Ext.Component#floating Floating} Components which are rendered directly into the document (Such as {@link Ext.window.Window Window}s which are * {@link Ext.Component#show show}n are managed by a {@link Ext.WindowMgr global instance}.

*

{@link Ext.Component#floating Floating} Components which are descendants of {@link Ext.Component#floating floating} Containers * (For example a {Ext.view.BoundList BoundList} within an {@link Ext.window.Window Window}, or a {@link Ext.menu.Menu Menu}), * are managed by a ZIndexManager owned by that floating Container. So ComboBox dropdowns within Windows will have managed z-indices * guaranteed to be correct, relative to the Window.

* @constructor */ Ext.define('Ext.ZIndexManager', { alternateClassName: 'Ext.WindowGroup', statics: { zBase : 9000 }, constructor: function(container) { var me = this; me.list = {}; me.accessList = []; me.front = null; if (container) { // This is the ZIndexManager for an Ext.container.Container, base its zseed on the zIndex of the Container's element if (container.isContainer) { container.on('resize', me._onContainerResize, me); me.zseed = Ext.num(container.getEl().getStyle('zIndex'), me.getNextZSeed()); // The containing element we will be dealing with (eg masking) is the content target me.targetEl = container.getTargetEl(); me.container = container; } // This is the ZIndexManager for a DOM element else { Ext.EventManager.onWindowResize(me._onContainerResize, me); me.zseed = me.getNextZSeed(); me.targetEl = Ext.get(container); } } // No container passed means we are the global WindowMgr. Our target is the doc body. // DOM must be ready to collect that ref. else { me.zseed = me.getNextZSeed(); Ext.onDocumentReady(function() { me.targetEl = Ext.getBody(); }); } }, getNextZSeed: function() { return (Ext.ZIndexManager.zBase += 10000); }, setBase: function(baseZIndex) { this.zseed = baseZIndex; return this._orderFloaters(); }, // private _sortFloaters: function(d1, d2) { return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1; }, // private _orderFloaters: function() { var a = this.accessList, len = a.length, i = 0, zIndex = this.zseed, comp; if (len > 0) { a.sort(this._sortFloaters); for (; i < len; i++) { comp = a[i]; if (comp && !comp.hidden) { // Setting the zIndex of a Component returns the topmost zIndex consumed by // that Component. // If it's just a plain floating Component such as a BoundList, then the // return value is the passed value plus 10, ready for the next item. // If a floating *Container* has its zIndex set, it re-orders its managed // floating children, starting from that new base, and returns a value 10000 above // the highest zIndex which it allocates. zIndex = comp.setZIndex(zIndex); } } } this._activateLast(); return zIndex; }, // private _setActiveChild: function(comp) { if (comp != this.front) { if (this.front) { this.front.setActive(false); } this.front = comp; if (comp) { comp.setActive(true); if (comp.modal) { this._showModalMask(comp.el.getStyle('zIndex') - 4); } else { this._hideModalMask(); } } } }, // private _activateLast: function(justHidden) { for (var i = this.accessList.length-1; i >=0; --i) { if (!this.accessList[i].hidden) { this._setActiveChild(this.accessList[i]); return; } } // none to activate this._setActiveChild(null); this._hideModalMask(); }, _showModalMask: function(zIndex) { if (!this.mask) { this.mask = this.targetEl.createChild({ cls: Ext.baseCSSPrefix + 'mask' }); this.mask.setVisibilityMode(Ext.core.Element.DISPLAY); this.mask.on('click', this._onMaskClick, this); } Ext.getBody().addCls(Ext.baseCSSPrefix + 'body-masked'); this.mask.setSize(this.targetEl.getViewSize(true)); this.mask.setStyle('zIndex', zIndex); this.mask.show(); }, _hideModalMask: function() { if (this.mask) { Ext.getBody().removeCls(Ext.baseCSSPrefix + 'body-masked'); this.mask.hide(); } }, _onMaskClick: function() { if (this.front) { this.front.focus(); } }, _onContainerResize: function() { if (this.mask && this.mask.isVisible()) { this.mask.setSize(this.targetEl.getViewSize(true)); } },
/** *

Registers a floating {@link Ext.Component} with this ZIndexManager. This should not * need to be called under normal circumstances. Floating Components (such as Windows, BoundLists and Menus) are automatically registered * with a {@link Ext.Component#zIndexManager zIndexManager} at render time.

*

Where this may be useful is moving Windows between two ZIndexManagers. For example, * to bring the Ext.MessageBox dialog under the same manager as the Desktop's * ZIndexManager in the desktop sample app:

MyDesktop.getDesktop().getManager().register(Ext.MessageBox);
* @param {Component} comp The Component to register. */ register : function(comp) { if (comp.zIndexManager) { comp.zIndexManager.unregister(comp); } comp.zIndexManager = this; this.list[comp.id] = comp; this.accessList.push(comp); comp.on('hide', this._activateLast, this); },
/** *

Unregisters a {@link Ext.Component} from this ZIndexManager. This should not * need to be called. Components are automatically unregistered upon destruction. * See {@link #register}.

* @param {Component} comp The Component to unregister. */ unregister : function(comp) { delete comp.zIndexManager; delete this.list[comp.id]; comp.un('hide', this._activateLast); Ext.Array.remove(this.accessList, comp); },
/** * Gets a registered Component by id. * @param {String/Object} id The id of the Component or a {@link Ext.Component} instance * @return {Ext.Component} */ get : function(id) { return typeof id == "object" ? id : this.list[id]; },
/** * Brings the specified Component to the front of any other active Components in this ZIndexManager. * @param {String/Object} comp The id of the Component or a {@link Ext.Component} instance * @return {Boolean} True if the dialog was brought to the front, else false * if it was already in front */ bringToFront : function(comp) { comp = this.get(comp); if (comp != this.front) { comp._lastAccess = new Date().getTime(); this._orderFloaters(); return true; } if (comp.modal) { Ext.getBody().addCls(Ext.baseCSSPrefix + 'body-masked'); this.mask.setSize(Ext.core.Element.getViewWidth(true), Ext.core.Element.getViewHeight(true)); this.mask.show(); } return false; },
/** * Sends the specified Component to the back of other active Components in this ZIndexManager. * @param {String/Object} comp The id of the Component or a {@link Ext.Component} instance * @return {Ext.Component} The Component */ sendToBack : function(comp) { comp = this.get(comp); comp._lastAccess = -(new Date().getTime()); this._orderFloaters(); return comp; },
/** * Hides all Components managed by this ZIndexManager. */ hideAll : function() { for (var id in this.list) { if (this.list[id].isComponent && this.list[id].isVisible()) { this.list[id].hide(); } } }, /** * @private * Temporarily hides all currently visible managed Components. This is for when * dragging a Window which may manage a set of floating descendants in its ZIndexManager; * they should all be hidden just for the duration of the drag. */ hide: function() { var i = 0, ln = this.accessList.length, comp; this.tempHidden = []; for (; i < ln; i++) { comp = this.accessList[i]; if (comp.isVisible()) { this.tempHidden.push(comp); comp.hide(); } } }, /** * @private * Restores temporarily hidden managed Components to visibility. */ show: function() { var i = 0, ln = this.tempHidden.length, comp, x, y; for (; i < ln; i++) { comp = this.tempHidden[i]; x = comp.x; y = comp.y; comp.show(); comp.setPosition(x, y); } delete this.tempHidden; },
/** * Gets the currently-active Component in this ZIndexManager. * @return {Ext.Component} The active Component */ getActive : function() { return this.front; },
/** * Returns zero or more Components in this ZIndexManager using the custom search function passed to this method. * The function should accept a single {@link Ext.Component} reference as its only argument and should * return true if the Component matches the search criteria, otherwise it should return false. * @param {Function} fn The search function * @param {Object} scope (optional) The scope (this reference) in which the function is executed. Defaults to the Component being tested. * that gets passed to the function if not specified) * @return {Array} An array of zero or more matching windows */ getBy : function(fn, scope) { var r = [], i = this.accessList.length-1, comp; for(; i >=0; --i) { comp = this.accessList[i]; if (fn.call(scope||comp, comp) !== false) { r.push(comp); } } return r; },
/** * Executes the specified function once for every Component in this ZIndexManager, passing each * Component as the only parameter. Returning false from the function will stop the iteration. * @param {Function} fn The function to execute for each item * @param {Object} scope (optional) The scope (this reference) in which the function is executed. Defaults to the current Component in the iteration. */ each : function(fn, scope) { var comp; for (var id in this.list) { comp = this.list[id]; if (comp.isComponent && fn.call(scope || comp, comp) === false) { return; } } }, destroy: function() { delete this.accessList; delete this.list; delete this.container; delete this.targetEl; } }, function() {
/** * @class Ext.WindowMgr * @extends Ext.ZIndexManager *

The default global floating Component group that is available automatically.

*

This manages instances of floating Components which were rendered programatically without * being added to a {@link Ext.Container Container}, and for floating Components which were added into non-floating Containers.

*

Floating Containers create their own instance of ZIndexManager, and floating Components added at any depth below * there are managed by that ZIndexManager.

* @singleton */ Ext.WindowMgr = new this(); });