X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/c930e9176a5a85509c5b0230e2bff5c22a591432..6e39d509471fe9b4e2660e0d1631b350d0c66f40:/docs/source/Container.html diff --git a/docs/source/Container.html b/docs/source/Container.html index b9fc4778..9495b6e6 100644 --- a/docs/source/Container.html +++ b/docs/source/Container.html @@ -1,5 +1,6 @@ + The source code @@ -14,12 +15,12 @@ *

The most commonly used Container classes are {@link Ext.Panel}, {@link Ext.Window} and {@link Ext.TabPanel}. * If you do not need the capabilities offered by the aforementioned classes you can create a lightweight * Container to be encapsulated by an HTML element to your specifications by using the - * {@link Ext.Component#autoEl autoEl} config option. This is a useful technique when creating + * {@link Ext.Component#autoEl autoEl} config option. This is a useful technique when creating * embedded {@link Ext.layout.ColumnLayout column} layouts inside {@link Ext.form.FormPanel FormPanels} * for example.

* *

The code below illustrates both how to explicitly create a Container, and how to implicitly - * create one using the 'container' xtype:


+ * create one using the 'container' xtype:

 // explicitly create a Container
 var embeddedColumns = new Ext.Container({
     autoEl: 'div',  // This is the default
@@ -64,7 +65,7 @@ var embeddedColumns = new Ext.Container({
  * Container, and does not apply any sizing at all.

*

A common mistake is when a developer neglects to specify a * {@link #layout} (e.g. widgets like GridPanels or - * TreePanels are added to Containers for which no {@link #layout} + * TreePanels are added to Containers for which no {@link #layout} * has been specified). If a Container is left to use the default * {@link Ext.layout.ContainerLayout ContainerLayout} scheme, none of its * child components will be resized, or changed in any way when the Container @@ -90,10 +91,10 @@ myTabPanel.{@link Ext.TabPanel#setActiveTab setActiveTab}(myNewGrid); *

Overnesting is a common problem. * An example of overnesting occurs when a GridPanel is added to a TabPanel * by wrapping the GridPanel inside a wrapping Panel (that has no - * {@link #layout} specified) and then add that wrapping Panel + * {@link #layout} specified) and then add that wrapping Panel * to the TabPanel. The point to realize is that a GridPanel is a * Component which can be added directly to a Container. If the wrapping Panel - * has no {@link #layout} configuration, then the overnested + * has no {@link #layout} configuration, then the overnested * GridPanel will not be sized as expected.

* *

Adding via remote configuration

@@ -122,7 +123,7 @@ Ext.Ajax.request({ });
*

The server script needs to return an executable Javascript statement which, when processed - * using eval(), will return either a config object with an {@link Ext.Component#xtype xtype}, + * using eval(), will return either a config object with an {@link Ext.Component#xtype xtype}, * or an instantiated Component. The server might return this for example:


 (function() {
     function formatDate(value){
@@ -162,10 +163,10 @@ Ext.Ajax.request({
     return grid;  // return instantiated component
 })();
 
- *

When the above code fragment is passed through the eval function in the success handler + *

When the above code fragment is passed through the eval function in the success handler * of the Ajax request, the code is executed by the Javascript processor, and the anonymous function * runs, and returns the instantiated grid component.

- *

Note: since the code above is generated by a server script, the baseParams for + *

Note: since the code above is generated by a server script, the baseParams for * the Store, the metadata to allow generation of the Record layout, and the ColumnModel * can all be generated into the code since these are all known on the server.

* @@ -195,7 +196,7 @@ new Ext.Window({ }).show(); *
*

If the {@link #layout} configuration is not explicitly specified for - * a general purpose container (e.g. Container or Panel) the + * a general purpose container (e.g. Container or Panel) the * {@link Ext.layout.ContainerLayout 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). @@ -217,31 +218,31 @@ layout: { } * - *

  • type
  • + *
  • type
  • *

    The layout type to be used for this container. If not specified, * a default {@link Ext.layout.ContainerLayout} will be created and used.

    - *

    Valid layout type values are:

    + *

    Valid layout type values are:

    *
    * *
  • Layout specific configuration properties
  • *

    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 type + * each layout type, see the layout class corresponding to the type * specified.

    * * @@ -256,13 +257,13 @@ layoutConfig: { align: 'left' } - *
  • layout
  • - *

    The layout type to be used for this container (see list + *

  • layout
  • + *

    The layout type to be used for this container (see list * of valid layout type values above).


    - *
  • {@link #layoutConfig}
  • + *
  • {@link #layoutConfig}
  • *

    Additional layout specific configuration properties. For complete * details regarding the valid config options for each layout type, see the - * layout class corresponding to the layout specified.

    + * layout class corresponding to the layout specified.

    * */
    /** @@ -273,12 +274,12 @@ layoutConfig: { */
    /** * @cfg {Boolean/Number} bufferResize - * When set to true (100 milliseconds) or a number of milliseconds, the layout assigned for this container will buffer + * When set to true (50 milliseconds) or a number of milliseconds, the layout assigned for this container will buffer * the frequency it calculates and does a re-layout of components. This is useful for heavy containers or containers - * with a large quantity of sub-components for which frequent layout calls would be expensive. + * with a large quantity of sub-components for which frequent layout calls would be expensive. Defaults to 50. */ - bufferResize: 100, - + bufferResize: 50, +
    /** * @cfg {String/Number} activeItem * A string component id or the numeric index of the component that should be initially activated within the @@ -326,14 +327,18 @@ layout: 'anchor', // specify a layout! * */
    /** - * @cfg {Object} defaults - *

    A config object that will be applied to all components added to this container either via the {@link #items} - * config or via the {@link #add} or {@link #insert} methods. The defaults config can contain any - * number of name/value property pairs to be added to each item, and should be valid for the types of items - * being added to the container. For example, to automatically apply padding to the body of each of a set of - * contained {@link Ext.Panel} items, you could pass: defaults: {bodyStyle:'padding:15px'}.


    - *

    Note: defaults will not be applied to config objects if the option is already specified. - * For example:

    
    +     * @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.

    + *

    If an added item is a config object, and not an instantiated Component, then the default properties are + * unconditionally applied. If the added item is an instantiated Component, then the default properties are + * applied conditionally so as not to override existing properties in the item.

    + *

    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} items, you could pass: defaults: {bodyStyle:'padding:15px'}.

    + *

    Usage:

    
     defaults: {               // defaults are applied to items, not the container
         autoScroll:true
     },
    @@ -371,11 +376,24 @@ items: [
         
    /** @cfg {String} defaultType *

    The default {@link Ext.Component xtype} of child Components to create in this Container when * a child item is specified as a raw configuration object, rather than as an instantiated Component.

    - *

    Defaults to 'panel', except {@link Ext.menu.Menu} which defaults to 'menuitem', - * and {@link Ext.Toolbar} and {@link Ext.ButtonGroup} which default to 'button'.

    + *

    Defaults to 'panel', except {@link Ext.menu.Menu} which defaults to 'menuitem', + * and {@link Ext.Toolbar} and {@link Ext.ButtonGroup} which default to 'button'.

    */ defaultType : 'panel', +
    /** @cfg {String} resizeEvent + * The event to listen to for resizing in layouts. Defaults to 'resize'. + */ + resizeEvent: 'resize', + +
    /** + * @cfg {Array} bubbleEvents + *

    An array of events that, when fired, should be bubbled to any parent container. + * See {@link Ext.util.Observable#enableBubble}. + * Defaults to ['add', 'remove']. + */ + bubbleEvents: ['add', 'remove'], + // private initComponent : function(){ Ext.Container.superclass.initComponent.call(this); @@ -424,7 +442,7 @@ items: [ 'remove' ); - this.enableBubble('add', 'remove'); + this.enableBubble(this.bubbleEvents);

    /** * The collection of components in this container as a {@link Ext.util.MixedCollection} @@ -434,11 +452,7 @@ items: [ var items = this.items; if(items){ delete this.items; - if(Ext.isArray(items) && items.length > 0){ - this.add.apply(this, items); - }else{ - this.add(items); - } + this.add(items); } }, @@ -460,29 +474,35 @@ items: [ layout.setContainer(this); }, - // private - render : function(){ - Ext.Container.superclass.render.apply(this, arguments); - if(this.layout){ - if(Ext.isObject(this.layout) && !this.layout.layout){ - this.layoutConfig = this.layout; - this.layout = this.layoutConfig.type; - } - if(typeof this.layout == 'string'){ - this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig); - } - this.setLayout(this.layout); + afterRender: function(){ + this.layoutDone = false; + if(!this.layout){ + this.layout = 'auto'; + } + if(Ext.isObject(this.layout) && !this.layout.layout){ + this.layoutConfig = this.layout; + this.layout = this.layoutConfig.type; + } + if(Ext.isString(this.layout)){ + this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig); + } + this.setLayout(this.layout); - if(this.activeItem !== undefined){ - var item = this.activeItem; - delete this.activeItem; - this.layout.setActiveItem(item); - } + // BoxComponent's afterRender will set the size. + // This will will trigger a layout if the layout is configured to monitor resize + Ext.Container.superclass.afterRender.call(this); + + if(Ext.isDefined(this.activeItem)){ + var item = this.activeItem; + delete this.activeItem; + this.layout.setActiveItem(item); } - if(!this.ownerCt){ - // force a layout if no ownerCt is set + + // If we have no ownerCt and the BoxComponent's sizing did not trigger a layout, force a layout + if(!this.ownerCt && !this.layoutDone){ this.doLayout(false, true); } + if(this.monitorResize === true){ Ext.EventManager.onWindowResize(this.doLayout, this, [false]); } @@ -515,10 +535,10 @@ items: [ * *

    Notes : *

      - *
    • If the Container is already rendered when add + *
    • If the Container is already rendered when add * is called, you may need to call {@link #doLayout} to refresh the view which causes * any unrendered child Components to be rendered. This is required so that you can - * add multiple child components if needed while only refreshing the layout + * add multiple child components if needed while only refreshing the layout * once. For example:
      
       var tb = new {@link Ext.Toolbar}();
       tb.render(document.body);  // toolbar is rendered
      @@ -541,21 +561,40 @@ tb.{@link #doLayout}();             // refresh the layout
               this.initItems();
               var args = arguments.length > 1;
               if(args || Ext.isArray(comp)){
      +            var result = [];
                   Ext.each(args ? arguments : comp, function(c){
      -                this.add(c);
      +                result.push(this.add(c));
                   }, this);
      -            return;
      +            return result;
               }
               var c = this.lookupComponent(this.applyDefaults(comp));
      -        var pos = this.items.length;
      -        if(this.fireEvent('beforeadd', this, c, pos) !== false && this.onBeforeAdd(c) !== false){
      +        var index = this.items.length;
      +        if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){
                   this.items.add(c);
      -            c.ownerCt = this;
      -            this.fireEvent('add', this, c, pos);
      +            // *onAdded
      +            c.onAdded(this, index);
      +            this.onAdd(c);
      +            this.fireEvent('add', this, c, index);
               }
               return c;
           },
       
      +    onAdd : function(c){
      +        // Empty template method
      +    },
      +    
      +    // private
      +    onAdded : function(container, pos) {
      +        //overridden here so we can cascade down, not worth creating a template method.
      +        this.ownerCt = container;
      +        this.initRef();
      +        //initialize references for child items
      +        this.cascade(function(c){
      +            c.initRef();
      +        });
      +        this.fireEvent('added', this, container, pos);
      +    },
      +
           
      /** * Inserts a Component into this Container at a specified index. Fires the * {@link #beforeadd} event before inserting, then fires the {@link #add} event after the @@ -578,20 +617,21 @@ tb.{@link #doLayout}(); // refresh the layout this.initItems(); var a = arguments, len = a.length; if(len > 2){ + var result = []; for(var i = len-1; i >= 1; --i) { - this.insert(index, a[i]); + result.push(this.insert(index, a[i])); } - return; + return result; } var c = this.lookupComponent(this.applyDefaults(comp)); - - if(c.ownerCt == this && this.items.indexOf(c) < index){ - --index; - } - + index = Math.min(index, this.items.length); if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){ + if(c.ownerCt == this){ + this.items.remove(c); + } this.items.insert(index, c); - c.ownerCt = this; + c.onAdded(this, index); + this.onAdd(c); this.fireEvent('add', this, c, index); } return c; @@ -599,14 +639,18 @@ tb.{@link #doLayout}(); // refresh the layout // private applyDefaults : function(c){ - if(this.defaults){ - if(typeof c == 'string'){ + var d = this.defaults; + if(d){ + if(Ext.isFunction(d)){ + d = d.call(this, c); + } + if(Ext.isString(c)){ c = Ext.ComponentMgr.get(c); - Ext.apply(c, this.defaults); + Ext.apply(c, d); }else if(!c.events){ - Ext.applyIf(c, this.defaults); + Ext.applyIf(c, d); }else{ - Ext.apply(c, this.defaults); + Ext.apply(c, d); } } return c; @@ -634,19 +678,29 @@ tb.{@link #doLayout}(); // refresh the layout this.initItems(); var c = this.getComponent(comp); if(c && this.fireEvent('beforeremove', this, c) !== false){ - this.items.remove(c); - delete c.ownerCt; - if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){ - c.destroy(); - } - if(this.layout && this.layout.activeItem == c){ - delete this.layout.activeItem; - } + this.doRemove(c, autoDestroy); this.fireEvent('remove', this, c); } return c; }, + onRemove: function(c){ + // Empty template method + }, + + // private + doRemove: function(c, autoDestroy){ + if(this.layout && this.rendered){ + this.layout.onRemove(c); + } + this.items.remove(c); + c.onRemoved(); + this.onRemove(c); + if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){ + c.destroy(); + } + }, +
      /** * Removes all components from this container. * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function. @@ -674,9 +728,9 @@ tb.{@link #doLayout}(); // refresh the layout * and gets a direct child component of this container. * @param {String/Number} comp This parameter may be any of the following: *
        - *
      • a String : representing the {@link Ext.Component#itemId itemId} + *
      • a String : representing the {@link Ext.Component#itemId itemId} * or {@link Ext.Component#id id} of the child component
      • - *
      • a Number : representing the position of the child component + *
      • a Number : representing the position of the child component * within the {@link #items} property
      • *
      *

      For additional information see {@link Ext.util.MixedCollection#get}. @@ -684,14 +738,14 @@ tb.{@link #doLayout}(); // refresh the layout */ getComponent : function(comp){ if(Ext.isObject(comp)){ - return comp; + comp = comp.getItemId(); } return this.items.get(comp); }, // private lookupComponent : function(comp){ - if(typeof comp == 'string'){ + if(Ext.isString(comp)){ return Ext.ComponentMgr.get(comp); }else if(!comp.events){ return this.createComponent(comp); @@ -700,8 +754,23 @@ tb.{@link #doLayout}(); // refresh the layout }, // private - createComponent : function(config){ - return Ext.create(config, this.defaultType); + createComponent : function(config, defaultType){ + // add in ownerCt at creation time but then immediately + // remove so that onBeforeAdd can handle it + var c = config.render ? config : Ext.create(Ext.apply({ + ownerCt: this + }, config), defaultType || this.defaultType); + delete c.ownerCt; + return c; + }, + +

      /** + * We can only lay out if there is a view area in which to layout. + * display:none on the layout target, *or any of its parent elements* will mean it has no view area. + */ + canLayout: function() { + var el = this.getLayoutTarget(), vs; + return !!(el && (vs = el.dom.offsetWidth || el.dom.offsetHeight)); },
      /** @@ -714,42 +783,80 @@ tb.{@link #doLayout}(); // refresh the layout */ doLayout: function(shallow, force){ var rendered = this.rendered, - forceLayout = this.forceLayout; + forceLayout = force || this.forceLayout, + cs, i, len, c; - if(!this.isVisible() || this.collapsed){ + this.layoutDone = true; + if(!this.canLayout() || this.collapsed){ this.deferLayout = this.deferLayout || !shallow; - if(!(force || forceLayout)){ + if(!forceLayout){ return; } shallow = shallow && !this.deferLayout; } else { delete this.deferLayout; } + + cs = (shallow !== true && this.items) ? this.items.items : []; + +// Inhibit child Containers from relaying on resize since we are about to to explicitly call doLayout on them all! + for(i = 0, len = cs.length; i < len; i++){ + if ((c = cs[i]).layout) { + c.suspendLayoutResize = true; + } + } + +// Tell the layout manager to ensure all child items are rendered, and sized according to their rules. +// Will not cause the child items to relayout. if(rendered && this.layout){ this.layout.layout(); } - if(shallow !== true && this.items){ - var cs = this.items.items; - for(var i = 0, len = cs.length; i < len; i++){ - var c = cs[i]; - if(c.doLayout){ - c.forceLayout = forceLayout; - c.doLayout(); - } + +// Explicitly lay out all child items + for(i = 0; i < len; i++){ + if((c = cs[i]).doLayout){ + c.doLayout(false, forceLayout); } } if(rendered){ - this.onLayout(shallow, force); + this.onLayout(shallow, forceLayout); } + // Initial layout completed + this.hasLayout = true; delete this.forceLayout; + +// Re-enable child layouts relaying on resize. + for(i = 0; i < len; i++){ + if ((c = cs[i]).layout) { + delete c.suspendLayoutResize; + } + } }, //private onLayout : Ext.emptyFn, + onResize: function(adjWidth, adjHeight, rawWidth, rawHeight){ + Ext.Container.superclass.onResize.apply(this, arguments); + if ((this.rendered && this.layout && this.layout.monitorResize) && !this.suspendLayoutResize) { + this.layout.onResize(); + } + }, + + // private + hasLayoutPending: function(){ + // Traverse hierarchy to see if any parent container has a pending layout. + var pending = this.layoutPending; + this.ownerCt.bubble(function(c){ + return !(pending = c.layoutPending); + }); + return pending; + + }, + onShow : function(){ Ext.Container.superclass.onShow.call(this); - if(this.deferLayout !== undefined){ + if(Ext.isDefined(this.deferLayout)){ this.doLayout(true); } }, @@ -769,8 +876,11 @@ tb.{@link #doLayout}(); // refresh the layout // private beforeDestroy : function(){ + var c; if(this.items){ - Ext.destroy.apply(Ext, this.items.items); + while(c = this.items.first()){ + this.doRemove(c, true); + } } if(this.monitorResize){ Ext.EventManager.removeResizeListener(this.doLayout, this);