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 {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. So 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.el.getStyle('zIndex') - 4);
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.el.getStyle('zIndex') - 4);
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(zIndex) {
156 this.mask = this.targetEl.createChild({
157 cls: Ext.baseCSSPrefix + 'mask'
159 this.mask.setVisibilityMode(Ext.core.Element.DISPLAY);
160 this.mask.on('click', this._onMaskClick, this);
162 Ext.getBody().addCls(Ext.baseCSSPrefix + 'body-masked');
163 this.mask.setSize(this.targetEl.getViewSize(true));
164 this.mask.setStyle('zIndex', zIndex);
168 _hideModalMask: function() {
170 Ext.getBody().removeCls(Ext.baseCSSPrefix + 'body-masked');
175 _onMaskClick: function() {
181 _onContainerResize: function() {
182 if (this.mask && this.mask.isVisible()) {
183 this.mask.setSize(this.targetEl.getViewSize(true));
188 * <p>Registers a floating {@link Ext.Component} with this ZIndexManager. This should not
189 * need to be called under normal circumstances. Floating Components (such as Windows, BoundLists and Menus) are automatically registered
190 * with a {@link Ext.Component#zIndexManager zIndexManager} at render time.</p>
191 * <p>Where this may be useful is moving Windows between two ZIndexManagers. For example,
192 * to bring the Ext.MessageBox dialog under the same manager as the Desktop's
193 * ZIndexManager in the desktop sample app:</p><code><pre>
194 MyDesktop.getDesktop().getManager().register(Ext.MessageBox);
196 * @param {Component} comp The Component to register.
198 register : function(comp) {
199 if (comp.zIndexManager) {
200 comp.zIndexManager.unregister(comp);
202 comp.zIndexManager = this;
204 this.list[comp.id] = comp;
205 this.zIndexStack.push(comp);
206 comp.on('hide', this._activateLast, this);
210 * <p>Unregisters a {@link Ext.Component} from this ZIndexManager. This should not
211 * need to be called. Components are automatically unregistered upon destruction.
212 * See {@link #register}.</p>
213 * @param {Component} comp The Component to unregister.
215 unregister : function(comp) {
216 delete comp.zIndexManager;
217 if (this.list && this.list[comp.id]) {
218 delete this.list[comp.id];
219 comp.un('hide', this._activateLast);
220 Ext.Array.remove(this.zIndexStack, comp);
222 // Destruction requires that the topmost visible floater be activated. Same as hiding.
223 this._activateLast(comp);
228 * Gets a registered Component by id.
229 * @param {String/Object} id The id of the Component or a {@link Ext.Component} instance
230 * @return {Ext.Component}
233 return typeof id == "object" ? id : this.list[id];
237 * Brings the specified Component to the front of any other active Components in this ZIndexManager.
238 * @param {String/Object} comp The id of the Component or a {@link Ext.Component} instance
239 * @return {Boolean} True if the dialog was brought to the front, else false
240 * if it was already in front
242 bringToFront : function(comp) {
243 comp = this.get(comp);
244 if (comp != this.front) {
245 Ext.Array.remove(this.zIndexStack, comp);
246 this.zIndexStack.push(comp);
247 this.assignZIndices();
251 Ext.getBody().addCls(Ext.baseCSSPrefix + 'body-masked');
252 this.mask.setSize(Ext.core.Element.getViewWidth(true), Ext.core.Element.getViewHeight(true));
259 * Sends the specified Component to the back of other active Components in this ZIndexManager.
260 * @param {String/Object} comp The id of the Component or a {@link Ext.Component} instance
261 * @return {Ext.Component} The Component
263 sendToBack : function(comp) {
264 comp = this.get(comp);
265 Ext.Array.remove(this.zIndexStack, comp);
266 this.zIndexStack.unshift(comp);
267 this.assignZIndices();
272 * Hides all Components managed by this ZIndexManager.
274 hideAll : function() {
275 for (var id in this.list) {
276 if (this.list[id].isComponent && this.list[id].isVisible()) {
277 this.list[id].hide();
284 * Temporarily hides all currently visible managed Components. This is for when
285 * dragging a Window which may manage a set of floating descendants in its ZIndexManager;
286 * they should all be hidden just for the duration of the drag.
290 ln = this.zIndexStack.length,
293 this.tempHidden = [];
294 for (; i < ln; i++) {
295 comp = this.zIndexStack[i];
296 if (comp.isVisible()) {
297 this.tempHidden.push(comp);
305 * Restores temporarily hidden managed Components to visibility.
309 ln = this.tempHidden.length,
314 for (; i < ln; i++) {
315 comp = this.tempHidden[i];
319 comp.setPosition(x, y);
321 delete this.tempHidden;
325 * Gets the currently-active Component in this ZIndexManager.
326 * @return {Ext.Component} The active Component
328 getActive : function() {
333 * Returns zero or more Components in this ZIndexManager using the custom search function passed to this method.
334 * The function should accept a single {@link Ext.Component} reference as its only argument and should
335 * return true if the Component matches the search criteria, otherwise it should return false.
336 * @param {Function} fn The search function
337 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the Component being tested.
338 * that gets passed to the function if not specified)
339 * @return {Array} An array of zero or more matching windows
341 getBy : function(fn, scope) {
344 len = this.zIndexStack.length,
347 for (; i < len; i++) {
348 comp = this.zIndexStack[i];
349 if (fn.call(scope||comp, comp) !== false) {
357 * Executes the specified function once for every Component in this ZIndexManager, passing each
358 * Component as the only parameter. Returning false from the function will stop the iteration.
359 * @param {Function} fn The function to execute for each item
360 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Component in the iteration.
362 each : function(fn, scope) {
364 for (var id in this.list) {
365 comp = this.list[id];
366 if (comp.isComponent && fn.call(scope || comp, comp) === false) {
373 * Executes the specified function once for every Component in this ZIndexManager, passing each
374 * Component as the only parameter. Returning false from the function will stop the iteration.
375 * The components are passed to the function starting at the bottom and proceeding to the top.
376 * @param {Function} fn The function to execute for each item
377 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function
378 * is executed. Defaults to the current Component in the iteration.
380 eachBottomUp: function (fn, scope) {
382 stack = this.zIndexStack,
385 for (i = 0, n = stack.length ; i < n; i++) {
387 if (comp.isComponent && fn.call(scope || comp, comp) === false) {
394 * Executes the specified function once for every Component in this ZIndexManager, passing each
395 * Component as the only parameter. Returning false from the function will stop the iteration.
396 * The components are passed to the function starting at the top and proceeding to the bottom.
397 * @param {Function} fn The function to execute for each item
398 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function
399 * is executed. Defaults to the current Component in the iteration.
401 eachTopDown: function (fn, scope) {
403 stack = this.zIndexStack,
406 for (i = stack.length ; i-- > 0; ) {
408 if (comp.isComponent && fn.call(scope || comp, comp) === false) {
414 destroy: function() {
415 delete this.zIndexStack;
417 delete this.container;
418 delete this.targetEl;
422 * @class Ext.WindowManager
423 * @extends Ext.ZIndexManager
424 * <p>The default global floating Component group that is available automatically.</p>
425 * <p>This manages instances of floating Components which were rendered programatically without
426 * being added to a {@link Ext.container.Container Container}, and for floating Components which were added into non-floating Containers.</p>
427 * <p><i>Floating</i> Containers create their own instance of ZIndexManager, and floating Components added at any depth below
428 * there are managed by that ZIndexManager.</p>
431 Ext.WindowManager = Ext.WindowMgr = new this();