Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / container / AbstractContainer.js
index 62de3a7..4013666 100644 (file)
@@ -1,8 +1,22 @@
+/*
+
+This file is part of Ext JS 4
+
+Copyright (c) 2011 Sencha Inc
+
+Contact:  http://www.sencha.com/contact
+
+GNU General Public License Usage
+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.
+
+If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
+
+*/
 /**
  * @class Ext.container.AbstractContainer
  * @extends Ext.Component
- * <p>An abstract base class which provides shared methods for Containers across the Sencha product line.</p>
- * Please refer to sub class's documentation
+ * An abstract base class which provides shared methods for Containers across the Sencha product line.
+ * @private
  */
 Ext.define('Ext.container.AbstractContainer', {
 
@@ -19,10 +33,10 @@ Ext.define('Ext.container.AbstractContainer', {
     /* End Definitions */
     /**
      * @cfg {String/Object} layout
-     * <p><b>*Important</b>: In order for child items to be correctly sized and
+     * <p><b>Important</b>: In order for child items to be correctly sized and
      * positioned, typically a layout manager <b>must</b> be specified through
      * the <code>layout</code> configuration option.</p>
-     * <br><p>The sizing and positioning of child {@link #items} is the responsibility of
+     * <p>The sizing and positioning of child {@link #items} is the responsibility of
      * the Container's layout manager which creates and manages the type of layout
      * you have in mind.  For example:</p>
      * <p>If the {@link #layout} configuration is not explicitly specified for
@@ -30,9 +44,8 @@ Ext.define('Ext.container.AbstractContainer', {
      * {@link Ext.layout.container.Auto default layout manager} will be used
      * which does nothing but render child components sequentially into the
      * Container (no sizing or positioning will be performed in this situation).</p>
-     * <br><p><b><code>layout</code></b> may be specified as either as an Object or
-     * as a String:</p><div><ul class="mdetail-params">
-     *
+     * <p><b><code>layout</code></b> may be specified as either as an Object or as a String:</p>
+     * <div><ul class="mdetail-params">
      * <li><u>Specify as an Object</u></li>
      * <div><ul class="mdetail-params">
      * <li>Example usage:</li>
@@ -46,7 +59,7 @@ layout: {
      * <li><code><b>type</b></code></li>
      * <br/><p>The layout type to be used for this container.  If not specified,
      * a default {@link Ext.layout.container.Auto} will be created and used.</p>
-     * <br/><p>Valid layout <code>type</code> values are:</p>
+     * <p>Valid layout <code>type</code> values are:</p>
      * <div class="sub-desc"><ul class="mdetail-params">
      * <li><code><b>{@link Ext.layout.container.Auto Auto}</b></code> &nbsp;&nbsp;&nbsp; <b>Default</b></li>
      * <li><code><b>{@link Ext.layout.container.Card card}</b></code></li>
@@ -58,7 +71,7 @@ layout: {
      * </ul></div>
      *
      * <li>Layout specific configuration properties</li>
-     * <br/><p>Additional layout specific configuration properties may also be
+     * <p>Additional layout specific configuration properties may also be
      * specified. For complete details regarding the valid config options for
      * each layout type, see the layout class corresponding to the <code>type</code>
      * specified.</p>
@@ -69,16 +82,12 @@ layout: {
      * <div><ul class="mdetail-params">
      * <li>Example usage:</li>
      * <pre><code>
-layout: {
-    type: 'vbox',
-    padding: '5',
-    align: 'left'
-}
+layout: 'vbox'
        </code></pre>
      * <li><code><b>layout</b></code></li>
-     * <br/><p>The layout <code>type</code> to be used for this container (see list
-     * of valid layout type values above).</p><br/>
-     * <br/><p>Additional layout specific configuration properties. For complete
+     * <p>The layout <code>type</code> to be used for this container (see list
+     * of valid layout type values above).</p>
+     * <p>Additional layout specific configuration properties. For complete
      * details regarding the valid config options for each layout type, see the
      * layout class corresponding to the <code>layout</code> specified.</p>
      * </ul></div></ul></div>
@@ -92,7 +101,7 @@ layout: {
      * items one at a time (like {@link Ext.layout.container.Card} and {@link Ext.layout.container.Fit}).
      */
     /**
-     * @cfg {Object/Array} items
+     * @cfg {Object/Object[]} items
      * <p>A single item, or an array of child Components to be added to this container</p>
      * <p><b>Unless configured with a {@link #layout}, a Container simply renders child Components serially into
      * its encapsulating element and performs no sizing or positioning upon them.</b><p>
@@ -120,36 +129,41 @@ layout: 'hbox', // The items are arranged horizontally
      * <p>Ext uses lazy rendering. Child Components will only be rendered
      * should it become necessary. Items are automatically laid out when they are first
      * shown (no sizing is done while hidden), or in response to a {@link #doLayout} call.</p>
-     * <p>Do not specify <code>{@link Ext.panel.Panel#contentEl contentEl}</code> or 
+     * <p>Do not specify <code>{@link Ext.panel.Panel#contentEl contentEl}</code> or
      * <code>{@link Ext.panel.Panel#html html}</code> with <code>items</code>.</p>
      */
     /**
-     * @cfg {Object|Function} defaults
-     * <p>This option is a means of applying default settings to all added items whether added through the {@link #items}
-     * config or via the {@link #add} or {@link #insert} methods.</p>
-     * <p>If an added item is a config object, and <b>not</b> an instantiated Component, then the default properties are
-     * unconditionally applied. If the added item <b>is</b> an instantiated Component, then the default properties are
-     * applied conditionally so as not to override existing properties in the item.</p>
-     * <p>If the defaults option is specified as a function, then the function will be called using this Container as the
-     * scope (<code>this</code> reference) and passing the added item as the first parameter. Any resulting object
-     * from that call is then applied to the item as default properties.</p>
-     * <p>For example, to automatically apply padding to the body of each of a set of
-     * contained {@link Ext.panel.Panel} items, you could pass: <code>defaults: {bodyStyle:'padding:15px'}</code>.</p>
-     * <p>Usage:</p><pre><code>
-defaults: {               // defaults are applied to items, not the container
-    autoScroll:true
-},
-items: [
-    {
-        xtype: 'panel',   // defaults <b>do not</b> have precedence over
-        id: 'panel1',     // options in config objects, so the defaults
-        autoScroll: false // will not be applied here, panel1 will be autoScroll:false
-    },
-    new Ext.panel.Panel({       // defaults <b>do</b> have precedence over options
-        id: 'panel2',     // options in components, so the defaults
-        autoScroll: false // will be applied here, panel2 will be autoScroll:true.
-    })
-]</code></pre>
+     * @cfg {Object/Function} defaults
+     * This option is a means of applying default settings to all added items whether added through the {@link #items}
+     * config or via the {@link #add} or {@link #insert} methods.
+     *
+     * Defaults are applied to both config objects and instantiated components conditionally so as not to override
+     * existing properties in the item (see {@link Ext#applyIf}).
+     *
+     * If the defaults option is specified as a function, then the function will be called using this Container as the
+     * scope (`this` reference) and passing the added item as the first parameter. Any resulting object
+     * from that call is then applied to the item as default properties.
+     *
+     * For example, to automatically apply padding to the body of each of a set of
+     * contained {@link Ext.panel.Panel} items, you could pass: `defaults: {bodyStyle:'padding:15px'}`.
+     *
+     * Usage:
+     *
+     *     defaults: { // defaults are applied to items, not the container
+     *         autoScroll: true
+     *     },
+     *     items: [
+     *         // default will not be applied here, panel1 will be autoScroll: false
+     *         {
+     *             xtype: 'panel',
+     *             id: 'panel1',
+     *             autoScroll: false
+     *         },
+     *         // this component will have autoScroll: true
+     *         new Ext.panel.Panel({
+     *             id: 'panel2'
+     *         })
+     *     ]
      */
 
     /** @cfg {Boolean} suspendLayout
@@ -174,16 +188,24 @@ items: [
 
     isContainer : true,
 
+    /**
+     * The number of container layout calls made on this object.
+     * @property layoutCounter
+     * @type {Number}
+     * @private
+     */
+    layoutCounter : 0,
+
     baseCls: Ext.baseCSSPrefix + 'container',
 
     /**
-     * @cfg {Array} bubbleEvents
+     * @cfg {String[]} bubbleEvents
      * <p>An array of events that, when fired, should be bubbled to any parent container.
      * See {@link Ext.util.Observable#enableBubble}.
      * Defaults to <code>['add', 'remove']</code>.
      */
     bubbleEvents: ['add', 'remove'],
-    
+
     // @private
     initComponent : function(){
         var me = this;
@@ -192,7 +214,7 @@ items: [
              * @event afterlayout
              * Fires when the components in this container are arranged by the associated layout manager.
              * @param {Ext.container.Container} this
-             * @param {ContainerLayout} layout The ContainerLayout implementation for this container
+             * @param {Ext.layout.container.Container} layout The ContainerLayout implementation for this container
              */
             'afterlayout',
             /**
@@ -228,35 +250,7 @@ items: [
              * @param {Ext.container.Container} this
              * @param {Ext.Component} component The component that was removed
              */
-            'remove',
-            /**
-             * @event beforecardswitch
-             * Fires before this container switches the active card. This event
-             * is only available if this container uses a CardLayout. Note that
-             * TabPanel and Carousel both get a CardLayout by default, so both
-             * will have this event.
-             * A handler can return false to cancel the card switch.
-             * @param {Ext.container.Container} this
-             * @param {Ext.Component} newCard The card that will be switched to
-             * @param {Ext.Component} oldCard The card that will be switched from
-             * @param {Number} index The index of the card that will be switched to
-             * @param {Boolean} animated True if this cardswitch will be animated
-             */
-            'beforecardswitch',
-            /**
-             * @event cardswitch
-             * Fires after this container switches the active card. If the card
-             * is switched using an animation, this event will fire after the
-             * animation has finished. This event is only available if this container
-             * uses a CardLayout. Note that TabPanel and Carousel both get a CardLayout
-             * by default, so both will have this event.
-             * @param {Ext.container.Container} this
-             * @param {Ext.Component} newCard The card that has been switched to
-             * @param {Ext.Component} oldCard The card that has been switched from
-             * @param {Number} index The index of the card that has been switched to
-             * @param {Boolean} animated True if this cardswitch was animated
-             */
-            'cardswitch'
+            'remove'
         );
 
         // layoutOnShow stack
@@ -292,6 +286,20 @@ items: [
         this.callParent();
     },
 
+    renderChildren: function () {
+        var me = this,
+            layout = me.getLayout();
+
+        me.callParent();
+        // this component's elements exist, so now create the child components' elements
+
+        if (layout) {
+            me.suspendLayout = true;
+            layout.renderChildren();
+            delete me.suspendLayout;
+        }
+    },
+
     // @private
     setLayout : function(layout) {
         var currentLayout = this.layout;
@@ -319,7 +327,7 @@ items: [
     },
 
     /**
-     * Manually force this container's layout to be recalculated.  The framwork uses this internally to refresh layouts
+     * Manually force this container's layout to be recalculated. The framework uses this internally to refresh layouts
      * form most cases.
      * @return {Ext.container.Container} this
      */
@@ -329,7 +337,7 @@ items: [
 
         if (me.rendered && layout && !me.suspendLayout) {
             // If either dimension is being auto-set, then it requires a ComponentLayout to be run.
-            if ((!Ext.isNumber(me.width) || !Ext.isNumber(me.height)) && me.componentLayout.type !== 'autocomponent') {
+            if (!me.isFixedWidth() || !me.isFixedHeight()) {
                 // Only run the ComponentLayout if it is not already in progress
                 if (me.componentLayout.layoutBusy !== true) {
                     me.doComponentLayout();
@@ -338,7 +346,7 @@ items: [
                     }
                 }
             }
-            // Both dimensions defined, run a ContainerLayout
+            // Both dimensions set, either by configuration, or by an owning layout, run a ContainerLayout
             else {
                 // Only run the ContainerLayout if it is not already in progress
                 if (layout.layoutBusy !== true) {
@@ -352,6 +360,7 @@ items: [
 
     // @private
     afterLayout : function(layout) {
+        ++this.layoutCounter;
         this.fireEvent('afterlayout', this, layout);
     },
 
@@ -387,12 +396,8 @@ items: [
 
             if (Ext.isString(config)) {
                 config = Ext.ComponentManager.get(config);
-                Ext.applyIf(config, defaults);
-            } else if (!config.isComponent) {
-                Ext.applyIf(config, defaults);
-            } else {
-                Ext.applyIf(config, defaults);
             }
+            Ext.applyIf(config, defaults);
         }
 
         return config;
@@ -448,17 +453,17 @@ If adding multiple new child Components, pass them as an array to the `add` meth
     });  // toolbar is rendered
     tb.add([{text:'Button 1'}, {text:'Button 2'}]); // add multiple items. ({@link #defaultType} for {@link Ext.toolbar.Toolbar Toolbar} is 'button')
 
-##Warning:## 
+##Warning:##
 
 Components directly managed by the BorderLayout layout manager
 may not be removed or added.  See the Notes for {@link Ext.layout.container.Border BorderLayout}
 for more details.
 
-     * @param {...Object/Array} Component
+     * @param {Ext.Component[]/Ext.Component...} component
      * Either one or more Components to add or an Array of Components to add.
      * See `{@link #items}` for additional information.
      *
-     * @return {Ext.Component/Array} The Components that were added.
+     * @return {Ext.Component[]/Ext.Component} The Components that were added.
      * @markdown
      */
     add : function() {
@@ -485,13 +490,13 @@ for more details.
             me.suspendLayout = true;
             for (i = 0, ln = items.length; i < ln; i++) {
                 item = items[i];
-                
+
                 //<debug>
                 if (!item) {
                     Ext.Error.raise("Trying to add a null item as a child of Container with itemId/id: " + me.getItemId());
                 }
                 //</debug>
-                
+
                 if (index != -1) {
                     item = me.add(index + i, item);
                 } else {
@@ -525,22 +530,6 @@ for more details.
         return cmp;
     },
 
-    /**
-     * @private
-     * <p>Called by Component#doAutoRender</p>
-     * <p>Register a Container configured <code>floating: true</code> with this Container's {@link Ext.ZIndexManager ZIndexManager}.</p>
-     * <p>Components added in ths way will not participate in the layout, but will be rendered
-     * upon first show in the way that {@link Ext.window.Window Window}s are.</p>
-     * <p></p>
-     */
-    registerFloatingItem: function(cmp) {
-        var me = this;
-        if (!me.floatingItems) {
-            me.floatingItems = Ext.create('Ext.ZIndexManager', me);
-        }
-        me.floatingItems.register(cmp);
-    },
-
     onAdd : Ext.emptyFn,
     onRemove : Ext.emptyFn,
 
@@ -587,7 +576,7 @@ for more details.
     // @private
     onBeforeAdd : function(item) {
         var me = this;
-        
+
         if (item.ownerCt) {
             item.ownerCt.remove(item, false);
         }
@@ -600,7 +589,7 @@ for more details.
     /**
      * Removes a component from this container.  Fires the {@link #beforeremove} event before removing, then fires
      * the {@link #remove} event after the component has been removed.
-     * @param {Component/String} component The component reference or id to remove.
+     * @param {Ext.Component/String} component The component reference or id to remove.
      * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
      * Defaults to the value of this Container's {@link #autoDestroy} config.
      * @return {Ext.Component} component The Component that was removed.
@@ -654,7 +643,7 @@ for more details.
      * Removes all components from this container.
      * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
      * Defaults to the value of this Container's {@link #autoDestroy} config.
-     * @return {Array} Array of the destroyed components
+     * @return {Ext.Component[]} Array of the destroyed components
      */
     removeAll : function(autoDestroy) {
         var me = this,
@@ -675,9 +664,11 @@ for more details.
             }
         }
 
-        // Resume Layouts now that all items have been removed and do a single layout
+        // Resume Layouts now that all items have been removed and do a single layout (if we removed anything!)
         me.suspendLayout = false;
-        me.doLayout();
+        if (len) {
+            me.doLayout();
+        }
         return items;
     },
 
@@ -721,8 +712,8 @@ for more details.
      * will be the args provided or the current component. If the function returns false at any point,
      * the cascade is stopped on that branch.
      * @param {Function} fn The function to call
-     * @param {Object} scope (optional) The scope of the function (defaults to current component)
-     * @param {Array} args (optional) The args to call the function with. The current component always passed as the last argument.
+     * @param {Object} [scope] The scope of the function (defaults to current component)
+     * @param {Array} [args] The args to call the function with. The current component always passed as the last argument.
      * @return {Ext.Container} this
      */
     cascade : function(fn, scope, origArgs){
@@ -772,27 +763,32 @@ for more details.
     /**
      * Retrieves all descendant components which match the passed selector.
      * Executes an Ext.ComponentQuery.query using this container as its root.
-     * @param {String} selector Selector complying to an Ext.ComponentQuery selector
-     * @return {Array} Ext.Component's which matched the selector
+     * @param {String} selector (optional) Selector complying to an Ext.ComponentQuery selector.
+     * If no selector is specified all items will be returned.
+     * @return {Ext.Component[]} Components which matched the selector
      */
     query : function(selector) {
+        selector = selector || '*';
         return Ext.ComponentQuery.query(selector, this);
     },
 
     /**
      * Retrieves the first direct child of this container which matches the passed selector.
      * The passed in selector must comply with an Ext.ComponentQuery selector.
-     * @param {String} selector An Ext.ComponentQuery selector
+     * @param {String} selector (optional) An Ext.ComponentQuery selector. If no selector is
+     * specified, the first child will be returned.
      * @return Ext.Component
      */
     child : function(selector) {
+        selector = selector || '';
         return this.query('> ' + selector)[0] || null;
     },
 
     /**
      * Retrieves the first descendant of this container which matches the passed selector.
      * The passed in selector must comply with an Ext.ComponentQuery selector.
-     * @param {String} selector An Ext.ComponentQuery selector
+     * @param {String} selector (optional) An Ext.ComponentQuery selector. If no selector is
+     * specified, the first child will be returned.
      * @return Ext.Component
      */
     down : function(selector) {
@@ -824,20 +820,20 @@ for more details.
             }
         }
         layoutCollection.clear();
-    },    
-    
+    },
+
     //@private
     // Enable all immediate children that was previously disabled
     onEnable: function() {
         Ext.Array.each(this.query('[isFormField]'), function(item) {
             if (item.resetDisable) {
                 item.enable();
-                delete item.resetDisable;             
+                delete item.resetDisable;
             }
         });
         this.callParent();
     },
-    
+
     // @private
     // Disable all immediate children that was previously disabled
     onDisable: function() {
@@ -871,9 +867,9 @@ for more details.
         }
 
         Ext.destroy(
-            me.layout,
-            me.floatingItems
+            me.layout
         );
         me.callParent();
     }
-});
\ No newline at end of file
+});
+