X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/c930e9176a5a85509c5b0230e2bff5c22a591432..10a866c12701c0a0afd0ac85dcdcf32a421514ac:/docs/source/Container.html?ds=inline 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 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
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:
{@link Ext.layout.AbsoluteLayout absolute}
{@link Ext.layout.AccordionLayout accordion}
{@link Ext.layout.AnchorLayout anchor}
{@link Ext.layout.ContainerLayout auto}
Default{@link Ext.layout.BorderLayout border}
{@link Ext.layout.CardLayout card}
{@link Ext.layout.ColumnLayout column}
{@link Ext.layout.FitLayout fit}
{@link Ext.layout.FormLayout form}
{@link Ext.layout.HBoxLayout hbox}
{@link Ext.layout.MenuLayout menu}
{@link Ext.layout.TableLayout table}
{@link Ext.layout.ToolbarLayout toolbar}
{@link Ext.layout.VBoxLayout vbox}
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.
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}
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 thelayout
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);