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.ZIndexManager
17 * <p>A class that manages a group of {@link Ext.Component#floating} Components and provides z-order management,
18 * and Component activation behavior, including masking below the active (topmost) Component.</p>
19 * <p>{@link Ext.Component#floating Floating} Components which are rendered directly into the document (such as {@link Ext.window.Window Window}s) which are
20 * {@link Ext.Component#show show}n are managed by a {@link Ext.WindowManager global instance}.</p>
21 * <p>{@link Ext.Component#floating Floating} Components which are descendants of {@link Ext.Component#floating floating} <i>Containers</i>
22 * (for example a {@link Ext.view.BoundList BoundList} within an {@link Ext.window.Window Window}, or a {@link Ext.menu.Menu Menu}),
23 * are managed by a ZIndexManager owned by that floating Container. Therefore ComboBox dropdowns within Windows will have managed z-indices
24 * guaranteed to be correct, relative to the Window.</p>
26 Ext.define('Ext.ZIndexManager', {
28 alternateClassName: 'Ext.WindowGroup',
34 constructor: function(container) {
43 // This is the ZIndexManager for an Ext.container.Container, base its zseed on the zIndex of the Container's element
44 if (container.isContainer) {
45 container.on('resize', me._onContainerResize, me);
46 me.zseed = Ext.Number.from(container.getEl().getStyle('zIndex'), me.getNextZSeed());
47 // The containing element we will be dealing with (eg masking) is the content target
48 me.targetEl = container.getTargetEl();
49 me.container = container;
51 // This is the ZIndexManager for a DOM element
53 Ext.EventManager.onWindowResize(me._onContainerResize, me);
54 me.zseed = me.getNextZSeed();
55 me.targetEl = Ext.get(container);
58 // No container passed means we are the global WindowManager. Our target is the doc body.
59 // DOM must be ready to collect that ref.
61 Ext.EventManager.onWindowResize(me._onContainerResize, me);
62 me.zseed = me.getNextZSeed();
63 Ext.onDocumentReady(function() {
64 me.targetEl = Ext.getBody();
69 getNextZSeed: function() {
70 return (Ext.ZIndexManager.zBase += 10000);
73 setBase: function(baseZIndex) {
74 this.zseed = baseZIndex;
75 return this.assignZIndices();
79 assignZIndices: function() {
80 var a = this.zIndexStack,
86 for (; i < len; i++) {
88 if (comp && !comp.hidden) {
90 // Setting the zIndex of a Component returns the topmost zIndex consumed by
92 // If it's just a plain floating Component such as a BoundList, then the
93 // return value is the passed value plus 10, ready for the next item.
94 // If a floating *Container* has its zIndex set, it re-orders its managed
95 // floating children, starting from that new base, and returns a value 10000 above
96 // the highest zIndex which it allocates.
97 zIndex = comp.setZIndex(zIndex);
100 this._activateLast();
105 _setActiveChild: function(comp) {
106 if (comp !== this.front) {
109 this.front.setActive(false, comp);
113 comp.setActive(true);
115 this._showModalMask(comp);
122 _activateLast: function(justHidden) {
124 lastActivated = false,
127 // Go down through the z-index stack.
128 // Activate the next visible one down.
129 // Keep going down to find the next visible modal one to shift the modal mask down under
130 for (i = this.zIndexStack.length-1; i >= 0; --i) {
131 comp = this.zIndexStack[i];
133 if (!lastActivated) {
134 this._setActiveChild(comp);
135 lastActivated = true;
138 // Move any modal mask down to just under the next modal floater down the stack
140 this._showModalMask(comp);
146 // none to activate, so there must be no modal mask.
147 // And clear the currently active property
148 this._hideModalMask();
149 if (!lastActivated) {
150 this._setActiveChild(null);
154 _showModalMask: function(comp) {
155 var zIndex = comp.el.getStyle('zIndex') - 4,
156 maskTarget = comp.floatParent ? comp.floatParent.getTargetEl() : Ext.get(comp.getEl().dom.parentNode),
161 Ext.global.console && Ext.global.console.warn && Ext.global.console.warn('mask target could not be found. Mask cannot be shown');
166 parentBox = maskTarget.getBox();
169 this.mask = Ext.getBody().createChild({
170 cls: Ext.baseCSSPrefix + 'mask'
172 this.mask.setVisibilityMode(Ext.Element.DISPLAY);
173 this.mask.on('click', this._onMaskClick, this);
175 if (maskTarget.dom === document.body) {
176 parentBox.height = Ext.Element.getViewHeight();
178 maskTarget.addCls(Ext.baseCSSPrefix + 'body-masked');
179 this.mask.setBox(parentBox);
180 this.mask.setStyle('zIndex', zIndex);
184 _hideModalMask: function() {
185 if (this.mask && this.mask.dom.parentNode) {
186 Ext.get(this.mask.dom.parentNode).removeCls(Ext.baseCSSPrefix + 'body-masked');
191 _onMaskClick: function() {
197 _onContainerResize: function() {
198 if (this.mask && this.mask.isVisible()) {
199 this.mask.setSize(Ext.get(this.mask.dom.parentNode).getViewSize(true));
204 * <p>Registers a floating {@link Ext.Component} with this ZIndexManager. This should not
205 * need to be called under normal circumstances. Floating Components (such as Windows, BoundLists and Menus) are automatically registered
206 * with a {@link Ext.Component#zIndexManager zIndexManager} at render time.</p>
207 * <p>Where this may be useful is moving Windows between two ZIndexManagers. For example,
208 * to bring the Ext.MessageBox dialog under the same manager as the Desktop's
209 * ZIndexManager in the desktop sample app:</p><code><pre>
210 MyDesktop.getDesktop().getManager().register(Ext.MessageBox);
212 * @param {Ext.Component} comp The Component to register.
214 register : function(comp) {
215 if (comp.zIndexManager) {
216 comp.zIndexManager.unregister(comp);
218 comp.zIndexManager = this;
220 this.list[comp.id] = comp;
221 this.zIndexStack.push(comp);
222 comp.on('hide', this._activateLast, this);
226 * <p>Unregisters a {@link Ext.Component} from this ZIndexManager. This should not
227 * need to be called. Components are automatically unregistered upon destruction.
228 * See {@link #register}.</p>
229 * @param {Ext.Component} comp The Component to unregister.
231 unregister : function(comp) {
232 delete comp.zIndexManager;
233 if (this.list && this.list[comp.id]) {
234 delete this.list[comp.id];
235 comp.un('hide', this._activateLast);
236 Ext.Array.remove(this.zIndexStack, comp);
238 // Destruction requires that the topmost visible floater be activated. Same as hiding.
239 this._activateLast(comp);
244 * Gets a registered Component by id.
245 * @param {String/Object} id The id of the Component or a {@link Ext.Component} instance
246 * @return {Ext.Component}
249 return typeof id == "object" ? id : this.list[id];
253 * Brings the specified Component to the front of any other active Components in this ZIndexManager.
254 * @param {String/Object} comp The id of the Component or a {@link Ext.Component} instance
255 * @return {Boolean} True if the dialog was brought to the front, else false
256 * if it was already in front
258 bringToFront : function(comp) {
259 comp = this.get(comp);
260 if (comp !== this.front) {
261 Ext.Array.remove(this.zIndexStack, comp);
262 this.zIndexStack.push(comp);
263 this.assignZIndices();
267 this._showModalMask(comp);
273 * Sends the specified Component to the back of other active Components in this ZIndexManager.
274 * @param {String/Object} comp The id of the Component or a {@link Ext.Component} instance
275 * @return {Ext.Component} The Component
277 sendToBack : function(comp) {
278 comp = this.get(comp);
279 Ext.Array.remove(this.zIndexStack, comp);
280 this.zIndexStack.unshift(comp);
281 this.assignZIndices();
286 * Hides all Components managed by this ZIndexManager.
288 hideAll : function() {
289 for (var id in this.list) {
290 if (this.list[id].isComponent && this.list[id].isVisible()) {
291 this.list[id].hide();
298 * Temporarily hides all currently visible managed Components. This is for when
299 * dragging a Window which may manage a set of floating descendants in its ZIndexManager;
300 * they should all be hidden just for the duration of the drag.
304 ln = this.zIndexStack.length,
307 this.tempHidden = [];
308 for (; i < ln; i++) {
309 comp = this.zIndexStack[i];
310 if (comp.isVisible()) {
311 this.tempHidden.push(comp);
319 * Restores temporarily hidden managed Components to visibility.
323 ln = this.tempHidden.length,
328 for (; i < ln; i++) {
329 comp = this.tempHidden[i];
333 comp.setPosition(x, y);
335 delete this.tempHidden;
339 * Gets the currently-active Component in this ZIndexManager.
340 * @return {Ext.Component} The active Component
342 getActive : function() {
347 * Returns zero or more Components in this ZIndexManager using the custom search function passed to this method.
348 * The function should accept a single {@link Ext.Component} reference as its only argument and should
349 * return true if the Component matches the search criteria, otherwise it should return false.
350 * @param {Function} fn The search function
351 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the Component being tested.
352 * that gets passed to the function if not specified)
353 * @return {Array} An array of zero or more matching windows
355 getBy : function(fn, scope) {
358 len = this.zIndexStack.length,
361 for (; i < len; i++) {
362 comp = this.zIndexStack[i];
363 if (fn.call(scope||comp, comp) !== false) {
371 * Executes the specified function once for every Component in this ZIndexManager, passing each
372 * Component as the only parameter. Returning false from the function will stop the iteration.
373 * @param {Function} fn The function to execute for each item
374 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Component in the iteration.
376 each : function(fn, scope) {
378 for (var id in this.list) {
379 comp = this.list[id];
380 if (comp.isComponent && fn.call(scope || comp, comp) === false) {
387 * Executes the specified function once for every Component in this ZIndexManager, passing each
388 * Component as the only parameter. Returning false from the function will stop the iteration.
389 * The components are passed to the function starting at the bottom and proceeding to the top.
390 * @param {Function} fn The function to execute for each item
391 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function
392 * is executed. Defaults to the current Component in the iteration.
394 eachBottomUp: function (fn, scope) {
396 stack = this.zIndexStack,
399 for (i = 0, n = stack.length ; i < n; i++) {
401 if (comp.isComponent && fn.call(scope || comp, comp) === false) {
408 * Executes the specified function once for every Component in this ZIndexManager, passing each
409 * Component as the only parameter. Returning false from the function will stop the iteration.
410 * The components are passed to the function starting at the top and proceeding to the bottom.
411 * @param {Function} fn The function to execute for each item
412 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function
413 * is executed. Defaults to the current Component in the iteration.
415 eachTopDown: function (fn, scope) {
417 stack = this.zIndexStack,
420 for (i = stack.length ; i-- > 0; ) {
422 if (comp.isComponent && fn.call(scope || comp, comp) === false) {
428 destroy: function() {
429 this.each(function(c) {
432 delete this.zIndexStack;
434 delete this.container;
435 delete this.targetEl;
439 * @class Ext.WindowManager
440 * @extends Ext.ZIndexManager
441 * <p>The default global floating Component group that is available automatically.</p>
442 * <p>This manages instances of floating Components which were rendered programatically without
443 * being added to a {@link Ext.container.Container Container}, and for floating Components which were added into non-floating Containers.</p>
444 * <p><i>Floating</i> Containers create their own instance of ZIndexManager, and floating Components added at any depth below
445 * there are managed by that ZIndexManager.</p>
448 Ext.WindowManager = Ext.WindowMgr = new this();