Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / ZIndexManager.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-ZIndexManager'>/**
19 </span> * @class Ext.ZIndexManager
20  * &lt;p&gt;A class that manages a group of {@link Ext.Component#floating} Components and provides z-order management,
21  * and Component activation behavior, including masking below the active (topmost) Component.&lt;/p&gt;
22  * &lt;p&gt;{@link Ext.Component#floating Floating} Components which are rendered directly into the document (such as {@link Ext.window.Window Window}s) which are
23  * {@link Ext.Component#show show}n are managed by a {@link Ext.WindowManager global instance}.&lt;/p&gt;
24  * &lt;p&gt;{@link Ext.Component#floating Floating} Components which are descendants of {@link Ext.Component#floating floating} &lt;i&gt;Containers&lt;/i&gt;
25  * (for example a {@link Ext.view.BoundList BoundList} within an {@link Ext.window.Window Window}, or a {@link Ext.menu.Menu Menu}),
26  * are managed by a ZIndexManager owned by that floating Container. Therefore ComboBox dropdowns within Windows will have managed z-indices
27  * guaranteed to be correct, relative to the Window.&lt;/p&gt;
28  */
29 Ext.define('Ext.ZIndexManager', {
30
31     alternateClassName: 'Ext.WindowGroup',
32
33     statics: {
34         zBase : 9000
35     },
36
37     constructor: function(container) {
38         var me = this;
39
40         me.list = {};
41         me.zIndexStack = [];
42         me.front = null;
43
44         if (container) {
45
46             // This is the ZIndexManager for an Ext.container.Container, base its zseed on the zIndex of the Container's element
47             if (container.isContainer) {
48                 container.on('resize', me._onContainerResize, me);
49                 me.zseed = Ext.Number.from(container.getEl().getStyle('zIndex'), me.getNextZSeed());
50                 // The containing element we will be dealing with (eg masking) is the content target
51                 me.targetEl = container.getTargetEl();
52                 me.container = container;
53             }
54             // This is the ZIndexManager for a DOM element
55             else {
56                 Ext.EventManager.onWindowResize(me._onContainerResize, me);
57                 me.zseed = me.getNextZSeed();
58                 me.targetEl = Ext.get(container);
59             }
60         }
61         // No container passed means we are the global WindowManager. Our target is the doc body.
62         // DOM must be ready to collect that ref.
63         else {
64             Ext.EventManager.onWindowResize(me._onContainerResize, me);
65             me.zseed = me.getNextZSeed();
66             Ext.onDocumentReady(function() {
67                 me.targetEl = Ext.getBody();
68             });
69         }
70     },
71
72     getNextZSeed: function() {
73         return (Ext.ZIndexManager.zBase += 10000);
74     },
75
76     setBase: function(baseZIndex) {
77         this.zseed = baseZIndex;
78         return this.assignZIndices();
79     },
80
81     // private
82     assignZIndices: function() {
83         var a = this.zIndexStack,
84             len = a.length,
85             i = 0,
86             zIndex = this.zseed,
87             comp;
88
89         for (; i &lt; len; i++) {
90             comp = a[i];
91             if (comp &amp;&amp; !comp.hidden) {
92
93                 // Setting the zIndex of a Component returns the topmost zIndex consumed by
94                 // that Component.
95                 // If it's just a plain floating Component such as a BoundList, then the
96                 // return value is the passed value plus 10, ready for the next item.
97                 // If a floating *Container* has its zIndex set, it re-orders its managed
98                 // floating children, starting from that new base, and returns a value 10000 above
99                 // the highest zIndex which it allocates.
100                 zIndex = comp.setZIndex(zIndex);
101             }
102         }
103         this._activateLast();
104         return zIndex;
105     },
106
107     // private
108     _setActiveChild: function(comp) {
109         if (comp !== this.front) {
110
111             if (this.front) {
112                 this.front.setActive(false, comp);
113             }
114             this.front = comp;
115             if (comp) {
116                 comp.setActive(true);
117                 if (comp.modal) {
118                     this._showModalMask(comp);
119                 }
120             }
121         }
122     },
123
124     // private
125     _activateLast: function(justHidden) {
126         var comp,
127             lastActivated = false,
128             i;
129
130         // Go down through the z-index stack.
131         // Activate the next visible one down.
132         // Keep going down to find the next visible modal one to shift the modal mask down under
133         for (i = this.zIndexStack.length-1; i &gt;= 0; --i) {
134             comp = this.zIndexStack[i];
135             if (!comp.hidden) {
136                 if (!lastActivated) {
137                     this._setActiveChild(comp);
138                     lastActivated = true;
139                 }
140
141                 // Move any modal mask down to just under the next modal floater down the stack
142                 if (comp.modal) {
143                     this._showModalMask(comp);
144                     return;
145                 }
146             }
147         }
148
149         // none to activate, so there must be no modal mask.
150         // And clear the currently active property
151         this._hideModalMask();
152         if (!lastActivated) {
153             this._setActiveChild(null);
154         }
155     },
156
157     _showModalMask: function(comp) {
158         var zIndex = comp.el.getStyle('zIndex') - 4,
159             maskTarget = comp.floatParent ? comp.floatParent.getTargetEl() : Ext.get(comp.getEl().dom.parentNode),
160             parentBox;
161         
162         if (!maskTarget) {
163             //&lt;debug&gt;
164             Ext.global.console &amp;&amp; Ext.global.console.warn &amp;&amp; Ext.global.console.warn('mask target could not be found. Mask cannot be shown');
165             //&lt;/debug&gt;
166             return;
167         }
168         
169         parentBox = maskTarget.getBox();
170
171         if (!this.mask) {
172             this.mask = Ext.getBody().createChild({
173                 cls: Ext.baseCSSPrefix + 'mask'
174             });
175             this.mask.setVisibilityMode(Ext.Element.DISPLAY);
176             this.mask.on('click', this._onMaskClick, this);
177         }
178         if (maskTarget.dom === document.body) {
179             parentBox.height = Ext.Element.getViewHeight();
180         }
181         maskTarget.addCls(Ext.baseCSSPrefix + 'body-masked');
182         this.mask.setBox(parentBox);
183         this.mask.setStyle('zIndex', zIndex);
184         this.mask.show();
185     },
186
187     _hideModalMask: function() {
188         if (this.mask &amp;&amp; this.mask.dom.parentNode) {
189             Ext.get(this.mask.dom.parentNode).removeCls(Ext.baseCSSPrefix + 'body-masked');
190             this.mask.hide();
191         }
192     },
193
194     _onMaskClick: function() {
195         if (this.front) {
196             this.front.focus();
197         }
198     },
199
200     _onContainerResize: function() {
201         if (this.mask &amp;&amp; this.mask.isVisible()) {
202             this.mask.setSize(Ext.get(this.mask.dom.parentNode).getViewSize(true));
203         }
204     },
205
206 <span id='Ext-ZIndexManager-method-register'>    /**
207 </span>     * &lt;p&gt;Registers a floating {@link Ext.Component} with this ZIndexManager. This should not
208      * need to be called under normal circumstances. Floating Components (such as Windows, BoundLists and Menus) are automatically registered
209      * with a {@link Ext.Component#zIndexManager zIndexManager} at render time.&lt;/p&gt;
210      * &lt;p&gt;Where this may be useful is moving Windows between two ZIndexManagers. For example,
211      * to bring the Ext.MessageBox dialog under the same manager as the Desktop's
212      * ZIndexManager in the desktop sample app:&lt;/p&gt;&lt;code&gt;&lt;pre&gt;
213 MyDesktop.getDesktop().getManager().register(Ext.MessageBox);
214 &lt;/pre&gt;&lt;/code&gt;
215      * @param {Ext.Component} comp The Component to register.
216      */
217     register : function(comp) {
218         if (comp.zIndexManager) {
219             comp.zIndexManager.unregister(comp);
220         }
221         comp.zIndexManager = this;
222
223         this.list[comp.id] = comp;
224         this.zIndexStack.push(comp);
225         comp.on('hide', this._activateLast, this);
226     },
227
228 <span id='Ext-ZIndexManager-method-unregister'>    /**
229 </span>     * &lt;p&gt;Unregisters a {@link Ext.Component} from this ZIndexManager. This should not
230      * need to be called. Components are automatically unregistered upon destruction.
231      * See {@link #register}.&lt;/p&gt;
232      * @param {Ext.Component} comp The Component to unregister.
233      */
234     unregister : function(comp) {
235         delete comp.zIndexManager;
236         if (this.list &amp;&amp; this.list[comp.id]) {
237             delete this.list[comp.id];
238             comp.un('hide', this._activateLast);
239             Ext.Array.remove(this.zIndexStack, comp);
240
241             // Destruction requires that the topmost visible floater be activated. Same as hiding.
242             this._activateLast(comp);
243         }
244     },
245
246 <span id='Ext-ZIndexManager-method-get'>    /**
247 </span>     * Gets a registered Component by id.
248      * @param {String/Object} id The id of the Component or a {@link Ext.Component} instance
249      * @return {Ext.Component}
250      */
251     get : function(id) {
252         return typeof id == &quot;object&quot; ? id : this.list[id];
253     },
254
255 <span id='Ext-ZIndexManager-method-bringToFront'>   /**
256 </span>     * Brings the specified Component to the front of any other active Components in this ZIndexManager.
257      * @param {String/Object} comp The id of the Component or a {@link Ext.Component} instance
258      * @return {Boolean} True if the dialog was brought to the front, else false
259      * if it was already in front
260      */
261     bringToFront : function(comp) {
262         comp = this.get(comp);
263         if (comp !== this.front) {
264             Ext.Array.remove(this.zIndexStack, comp);
265             this.zIndexStack.push(comp);
266             this.assignZIndices();
267             return true;
268         }
269         if (comp.modal) {
270             this._showModalMask(comp);
271         }
272         return false;
273     },
274
275 <span id='Ext-ZIndexManager-method-sendToBack'>    /**
276 </span>     * Sends the specified Component to the back of other active Components in this ZIndexManager.
277      * @param {String/Object} comp The id of the Component or a {@link Ext.Component} instance
278      * @return {Ext.Component} The Component
279      */
280     sendToBack : function(comp) {
281         comp = this.get(comp);
282         Ext.Array.remove(this.zIndexStack, comp);
283         this.zIndexStack.unshift(comp);
284         this.assignZIndices();
285         return comp;
286     },
287
288 <span id='Ext-ZIndexManager-method-hideAll'>    /**
289 </span>     * Hides all Components managed by this ZIndexManager.
290      */
291     hideAll : function() {
292         for (var id in this.list) {
293             if (this.list[id].isComponent &amp;&amp; this.list[id].isVisible()) {
294                 this.list[id].hide();
295             }
296         }
297     },
298
299 <span id='Ext-ZIndexManager-method-hide'>    /**
300 </span>     * @private
301      * Temporarily hides all currently visible managed Components. This is for when
302      * dragging a Window which may manage a set of floating descendants in its ZIndexManager;
303      * they should all be hidden just for the duration of the drag.
304      */
305     hide: function() {
306         var i = 0,
307             ln = this.zIndexStack.length,
308             comp;
309
310         this.tempHidden = [];
311         for (; i &lt; ln; i++) {
312             comp = this.zIndexStack[i];
313             if (comp.isVisible()) {
314                 this.tempHidden.push(comp);
315                 comp.hide();
316             }
317         }
318     },
319
320 <span id='Ext-ZIndexManager-method-show'>    /**
321 </span>     * @private
322      * Restores temporarily hidden managed Components to visibility.
323      */
324     show: function() {
325         var i = 0,
326             ln = this.tempHidden.length,
327             comp,
328             x,
329             y;
330
331         for (; i &lt; ln; i++) {
332             comp = this.tempHidden[i];
333             x = comp.x;
334             y = comp.y;
335             comp.show();
336             comp.setPosition(x, y);
337         }
338         delete this.tempHidden;
339     },
340
341 <span id='Ext-ZIndexManager-method-getActive'>    /**
342 </span>     * Gets the currently-active Component in this ZIndexManager.
343      * @return {Ext.Component} The active Component
344      */
345     getActive : function() {
346         return this.front;
347     },
348
349 <span id='Ext-ZIndexManager-method-getBy'>    /**
350 </span>     * Returns zero or more Components in this ZIndexManager using the custom search function passed to this method.
351      * The function should accept a single {@link Ext.Component} reference as its only argument and should
352      * return true if the Component matches the search criteria, otherwise it should return false.
353      * @param {Function} fn The search function
354      * @param {Object} scope (optional) The scope (&lt;code&gt;this&lt;/code&gt; reference) in which the function is executed. Defaults to the Component being tested.
355      * that gets passed to the function if not specified)
356      * @return {Array} An array of zero or more matching windows
357      */
358     getBy : function(fn, scope) {
359         var r = [],
360             i = 0,
361             len = this.zIndexStack.length,
362             comp;
363
364         for (; i &lt; len; i++) {
365             comp = this.zIndexStack[i];
366             if (fn.call(scope||comp, comp) !== false) {
367                 r.push(comp);
368             }
369         }
370         return r;
371     },
372
373 <span id='Ext-ZIndexManager-method-each'>    /**
374 </span>     * Executes the specified function once for every Component in this ZIndexManager, passing each
375      * Component as the only parameter. Returning false from the function will stop the iteration.
376      * @param {Function} fn The function to execute for each item
377      * @param {Object} scope (optional) The scope (&lt;code&gt;this&lt;/code&gt; reference) in which the function is executed. Defaults to the current Component in the iteration.
378      */
379     each : function(fn, scope) {
380         var comp;
381         for (var id in this.list) {
382             comp = this.list[id];
383             if (comp.isComponent &amp;&amp; fn.call(scope || comp, comp) === false) {
384                 return;
385             }
386         }
387     },
388
389 <span id='Ext-ZIndexManager-method-eachBottomUp'>    /**
390 </span>     * Executes the specified function once for every Component in this ZIndexManager, passing each
391      * Component as the only parameter. Returning false from the function will stop the iteration.
392      * The components are passed to the function starting at the bottom and proceeding to the top.
393      * @param {Function} fn The function to execute for each item
394      * @param {Object} scope (optional) The scope (&lt;code&gt;this&lt;/code&gt; reference) in which the function
395      * is executed. Defaults to the current Component in the iteration.
396      */
397     eachBottomUp: function (fn, scope) {
398         var comp,
399             stack = this.zIndexStack,
400             i, n;
401
402         for (i = 0, n = stack.length ; i &lt; n; i++) {
403             comp = stack[i];
404             if (comp.isComponent &amp;&amp; fn.call(scope || comp, comp) === false) {
405                 return;
406             }
407         }
408     },
409
410 <span id='Ext-ZIndexManager-method-eachTopDown'>    /**
411 </span>     * Executes the specified function once for every Component in this ZIndexManager, passing each
412      * Component as the only parameter. Returning false from the function will stop the iteration.
413      * The components are passed to the function starting at the top and proceeding to the bottom.
414      * @param {Function} fn The function to execute for each item
415      * @param {Object} scope (optional) The scope (&lt;code&gt;this&lt;/code&gt; reference) in which the function
416      * is executed. Defaults to the current Component in the iteration.
417      */
418     eachTopDown: function (fn, scope) {
419         var comp,
420             stack = this.zIndexStack,
421             i;
422
423         for (i = stack.length ; i-- &gt; 0; ) {
424             comp = stack[i];
425             if (comp.isComponent &amp;&amp; fn.call(scope || comp, comp) === false) {
426                 return;
427             }
428         }
429     },
430
431     destroy: function() {
432         this.each(function(c) {
433             c.destroy();
434         });
435         delete this.zIndexStack;
436         delete this.list;
437         delete this.container;
438         delete this.targetEl;
439     }
440 }, function() {
441 <span id='Ext-WindowManager'>    /**
442 </span>     * @class Ext.WindowManager
443      * @extends Ext.ZIndexManager
444      * &lt;p&gt;The default global floating Component group that is available automatically.&lt;/p&gt;
445      * &lt;p&gt;This manages instances of floating Components which were rendered programatically without
446      * being added to a {@link Ext.container.Container Container}, and for floating Components which were added into non-floating Containers.&lt;/p&gt;
447      * &lt;p&gt;&lt;i&gt;Floating&lt;/i&gt; Containers create their own instance of ZIndexManager, and floating Components added at any depth below
448      * there are managed by that ZIndexManager.&lt;/p&gt;
449      * @singleton
450      */
451     Ext.WindowManager = Ext.WindowMgr = new this();
452 });
453 </pre>
454 </body>
455 </html>