X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/c930e9176a5a85509c5b0230e2bff5c22a591432..2e847cf21b8ab9d15fa167b315ca5b2fa92638fc:/pkgs/cmp-foundation-debug.js diff --git a/pkgs/cmp-foundation-debug.js b/pkgs/cmp-foundation-debug.js index 94a91ae5..2e29ba62 100644 --- a/pkgs/cmp-foundation-debug.js +++ b/pkgs/cmp-foundation-debug.js @@ -1,6 +1,6 @@ /*! - * Ext JS Library 3.0.0 - * Copyright(c) 2006-2009 Ext JS, LLC + * Ext JS Library 3.1.1 + * Copyright(c) 2006-2010 Ext JS, LLC * licensing@extjs.com * http://www.extjs.com/license */ @@ -11,12 +11,12 @@ * {@link Ext.Component#id id} (see {@link #get}, or the convenience method {@link Ext#getCmp Ext.getCmp}).

*

This object also provides a registry of available Component classes * indexed by a mnemonic code known as the Component's {@link Ext.Component#xtype xtype}. - * The {@link Ext.Component#xtype xtype} provides a way to avoid instantiating child Components + * The {@link Ext.Component#xtype xtype} provides a way to avoid instantiating child Components * when creating a full, nested config object for a complete Ext page.

*

A child Component may be specified simply as a config object - * as long as the correct {@link Ext.Component#xtype xtype} is specified so that if and when the Component + * as long as the correct {@link Ext.Component#xtype xtype} is specified so that if and when the Component * needs rendering, the correct type can be looked up for lazy instantiation.

- *

For a list of all available {@link Ext.Component#xtype xtypes}, see {@link Ext.Component}.

+ *

For a list of all available {@link Ext.Component#xtype xtypes}, see {@link Ext.Component}.

* @singleton */ Ext.ComponentMgr = function(){ @@ -45,7 +45,7 @@ Ext.ComponentMgr = function(){ * Returns a component by {@link Ext.Component#id id}. * For additional details see {@link Ext.util.MixedCollection#get}. * @param {String} id The component {@link Ext.Component#id id} - * @return Ext.Component The Component, undefined if not found, or null if a + * @return Ext.Component The Component, undefined if not found, or null if a * Class was found. */ get : function(id){ @@ -53,10 +53,10 @@ Ext.ComponentMgr = function(){ }, /** - * Registers a function that will be called when a specified component is added to ComponentMgr + * Registers a function that will be called when a Component with the specified id is added to ComponentMgr. This will happen on instantiation. * @param {String} id The component {@link Ext.Component#id id} * @param {Function} fn The callback function - * @param {Object} scope The scope of the callback + * @param {Object} scope The scope (this reference) in which the callback is executed. Defaults to the Component. */ onAvailable : function(id, fn, scope){ all.on("add", function(index, o){ @@ -74,6 +74,18 @@ Ext.ComponentMgr = function(){ */ all : all, + /** + * The xtypes that have been registered with the component manager. + * @type {Object} + */ + types : types, + + /** + * The ptypes that have been registered with the component manager. + * @type {Object} + */ + ptypes: ptypes, + /** * Checks if a Component type is registered. * @param {Ext.Component} xtype The mnemonic string by which the Component class may be looked up @@ -82,6 +94,15 @@ Ext.ComponentMgr = function(){ isRegistered : function(xtype){ return types[xtype] !== undefined; }, + + /** + * Checks if a Plugin type is registered. + * @param {Ext.Component} ptype The mnemonic string by which the Plugin class may be looked up + * @return {Boolean} Whether the type is registered. + */ + isPluginRegistered : function(ptype){ + return ptypes[ptype] !== undefined; + }, /** *

Registers a new Component constructor, keyed by a new @@ -103,7 +124,7 @@ Ext.ComponentMgr = function(){ * config object's {@link Ext.component#xtype xtype} to determine the class to instantiate. * @param {Object} config A configuration object for the Component you wish to create. * @param {Constructor} defaultType The constructor to provide the default Component type if - * the config object does not contain a xtype. (Optional if the config contains a xtype). + * the config object does not contain a xtype. (Optional if the config contains a xtype). * @return {Ext.Component} The newly instantiated Component. */ create : function(config, defaultType){ @@ -129,11 +150,16 @@ Ext.ComponentMgr = function(){ * config object's {@link Ext.component#ptype ptype} to determine the class to instantiate. * @param {Object} config A configuration object for the Plugin you wish to create. * @param {Constructor} defaultType The constructor to provide the default Plugin type if - * the config object does not contain a ptype. (Optional if the config contains a ptype). + * the config object does not contain a ptype. (Optional if the config contains a ptype). * @return {Ext.Component} The newly instantiated Plugin. */ createPlugin : function(config, defaultType){ - return new ptypes[config.ptype || defaultType](config); + var PluginCls = ptypes[config.ptype || defaultType]; + if (PluginCls.init) { + return PluginCls; + } else { + return new PluginCls(config); + } } }; }(); @@ -156,8 +182,18 @@ Ext.reg = Ext.ComponentMgr.registerType; // this will be called a lot internally * @method preg */ Ext.preg = Ext.ComponentMgr.registerPlugin; -Ext.create = Ext.ComponentMgr.create; /** + * Shorthand for {@link Ext.ComponentMgr#create} + * Creates a new Component from the specified config object using the + * config object's {@link Ext.component#xtype xtype} to determine the class to instantiate. + * @param {Object} config A configuration object for the Component you wish to create. + * @param {Constructor} defaultType The constructor to provide the default Component type if + * the config object does not contain a xtype. (Optional if the config contains a xtype). + * @return {Ext.Component} The newly instantiated Component. + * @member Ext + * @method create + */ +Ext.create = Ext.ComponentMgr.create;/** * @class Ext.Component * @extends Ext.util.Observable *

Base class for all Ext components. All subclasses of Component may participate in the automated @@ -226,7 +262,7 @@ menutextitem {@link Ext.menu.TextItem} Form components --------------------------------------- -form {@link Ext.FormPanel} +form {@link Ext.form.FormPanel} checkbox {@link Ext.form.Checkbox} checkboxgroup {@link Ext.form.CheckboxGroup} combo {@link Ext.form.ComboBox} @@ -295,6 +331,14 @@ Ext.Component = function(config){ Ext.apply(this, config); this.addEvents( + /** + * @event added + * Fires when a component is added to an Ext.Container + * @param {Ext.Component} this + * @param {Ext.Container} ownerCt Container which holds the component + * @param {number} index Position at which the component was added + */ + 'added', /** * @event disable * Fires after the component is disabled. @@ -334,6 +378,13 @@ Ext.Component = function(config){ * @param {Ext.Component} this */ 'hide', + /** + * @event removed + * Fires when a component is removed from an Ext.Container + * @param {Ext.Component} this + * @param {Ext.Container} ownerCt Container which holds the component + */ + 'removed', /** * @event beforerender * Fires before the component is {@link #rendered}. Return false from an @@ -429,7 +480,7 @@ Ext.Component = function(config){ } if(this.stateful !== false){ - this.initState(config); + this.initState(); } if(this.applyTo){ @@ -445,7 +496,7 @@ Ext.Component = function(config){ Ext.Component.AUTO_ID = 1000; Ext.extend(Ext.Component, Ext.util.Observable, { - // Configs below are used for all Components when rendered by FormLayout. + // Configs below are used for all Components when rendered by FormLayout. /** * @cfg {String} fieldLabel

The label text to display next to this Component (defaults to '').

*

Note: this config is only used when this Component is rendered by a Container which @@ -544,7 +595,11 @@ new Ext.FormPanel({ *

See {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl} also.

*/ /** - * @cfg {String} itemCls

An additional CSS class to apply to the div wrapping the form item + * @cfg {String} itemCls + *

Note: this config is only used when this Component is rendered by a Container which + * has been configured to use the {@link Ext.layout.FormLayout FormLayout} layout manager (e.g. + * {@link Ext.form.FormPanel} or specifying layout:'form').


+ *

An additional CSS class to apply to the div wrapping the form item * element of this field. If supplied, itemCls at the field level will override * the default itemCls supplied at the container level. The value specified for * itemCls will be added to the default class ('x-form-item').

@@ -554,35 +609,24 @@ new Ext.FormPanel({ * any other element within the markup for the field.

*

Note: see the note for {@link #fieldLabel}.


* Example use:

-// Apply a style to the field's label:
+// Apply a style to the field's label:
 <style>
     .required .x-form-item-label {font-weight:bold;color:red;}
 </style>
 
 new Ext.FormPanel({
-	height: 100,
-	renderTo: Ext.getBody(),
-	items: [{
-		xtype: 'textfield',
-		fieldLabel: 'Name',
-		itemCls: 'required' //this label will be styled
-	},{
-		xtype: 'textfield',
-		fieldLabel: 'Favorite Color'
-	}]
+    height: 100,
+    renderTo: Ext.getBody(),
+    items: [{
+        xtype: 'textfield',
+        fieldLabel: 'Name',
+        itemCls: 'required' //this label will be styled
+    },{
+        xtype: 'textfield',
+        fieldLabel: 'Favorite Color'
+    }]
 });
 
- */ - - // Configs below are used for all Components when rendered by AnchorLayout. - /** - * @cfg {String} anchor

Note: this config is only used when this Component is rendered - * by a Container which has been configured to use an {@link Ext.layout.AnchorLayout AnchorLayout} - * based layout manager, for example:

- *

See {@link Ext.layout.AnchorLayout}.{@link Ext.layout.AnchorLayout#anchor anchor} also.

*/ /** @@ -913,29 +957,76 @@ new Ext.Panel({ * @property el */ /** - * The component's owner {@link Ext.Container} (defaults to undefined, and is set automatically when - * the component is added to a container). Read-only. - *

Note: to access items within the container see {@link #itemId}.

+ * This Component's owner {@link Ext.Container Container} (defaults to undefined, and is set automatically when + * this Component is added to a Container). Read-only. + *

Note: to access items within the Container see {@link #itemId}.

* @type Ext.Container * @property ownerCt */ /** * True if this component is hidden. Read-only. * @type Boolean - * @property + * @property hidden */ /** * True if this component is disabled. Read-only. * @type Boolean - * @property + * @property disabled */ /** * True if this component has been rendered. Read-only. * @type Boolean - * @property + * @property rendered */ rendered : false, + /** + * @cfg {String} contentEl + *

Optional. Specify an existing HTML element, or the id of an existing HTML element to use as the content + * for this component.

+ * + */ + /** + * @cfg {String/Object} html + * An HTML fragment, or a {@link Ext.DomHelper DomHelper} specification to use as the layout element + * content (defaults to ''). The HTML content is added after the component is rendered, + * so the document will not contain this HTML at the time the {@link #render} event is fired. + * This content is inserted into the body before any configured {@link #contentEl} is appended. + */ + + /** + * @cfg {Mixed} tpl + * An {@link Ext.Template}, {@link Ext.XTemplate} + * or an array of strings to form an Ext.XTemplate. + * Used in conjunction with the {@link #data} and + * {@link #tplWriteMode} configurations. + */ + + /** + * @cfg {String} tplWriteMode The Ext.(X)Template method to use when + * updating the content area of the Component. Defaults to 'overwrite' + * (see {@link Ext.XTemplate#overwrite}). + */ + tplWriteMode : 'overwrite', + + /** + * @cfg {Mixed} data + * The initial set of data to apply to the {@link #tpl} to + * update the content area of the Component. + */ + + // private ctype : 'Ext.Component', @@ -1051,7 +1142,32 @@ Ext.Foo = Ext.extend(Ext.Bar, { this.el.addClassOnOver(this.overCls); } this.fireEvent('render', this); + + + // Populate content of the component with html, contentEl or + // a tpl. + var contentTarget = this.getContentTarget(); + if (this.html){ + contentTarget.update(Ext.DomHelper.markup(this.html)); + delete this.html; + } + if (this.contentEl){ + var ce = Ext.getDom(this.contentEl); + Ext.fly(ce).removeClass(['x-hidden', 'x-hide-display']); + contentTarget.appendChild(ce); + } + if (this.tpl) { + if (!this.tpl.compile) { + this.tpl = new Ext.XTemplate(this.tpl); + } + if (this.data) { + this.tpl[this.tplWriteMode](contentTarget, this.data); + delete this.data; + } + } this.afterRender(this.container); + + if(this.hidden){ // call this so we don't fire initial hide events. this.doHide(); @@ -1064,17 +1180,70 @@ Ext.Foo = Ext.extend(Ext.Bar, { if(this.stateful !== false){ this.initStateEvents(); } - this.initRef(); this.fireEvent('afterrender', this); } return this; }, - initRef : function(){ + + /** + * Update the content area of a component. + * @param {Mixed} htmlOrData + * If this component has been configured with a template via the tpl config + * then it will use this argument as data to populate the template. + * If this component was not configured with a template, the components + * content area will be updated via Ext.Element update + * @param {Boolean} loadScripts + * (optional) Only legitimate when using the html configuration. Defaults to false + * @param {Function} callback + * (optional) Only legitimate when using the html configuration. Callback to execute when scripts have finished loading + */ + update: function(htmlOrData, loadScripts, cb) { + var contentTarget = this.getContentTarget(); + if (this.tpl && typeof htmlOrData !== "string") { + this.tpl[this.tplWriteMode](contentTarget, htmlOrData || {}); + } else { + var html = Ext.isObject(htmlOrData) ? Ext.DomHelper.markup(htmlOrData) : htmlOrData; + contentTarget.update(html, loadScripts, cb); + } + }, + + + /** + * @private + * Method to manage awareness of when components are added to their + * respective Container, firing an added event. + * References are established at add time rather than at render time. + * @param {Ext.Container} container Container which holds the component + * @param {number} pos Position at which the component was added + */ + onAdded : function(container, pos) { + this.ownerCt = container; + this.initRef(); + this.fireEvent('added', this, container, pos); + }, + + /** + * @private + * Method to manage awareness of when components are removed from their + * respective Container, firing an removed event. References are properly + * cleaned up after removing a component from its owning container. + */ + onRemoved : function() { + this.removeRef(); + this.fireEvent('removed', this, this.ownerCt); + delete this.ownerCt; + }, + + /** + * @private + * Method to establish a reference to a component. + */ + initRef : function() { /** * @cfg {String} ref - *

A path specification, relative to the Component's {@link #ownerCt} specifying into which - * ancestor Container to place a named reference to this Component.

+ *

A path specification, relative to the Component's {@link #ownerCt} + * specifying into which ancestor Container to place a named reference to this Component.

*

The ancestor axis can be traversed by using '/' characters in the path. * For example, to put a reference to a Toolbar Button into the Panel which owns the Toolbar:


 var myGrid = new Ext.grid.EditorGridPanel({
@@ -1095,33 +1264,50 @@ var myGrid = new Ext.grid.EditorGridPanel({
     }
 });
 
- *

In the code above, if the ref had been 'saveButton' the reference would - * have been placed into the Toolbar. Each '/' in the ref moves up one level from the - * Component's {@link #ownerCt}.

+ *

In the code above, if the ref had been 'saveButton' + * the reference would have been placed into the Toolbar. Each '/' in the ref + * moves up one level from the Component's {@link #ownerCt}.

+ *

Also see the {@link #added} and {@link #removed} events.

*/ - if(this.ref){ - var levels = this.ref.split('/'); - var last = levels.length, i = 0; - var t = this; - while(i < last){ - if(t.ownerCt){ - t = t.ownerCt; - } - i++; + if(this.ref && !this.refOwner){ + var levels = this.ref.split('/'), + last = levels.length, + i = 0, + t = this; + + while(t && i < last){ + t = t.ownerCt; + ++i; } - t[levels[--i]] = this; + if(t){ + t[this.refName = levels[--i]] = this; + /** + * @type Ext.Container + * @property refOwner + * The ancestor Container into which the {@link #ref} reference was inserted if this Component + * is a child of a Container, and has been configured with a ref. + */ + this.refOwner = t; + } + } + }, + + removeRef : function() { + if (this.refOwner && this.refName) { + delete this.refOwner[this.refName]; + delete this.refOwner; } }, // private - initState : function(config){ + initState : function(){ if(Ext.state.Manager){ var id = this.getStateId(); if(id){ var state = Ext.state.Manager.get(id); if(state){ if(this.fireEvent('beforestaterestore', this, state) !== false){ - this.applyState(state); + this.applyState(Ext.apply({}, state)); this.fireEvent('staterestore', this, state); } } @@ -1131,7 +1317,7 @@ var myGrid = new Ext.grid.EditorGridPanel({ // private getStateId : function(){ - return this.stateId || ((this.id.indexOf('ext-comp-') == 0 || this.id.indexOf('ext-gen') == 0) ? null : this.id); + return this.stateId || ((/^(ext-comp-|ext-gen)/).test(String(this.id)) ? null : this.id); }, // private @@ -1144,7 +1330,7 @@ var myGrid = new Ext.grid.EditorGridPanel({ }, // private - applyState : function(state, config){ + applyState : function(state){ if(state){ Ext.apply(this, state); } @@ -1226,6 +1412,10 @@ var myGrid = new Ext.grid.EditorGridPanel({ this.el = Ext.get(this.el); if(this.allowDomMove !== false){ ct.dom.insertBefore(this.el.dom, position); + if (div) { + Ext.removeNode(div); + div = null; + } } } }, @@ -1251,19 +1441,33 @@ var myGrid = new Ext.grid.EditorGridPanel({ * */ destroy : function(){ - if(this.fireEvent('beforedestroy', this) !== false){ - this.beforeDestroy(); - if(this.rendered){ - this.el.removeAllListeners(); - this.el.remove(); - if(this.actionMode == 'container' || this.removeMode == 'container'){ - this.container.remove(); + if(!this.isDestroyed){ + if(this.fireEvent('beforedestroy', this) !== false){ + this.destroying = true; + this.beforeDestroy(); + if(this.ownerCt && this.ownerCt.remove){ + this.ownerCt.remove(this, false); + } + if(this.rendered){ + this.el.remove(); + if(this.actionMode == 'container' || this.removeMode == 'container'){ + this.container.remove(); + } } + this.onDestroy(); + Ext.ComponentMgr.unregister(this); + this.fireEvent('destroy', this); + this.purgeListeners(); + this.destroying = false; + this.isDestroyed = true; } - this.onDestroy(); - Ext.ComponentMgr.unregister(this); - this.fireEvent('destroy', this); - this.purgeListeners(); + } + }, + + deleteMembers : function(){ + var args = arguments; + for(var i = 0, len = args.length; i < len; ++i){ + delete this[args[i]]; } }, @@ -1298,6 +1502,11 @@ new Ext.Panel({ return this.el; }, + // private + getContentTarget : function(){ + return this.el; + }, + /** * Returns the id of this component or automatically generates and * returns an id if an id is not defined yet:

@@ -1418,7 +1627,7 @@ new Ext.Panel({
 
     // private
     onShow : function(){
-        this.getVisibiltyEl().removeClass('x-hide-' + this.hideMode);
+        this.getVisibilityEl().removeClass('x-hide-' + this.hideMode);
     },
 
     /**
@@ -1446,11 +1655,11 @@ new Ext.Panel({
 
     // private
     onHide : function(){
-        this.getVisibiltyEl().addClass('x-hide-' + this.hideMode);
+        this.getVisibilityEl().addClass('x-hide-' + this.hideMode);
     },
 
     // private
-    getVisibiltyEl : function(){
+    getVisibilityEl : function(){
         return this.hideParent ? this.container : this.getActionEl();
     },
 
@@ -1468,7 +1677,7 @@ new Ext.Panel({
      * @return {Boolean} True if this component is visible, false otherwise.
      */
     isVisible : function(){
-        return this.rendered && this.getVisibiltyEl().isVisible();
+        return this.rendered && this.getVisibilityEl().isVisible();
     },
 
     /**
@@ -1579,8 +1788,9 @@ alert(t.getXTypes());  // alerts 'component/box/field/textfield'
             });
     },
 
-    getDomPositionEl : function(){
-        return this.getPositionEl ? this.getPositionEl() : this.getEl();
+    // protected
+    getPositionEl : function(){
+        return this.positionEl || this.el;
     },
 
     // private
@@ -1599,15 +1809,38 @@ alert(t.getXTypes());  // alerts 'component/box/field/textfield'
         this.mons = [];
     },
 
-    // internal function for auto removal of assigned event handlers on destruction
-    mon : function(item, ename, fn, scope, opt){
+    // private
+    createMons: function(){
         if(!this.mons){
             this.mons = [];
             this.on('beforedestroy', this.clearMons, this, {single: true});
         }
+    },
 
+    /**
+     * 

Adds listeners to any Observable object (or Elements) which are automatically removed when this Component + * is destroyed. Usage:

+myGridPanel.mon(myGridPanel.getSelectionModel(), 'selectionchange', handleSelectionChange, null, {buffer: 50});
+
+ *

or:

+myGridPanel.mon(myGridPanel.getSelectionModel(), {
+    selectionchange: handleSelectionChange,
+    buffer: 50
+});
+
+ * @param {Observable|Element} item The item to which to add a listener/listeners. + * @param {Object|String} ename The event name, or an object containing event name properties. + * @param {Function} fn Optional. If the ename parameter was an event name, this + * is the handler function. + * @param {Object} scope Optional. If the ename parameter was an event name, this + * is the scope (this reference) in which the handler function is executed. + * @param {Object} opt Optional. If the ename parameter was an event name, this + * is the {@link Ext.util.Observable#addListener addListener} options. + */ + mon : function(item, ename, fn, scope, opt){ + this.createMons(); if(Ext.isObject(ename)){ - var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/; + var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/; var o = ename; for(var e in o){ @@ -1616,31 +1849,39 @@ alert(t.getXTypes()); // alerts 'component/box/field/textfield' } if(Ext.isFunction(o[e])){ // shared options - this.mons.push({ - item: item, ename: e, fn: o[e], scope: o.scope - }); - item.on(e, o[e], o.scope, o); + this.mons.push({ + item: item, ename: e, fn: o[e], scope: o.scope + }); + item.on(e, o[e], o.scope, o); }else{ // individual options - this.mons.push({ - item: item, ename: e, fn: o[e], scope: o.scope - }); - item.on(e, o[e]); + this.mons.push({ + item: item, ename: e, fn: o[e], scope: o.scope + }); + item.on(e, o[e]); } } return; } - this.mons.push({ item: item, ename: ename, fn: fn, scope: scope }); item.on(ename, fn, scope, opt); }, - // protected, opposite of mon + /** + * Removes listeners that were added by the {@link #mon} method. + * @param {Observable|Element} item The item from which to remove a listener/listeners. + * @param {Object|String} ename The event name, or an object containing event name properties. + * @param {Function} fn Optional. If the ename parameter was an event name, this + * is the handler function. + * @param {Object} scope Optional. If the ename parameter was an event name, this + * is the scope (this reference) in which the handler function is executed. + */ mun : function(item, ename, fn, scope){ var found, mon; + this.createMons(); for(var i = 0, len = this.mons.length; i < len; ++i){ mon = this.mons[i]; if(item === mon.item && ename == mon.ename && fn === mon.fn && scope === mon.scope){ @@ -1690,8 +1931,7 @@ alert(t.getXTypes()); // alerts 'component/box/field/textfield' } }); -Ext.reg('component', Ext.Component); -/** +Ext.reg('component', Ext.Component);/** * @class Ext.Action *

An Action is a piece of reusable functionality that can be abstracted out of any particular component so that it * can be usefully shared among multiple components. Actions let you share handlers, configuration options and UI @@ -1744,13 +1984,7 @@ aRef.setText('New text'); * @constructor * @param {Object} config The configuration options */ -Ext.Action = function(config){ - this.initialConfig = config; - this.itemId = config.itemId = (config.itemId || config.id || Ext.id()); - this.items = []; -} - -Ext.Action.prototype = { +Ext.Action = Ext.extend(Object, { /** * @cfg {String} text The text to set for all components using this action (defaults to ''). */ @@ -1783,9 +2017,16 @@ Ext.Action.prototype = { * See {@link Ext.Component}.{@link Ext.Component#itemId itemId}. */ /** - * @cfg {Object} scope The scope in which the {@link #handler} function will execute. + * @cfg {Object} scope The scope (this reference) in which the + * {@link #handler} is executed. Defaults to this Button. */ + constructor : function(config){ + this.initialConfig = config; + this.itemId = config.itemId = (config.itemId || config.id || Ext.id()); + this.items = []; + }, + // private isAction : true, @@ -1885,10 +2126,10 @@ Ext.Action.prototype = { }, /** - * Sets the function that will be called by each component using this action when its primary event is triggered. + * Sets the function that will be called by each Component using this action when its primary event is triggered. * @param {Function} fn The function that will be invoked by the action's components. The function * will be called with no arguments. - * @param {Object} scope The scope in which the function will execute + * @param {Object} scope The scope (this reference) in which the function is executed. Defaults to the Component firing the event. */ setHandler : function(fn, scope){ this.initialConfig.handler = fn; @@ -1897,10 +2138,10 @@ Ext.Action.prototype = { }, /** - * Executes the specified function once for each component currently tied to this action. The function passed + * Executes the specified function once for each Component currently tied to this action. The function passed * in should accept a single argument that will be an object that supports the basic Action config/method interface. * @param {Function} fn The function to execute for each component - * @param {Object} scope The scope in which the function will execute + * @param {Object} scope The scope (this reference) in which the function is executed. Defaults to the Component. */ each : function(fn, scope){ Ext.each(this.items, fn, scope); @@ -1936,7 +2177,7 @@ Ext.Action.prototype = { execute : function(){ this.initialConfig.handler.apply(this.initialConfig.scope || window, arguments); } -}; +}); /** * @class Ext.Layer * @extends Ext.Element @@ -2107,7 +2348,7 @@ Ext.extend(Ext.Layer, Ext.Element, { } this.removeAllListeners(); Ext.removeNode(this.dom); - Ext.Element.uncache(this.id); + delete this.dom; }, remove : function(){ @@ -2396,7 +2637,8 @@ Ext.extend(Ext.Layer, Ext.Element, { return this; } }); -})();/** +})(); +/** * @class Ext.Shadow * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned, * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced @@ -2611,6 +2853,34 @@ var myImage = new Ext.BoxComponent({ */ Ext.BoxComponent = Ext.extend(Ext.Component, { + // Configs below are used for all Components when rendered by BoxLayout. + /** + * @cfg {Number} flex + *

Note: this config is only used when this Component is rendered + * by a Container which has been configured to use a {@link Ext.layout.BoxLayout BoxLayout}. + * Each child Component with a flex property will be flexed either vertically (by a VBoxLayout) + * or horizontally (by an HBoxLayout) according to the item's relative flex value + * compared to the sum of all Components with flex value specified. Any child items that have + * either a flex = 0 or flex = undefined will not be 'flexed' (the initial size will not be changed). + */ + // Configs below are used for all Components when rendered by AnchorLayout. + /** + * @cfg {String} anchor

Note: this config is only used when this Component is rendered + * by a Container which has been configured to use an {@link Ext.layout.AnchorLayout AnchorLayout} (or subclass thereof). + * based layout manager, for example:

    + *
  • {@link Ext.form.FormPanel}
  • + *
  • specifying layout: 'anchor' // or 'form', or 'absolute'
  • + *

+ *

See {@link Ext.layout.AnchorLayout}.{@link Ext.layout.AnchorLayout#anchor anchor} also.

+ */ + // tabTip config is used when a BoxComponent is a child of a TabPanel + /** + * @cfg {String} tabTip + *

Note: this config is only used when this BoxComponent is a child item of a TabPanel.

+ * A string to be used as innerHTML (html tags are accepted) to show in a tooltip when mousing over + * the associated tab selector element. {@link Ext.QuickTips}.init() + * must be called in order for the tips to render. + */ // Configs below are used for all Components when rendered by BorderLayout. /** * @cfg {String} region

Note: this config is only used when this BoxComponent is rendered @@ -2671,6 +2941,26 @@ Ext.BoxComponent = Ext.extend(Ext.Component, { * The width of this component in pixels (defaults to auto). * Note to express this dimension as a percentage or offset see {@link Ext.Component#anchor}. */ + /** + * @cfg {Number} boxMinHeight + *

The minimum value in pixels which this BoxComponent will set its height to.

+ *

Warning: This will override any size management applied by layout managers.

+ */ + /** + * @cfg {Number} boxMinWidth + *

The minimum value in pixels which this BoxComponent will set its width to.

+ *

Warning: This will override any size management applied by layout managers.

+ */ + /** + * @cfg {Number} boxMaxHeight + *

The maximum value in pixels which this BoxComponent will set its height to.

+ *

Warning: This will override any size management applied by layout managers.

+ */ + /** + * @cfg {Number} boxMaxWidth + *

The maximum value in pixels which this BoxComponent will set its width to.

+ *

Warning: This will override any size management applied by layout managers.

+ */ /** * @cfg {Boolean} autoHeight *

True to use height:'auto', false to use fixed height (or allow it to be managed by its parent @@ -2745,6 +3035,11 @@ var myPanel = new Ext.Panel({ });

*/ + /** + * @cfg {Boolean} autoScroll + * true to use overflow:'auto' on the components layout element and show scroll bars automatically when + * necessary, false to clip any overflowing content (defaults to false). + */ /* // private internal config * {Boolean} deferHeight @@ -2800,15 +3095,26 @@ var myPanel = new Ext.Panel({ * @return {Ext.BoxComponent} this */ setSize : function(w, h){ + // support for standard size objects if(typeof w == 'object'){ - h = w.height; - w = w.width; + h = w.height, w = w.width; + } + if (Ext.isDefined(w) && Ext.isDefined(this.boxMinWidth) && (w < this.boxMinWidth)) { + w = this.boxMinWidth; + } + if (Ext.isDefined(h) && Ext.isDefined(this.boxMinHeight) && (h < this.boxMinHeight)) { + h = this.boxMinHeight; + } + if (Ext.isDefined(w) && Ext.isDefined(this.boxMaxWidth) && (w > this.boxMaxWidth)) { + w = this.boxMaxWidth; + } + if (Ext.isDefined(h) && Ext.isDefined(this.boxMaxHeight) && (h > this.boxMaxHeight)) { + h = this.boxMaxHeight; } // not rendered if(!this.boxReady){ - this.width = w; - this.height = h; + this.width = w, this.height = h; return this; } @@ -2817,10 +3123,12 @@ var myPanel = new Ext.Panel({ return this; } this.lastSize = {width: w, height: h}; - var adj = this.adjustSize(w, h); - var aw = adj.width, ah = adj.height; + var adj = this.adjustSize(w, h), + aw = adj.width, + ah = adj.height, + rz; if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters - var rz = this.getResizeEl(); + rz = this.getResizeEl(); if(!this.deferHeight && aw !== undefined && ah !== undefined){ rz.setSize(aw, ah); }else if(!this.deferHeight && ah !== undefined){ @@ -2939,14 +3247,23 @@ var myPanel = new Ext.Panel({ * contains both the <input> Element (which is what would be returned * by its {@link #getEl} method, and the trigger button Element. * This Element is returned as the resizeEl. + * @return {Ext.Element} The Element which is to be resized by size managing layouts. */ getResizeEl : function(){ return this.resizeEl || this.el; }, - // protected - getPositionEl : function(){ - return this.positionEl || this.el; + /** + * Sets the overflow on the content element of the component. + * @param {Boolean} scroll True to allow the Component to auto scroll. + * @return {Ext.BoxComponent} this + */ + setAutoScroll : function(scroll){ + if(this.rendered){ + this.getContentTarget().setOverflow(scroll ? 'auto' : ''); + } + this.autoScroll = scroll; + return this; }, /** @@ -3010,20 +3327,16 @@ var myPanel = new Ext.Panel({ }, // private - onRender : function(ct, position){ - Ext.BoxComponent.superclass.onRender.call(this, ct, position); + afterRender : function(){ + Ext.BoxComponent.superclass.afterRender.call(this); if(this.resizeEl){ this.resizeEl = Ext.get(this.resizeEl); } if(this.positionEl){ this.positionEl = Ext.get(this.positionEl); } - }, - - // private - afterRender : function(){ - Ext.BoxComponent.superclass.afterRender.call(this); this.boxReady = true; + Ext.isDefined(this.autoScroll) && this.setAutoScroll(this.autoScroll); this.setSize(this.width, this.height); if(this.x || this.y){ this.setPosition(this.x, this.y); @@ -3051,7 +3364,6 @@ var myPanel = new Ext.Panel({ * @param {Number} rawHeight The height that was originally specified */ onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){ - }, /* // protected @@ -3113,12 +3425,12 @@ split.on('moved', splitterMoved); * @param {Mixed} dragElement The element to be dragged and act as the SplitBar. * @param {Mixed} resizingElement The element to be resized based on where the SplitBar element is dragged * @param {Number} orientation (optional) Either Ext.SplitBar.HORIZONTAL or Ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL) - * @param {Number} placement (optional) Either Ext.SplitBar.LEFT or Ext.SplitBar.RIGHT for horizontal or + * @param {Number} placement (optional) Either Ext.SplitBar.LEFT or Ext.SplitBar.RIGHT for horizontal or Ext.SplitBar.TOP or Ext.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial position of the SplitBar). */ Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){ - + /** @private */ this.el = Ext.get(dragElement, true); this.el.dom.unselectable = "on"; @@ -3132,7 +3444,7 @@ Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, ex * @type Number */ this.orientation = orientation || Ext.SplitBar.HORIZONTAL; - + /** * The increment, in pixels by which to move this SplitBar. When undefined, the SplitBar moves smoothly. * @type Number @@ -3143,28 +3455,28 @@ Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, ex * @type Number */ this.minSize = 0; - + /** * The maximum size of the resizing element. (Defaults to 2000) * @type Number */ this.maxSize = 2000; - + /** * Whether to animate the transition to the new size * @type Boolean */ this.animate = false; - + /** * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes. * @type Boolean */ this.useShim = false; - + /** @private */ this.shim = null; - + if(!existingProxy){ /** @private */ this.proxy = Ext.SplitBar.createProxy(this.orientation); @@ -3173,22 +3485,22 @@ Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, ex } /** @private */ this.dd = new Ext.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id}); - + /** @private */ this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this); - + /** @private */ this.dd.endDrag = this.onEndProxyDrag.createDelegate(this); - + /** @private */ this.dragSpecs = {}; - + /** * @private The adapter to use to positon and resize elements */ this.adapter = new Ext.SplitBar.BasicLayoutAdapter(); this.adapter.init(this); - + if(this.orientation == Ext.SplitBar.HORIZONTAL){ /** @private */ this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Ext.SplitBar.LEFT : Ext.SplitBar.RIGHT); @@ -3198,7 +3510,7 @@ Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, ex this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Ext.SplitBar.TOP : Ext.SplitBar.BOTTOM); this.el.addClass("x-splitbar-v"); } - + this.addEvents( /** * @event resize @@ -3243,7 +3555,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, { if(this.orientation == Ext.SplitBar.HORIZONTAL){ this.dd.resetConstraints(); this.dd.setXConstraint( - this.placement == Ext.SplitBar.LEFT ? c1 : c2, + this.placement == Ext.SplitBar.LEFT ? c1 : c2, this.placement == Ext.SplitBar.LEFT ? c2 : c1, this.tickSize ); @@ -3252,7 +3564,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, { this.dd.resetConstraints(); this.dd.setXConstraint(0, 0); this.dd.setYConstraint( - this.placement == Ext.SplitBar.TOP ? c1 : c2, + this.placement == Ext.SplitBar.TOP ? c1 : c2, this.placement == Ext.SplitBar.TOP ? c2 : c1, this.tickSize ); @@ -3261,8 +3573,8 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, { this.dragSpecs.startPoint = [x, y]; Ext.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y); }, - - /** + + /** * @private Called after the drag operation by the DDProxy */ onEndProxyDrag : function(e){ @@ -3274,13 +3586,13 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, { } var newSize; if(this.orientation == Ext.SplitBar.HORIZONTAL){ - newSize = this.dragSpecs.startSize + + newSize = this.dragSpecs.startSize + (this.placement == Ext.SplitBar.LEFT ? endPoint[0] - this.dragSpecs.startPoint[0] : this.dragSpecs.startPoint[0] - endPoint[0] ); }else{ - newSize = this.dragSpecs.startSize + + newSize = this.dragSpecs.startSize + (this.placement == Ext.SplitBar.TOP ? endPoint[1] - this.dragSpecs.startPoint[1] : this.dragSpecs.startPoint[1] - endPoint[1] @@ -3295,7 +3607,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, { } } }, - + /** * Get the adapter this SplitBar uses * @return The adapter object @@ -3303,7 +3615,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, { getAdapter : function(){ return this.adapter; }, - + /** * Set the adapter this SplitBar uses * @param {Object} adapter A SplitBar adapter object @@ -3312,7 +3624,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, { this.adapter = adapter; this.adapter.init(this); }, - + /** * Gets the minimum size for the resizing element * @return {Number} The minimum size @@ -3320,7 +3632,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, { getMinimumSize : function(){ return this.minSize; }, - + /** * Sets the minimum size for the resizing element * @param {Number} minSize The minimum size @@ -3328,7 +3640,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, { setMinimumSize : function(minSize){ this.minSize = minSize; }, - + /** * Gets the maximum size for the resizing element * @return {Number} The maximum size @@ -3336,7 +3648,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, { getMaximumSize : function(){ return this.maxSize; }, - + /** * Sets the maximum size for the resizing element * @param {Number} maxSize The maximum size @@ -3344,7 +3656,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, { setMaximumSize : function(maxSize){ this.maxSize = maxSize; }, - + /** * Sets the initialize size for the resizing element * @param {Number} size The initial size @@ -3355,18 +3667,18 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, { this.adapter.setElementSize(this, size); this.animate = oldAnimate; }, - + /** - * Destroy this splitbar. + * Destroy this splitbar. * @param {Boolean} removeEl True to remove the element */ destroy : function(removeEl){ - Ext.destroy(this.shim, Ext.get(this.proxy)); + Ext.destroy(this.shim, Ext.get(this.proxy)); this.dd.unreg(); if(removeEl){ this.el.remove(); } - this.purgeListeners(); + this.purgeListeners(); } }); @@ -3375,14 +3687,14 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, { */ Ext.SplitBar.createProxy = function(dir){ var proxy = new Ext.Element(document.createElement("div")); + document.body.appendChild(proxy.dom); proxy.unselectable(); var cls = 'x-splitbar-proxy'; proxy.addClass(cls + ' ' + (dir == Ext.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v')); - document.body.appendChild(proxy.dom); return proxy.dom; }; -/** +/** * @class Ext.SplitBar.BasicLayoutAdapter * Default Adapter. It assumes the splitter and resizing element are not positioned * elements and only gets/sets the width of the element. Generally used for table based layouts. @@ -3393,10 +3705,10 @@ Ext.SplitBar.BasicLayoutAdapter = function(){ Ext.SplitBar.BasicLayoutAdapter.prototype = { // do nothing for now init : function(s){ - + }, /** - * Called before drag operations to get the current size of the resizing element. + * Called before drag operations to get the current size of the resizing element. * @param {Ext.SplitBar} s The SplitBar using this adapter */ getElementSize : function(s){ @@ -3406,7 +3718,7 @@ Ext.SplitBar.BasicLayoutAdapter.prototype = { return s.resizingEl.getHeight(); } }, - + /** * Called after drag operations to set the size of the resizing element. * @param {Ext.SplitBar} s The SplitBar using this adapter @@ -3424,7 +3736,7 @@ Ext.SplitBar.BasicLayoutAdapter.prototype = { s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut'); } }else{ - + if(!s.animate){ s.resizingEl.setHeight(newSize); if(onComplete){ @@ -3437,10 +3749,10 @@ Ext.SplitBar.BasicLayoutAdapter.prototype = { } }; -/** +/** *@class Ext.SplitBar.AbsoluteLayoutAdapter * @extends Ext.SplitBar.BasicLayoutAdapter - * Adapter that moves the splitter element to align with the resized sizing element. + * Adapter that moves the splitter element to align with the resized sizing element. * Used with an absolute positioned SplitBar. * @param {Mixed} container The container that wraps around the absolute positioned content. If it's * document.body, make sure you assign an id to the body element. @@ -3454,15 +3766,15 @@ Ext.SplitBar.AbsoluteLayoutAdapter.prototype = { init : function(s){ this.basic.init(s); }, - + getElementSize : function(s){ return this.basic.getElementSize(s); }, - + setElementSize : function(s, newSize, onComplete){ this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s])); }, - + moveSplitter : function(s){ var yes = Ext.SplitBar; switch(s.placement){ @@ -3532,12 +3844,12 @@ Ext.SplitBar.BOTTOM = 4; *

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
@@ -3582,7 +3894,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 @@ -3608,12 +3920,11 @@ 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

* @@ -3641,7 +3952,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){
@@ -3681,10 +3992,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.

* @@ -3699,11 +4010,12 @@ Ext.Container = Ext.extend(Ext.BoxComponent, { */ /** * @cfg {String/Object} layout - * When creating complex UIs, it is important to remember that sizing and - * positioning of child items is the responsibility of the Container's - * layout manager. If you expect child items to be sized in response to - * user interactions, you must specify a layout manager which - * creates and manages the type of layout you have in mind. For example:

+     * 

*Important: In order for child items to be correctly sized and + * positioned, typically a layout manager must be specified through + * the layout configuration option.

+ *

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:


 new Ext.Window({
     width:300, height: 300,
     layout: 'fit', // explicitly set layout manager: override the default (layout:'auto')
@@ -3712,13 +4024,17 @@ new Ext.Window({
     }]
 }).show();
      * 
- *

Omitting the {@link #layout} config means that 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).

- *

The layout manager class for this container may be specified as either as an - * Object or as a String:

- *
    + *

    If the {@link #layout} configuration is not explicitly specified for + * 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). + * Some container classes implicitly specify a default layout + * (e.g. FormPanel specifies layout:'form'). Other specific + * purpose classes internally specify/manage their internal layout (e.g. + * GridPanel, TabPanel, TreePanel, Toolbar, Menu, etc.).

    + *

    layout may be specified as either as an Object or + * as a String:

      * *
    • Specify as an Object
    • *
        @@ -3731,31 +4047,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.

    * * @@ -3770,13 +4086,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.

    * */ /** @@ -3787,12 +4103,13 @@ 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, - + // Deprecated - will be removed in 3.2.x + bufferResize: 50, + /** * @cfg {String/Number} activeItem * A string component id or the numeric index of the component that should be initially activated within the @@ -3803,7 +4120,7 @@ layoutConfig: { */ /** * @cfg {Object/Array} items - *
    ** IMPORTANT: be sure to specify a {@link #layout} ! **
    + *
    ** IMPORTANT: be sure to {@link #layout specify a layout} if needed ! **
    *

    A single item, or an array of child Components to be added to this container, * for example:

    *
    
    @@ -3840,14 +4157,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
     },
    @@ -3885,11 +4206,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); @@ -3938,7 +4272,7 @@ items: [ 'remove' ); - this.enableBubble('add', 'remove'); + this.enableBubble(this.bubbleEvents); /** * The collection of components in this container as a {@link Ext.util.MixedCollection} @@ -3948,11 +4282,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); } }, @@ -3974,29 +4304,36 @@ 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(){ + // Render this Container, this should be done before setLayout is called which + // will hook onResize + Ext.Container.superclass.afterRender.call(this); + 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); - } + // If a CardLayout, the active item set + if(this.activeItem !== undefined){ + var item = this.activeItem; + delete this.activeItem; + this.layout.setActiveItem(item); } + + // If we have no ownerCt, render and size all children if(!this.ownerCt){ - // force a layout if no ownerCt is set this.doLayout(false, true); } + + // This is a manually configured flag set by users in conjunction with renderTo. + // Not to be confused with the flag by the same name used in Layouts. if(this.monitorResize === true){ Ext.EventManager.onWindowResize(this.doLayout, this, [false]); } @@ -4029,10 +4366,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
      @@ -4055,21 +4392,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
      @@ -4092,20 +4448,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;
      @@ -4113,14 +4470,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;
      @@ -4148,19 +4509,35 @@ 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){
      +        var l = this.layout,
      +            hasLayout = l && this.rendered;
      +
      +        if(hasLayout){
      +            l.onRemove(c);
      +        }
      +        this.items.remove(c);
      +        c.onRemoved();
      +        this.onRemove(c);
      +        if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){
      +            c.destroy();
      +        }
      +        if(hasLayout){
      +            l.afterRemove(c);
      +        }
      +    },
      +
           /**
            * Removes all components from this container.
            * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
      @@ -4188,9 +4565,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}. @@ -4198,14 +4575,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); @@ -4214,8 +4591,25 @@ 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. + */ + + // private + canLayout : function() { + var el = this.getVisibilityEl(); + return el && el.dom && !el.isStyle("display", "none"); }, /** @@ -4226,13 +4620,14 @@ tb.{@link #doLayout}(); // refresh the layout * @param {Boolean} force (optional) True to force a layout to occur, even if the item is hidden. * @return {Ext.Container} this */ - doLayout: function(shallow, force){ + + doLayout : function(shallow, force){ var rendered = this.rendered, - forceLayout = this.forceLayout; + forceLayout = force || this.forceLayout; - if(!this.isVisible() || this.collapsed){ + if(this.collapsed || !this.canLayout()){ this.deferLayout = this.deferLayout || !shallow; - if(!(force || forceLayout)){ + if(!forceLayout){ return; } shallow = shallow && !this.deferLayout; @@ -4247,23 +4642,55 @@ tb.{@link #doLayout}(); // refresh the layout for(var i = 0, len = cs.length; i < len; i++){ var c = cs[i]; if(c.doLayout){ - c.forceLayout = forceLayout; - c.doLayout(); + c.doLayout(false, forceLayout); } } } if(rendered){ - this.onLayout(shallow, force); + this.onLayout(shallow, forceLayout); } + // Initial layout completed + this.hasLayout = true; delete this.forceLayout; }, - //private onLayout : Ext.emptyFn, + // private + shouldBufferLayout: function(){ + /* + * Returns true if the container should buffer a layout. + * This is true only if the container has previously been laid out + * and has a parent container that is pending a layout. + */ + var hl = this.hasLayout; + if(this.ownerCt){ + // Only ever buffer if we've laid out the first time and we have one pending. + return hl ? !this.hasLayoutPending() : false; + } + // Never buffer initial layout + return hl; + }, + + // private + hasLayoutPending: function(){ + // Traverse hierarchy to see if any parent container has a pending layout. + var pending = false; + this.ownerCt.bubble(function(c){ + if(c.layoutPending){ + pending = true; + return false; + } + }); + return pending; + }, + onShow : function(){ + // removes css classes that were added to hide Ext.Container.superclass.onShow.call(this); - if(this.deferLayout !== undefined){ + // If we were sized during the time we were hidden, layout. + if(Ext.isDefined(this.deferLayout)){ + delete this.deferLayout; this.doLayout(true); } }, @@ -4283,8 +4710,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); @@ -4413,20 +4843,10 @@ Ext.Container.LAYOUTS = {}; Ext.reg('container', Ext.Container); /** * @class Ext.layout.ContainerLayout - *

      The ContainerLayout class is the default layout manager delegated by {@link Ext.Container} to - * render any child Components when no {@link Ext.Container#layout layout} is configured into - * a {@link Ext.Container Container}. ContainerLayout provides the basic foundation for all other layout - * classes in Ext. It simply renders all child Components into the Container, performing no sizing or - * positioning services. To utilize a layout that provides sizing and positioning of child Components, - * specify an appropriate {@link Ext.Container#layout layout}.

      *

      This class is intended to be extended or created via the {@link Ext.Container#layout layout} * configuration property. See {@link Ext.Container#layout} for additional details.

      */ -Ext.layout.ContainerLayout = function(config){ - Ext.apply(this, config); -}; - -Ext.layout.ContainerLayout.prototype = { +Ext.layout.ContainerLayout = Ext.extend(Object, { /** * @cfg {String} extraCls *

      An optional extra CSS class that will be added to the container. This can be useful for adding @@ -4466,11 +4886,49 @@ Ext.layout.ContainerLayout.prototype = { // private activeItem : null, + constructor : function(config){ + this.id = Ext.id(null, 'ext-layout-'); + Ext.apply(this, config); + }, + + type: 'container', + + /* Workaround for how IE measures autoWidth elements. It prefers bottom-up measurements + whereas other browser prefer top-down. We will hide all target child elements before we measure and + put them back to get an accurate measurement. + */ + IEMeasureHack : function(target, viewFlag) { + var tChildren = target.dom.childNodes, tLen = tChildren.length, c, d = [], e, i, ret; + for (i = 0 ; i < tLen ; i++) { + c = tChildren[i]; + e = Ext.get(c); + if (e) { + d[i] = e.getStyle('display'); + e.setStyle({display: 'none'}); + } + } + ret = target ? target.getViewSize(viewFlag) : {}; + for (i = 0 ; i < tLen ; i++) { + c = tChildren[i]; + e = Ext.get(c); + if (e) { + e.setStyle({display: d[i]}); + } + } + return ret; + }, + + // Placeholder for the derived layouts + getLayoutTargetSize : Ext.EmptyFn, + // private layout : function(){ - var target = this.container.getLayoutTarget(); - this.onLayout(this.container, target); - this.container.fireEvent('afterlayout', this.container, this); + var ct = this.container, target = ct.getLayoutTarget(); + if(!(this.hasLayout || Ext.isEmpty(this.targetCls))){ + target.addClass(this.targetCls); + } + this.onLayout(ct, target); + ct.fireEvent('afterlayout', ct, this); }, // private @@ -4480,14 +4938,14 @@ Ext.layout.ContainerLayout.prototype = { // private isValidParent : function(c, target){ - return target && c.getDomPositionEl().dom.parentNode == (target.dom || target); + return target && c.getPositionEl().dom.parentNode == (target.dom || target); }, // private renderAll : function(ct, target){ - var items = ct.items.items; - for(var i = 0, len = items.length; i < len; i++) { - var c = items[i]; + var items = ct.items.items, i, c, len = items.length; + for(i = 0; i < len; i++) { + c = items[i]; if(c && (!c.rendered || !this.isValidParent(c, target))){ this.renderItem(c, i, target); } @@ -4496,69 +4954,117 @@ Ext.layout.ContainerLayout.prototype = { // private renderItem : function(c, position, target){ - if(c && !c.rendered){ - c.render(target, position); - this.configureItem(c, position); - }else if(c && !this.isValidParent(c, target)){ - if(typeof position == 'number'){ - position = target.dom.childNodes[position]; + if(c){ + if(!c.rendered){ + c.render(target, position); + this.configureItem(c, position); + }else if(!this.isValidParent(c, target)){ + if(Ext.isNumber(position)){ + position = target.dom.childNodes[position]; + } + target.dom.insertBefore(c.getPositionEl().dom, position || null); + c.container = target; + this.configureItem(c, position); } - target.dom.insertBefore(c.getDomPositionEl().dom, position || null); - c.container = target; - this.configureItem(c, position); } }, - + + // private. + // Get all rendered items to lay out. + getRenderedItems: function(ct){ + var t = ct.getLayoutTarget(), cti = ct.items.items, len = cti.length, i, c, items = []; + for (i = 0; i < len; i++) { + if((c = cti[i]).rendered && this.isValidParent(c, t)){ + items.push(c); + } + }; + return items; + }, + // private configureItem: function(c, position){ if(this.extraCls){ var t = c.getPositionEl ? c.getPositionEl() : c; t.addClass(this.extraCls); } + // If we are forcing a layout, do so *before* we hide so elements have height/width + if(c.doLayout && this.forceLayout){ + c.doLayout(); + } if (this.renderHidden && c != this.activeItem) { c.hide(); } - if(c.doLayout){ - c.doLayout(false, this.forceLayout); + }, + + onRemove: function(c){ + if(this.activeItem == c){ + delete this.activeItem; + } + if(c.rendered && this.extraCls){ + var t = c.getPositionEl ? c.getPositionEl() : c; + t.removeClass(this.extraCls); + } + }, + + afterRemove: function(c){ + if(c.removeRestore){ + c.removeMode = 'container'; + delete c.removeRestore; } }, // private onResize: function(){ - if(this.container.collapsed){ + var ct = this.container, + b; + if(ct.collapsed){ return; } - var b = this.container.bufferResize; - if(b){ - if(!this.resizeTask){ - this.resizeTask = new Ext.util.DelayedTask(this.runLayout, this); - this.resizeBuffer = typeof b == 'number' ? b : 100; + if(b = ct.bufferResize){ + // Only allow if we should buffer the layout + if(ct.shouldBufferLayout()){ + if(!this.resizeTask){ + this.resizeTask = new Ext.util.DelayedTask(this.runLayout, this); + this.resizeBuffer = Ext.isNumber(b) ? b : 50; + } + ct.layoutPending = true; + this.resizeTask.delay(this.resizeBuffer); } - this.resizeTask.delay(this.resizeBuffer); }else{ this.runLayout(); } }, - - // private + runLayout: function(){ - this.layout(); - this.container.onLayout(); + var ct = this.container; + // AutoLayout is known to require the recursive doLayout call, others need this currently (BorderLayout for example) + // but shouldn't. A more extensive review will take place for 3.2 which requires a ContainerMgr with hierarchy lookups. + //this.layout(); + //ct.onLayout(); + ct.doLayout(); + delete ct.layoutPending; }, // private setContainer : function(ct){ + if (!Ext.LayoutManager) { + Ext.LayoutManager = {}; + } + + /* This monitorResize flag will be renamed soon as to avoid confusion + * with the Container version which hooks onWindowResize to doLayout + * + * monitorResize flag in this context attaches the resize event between + * a container and it's layout + */ + if(this.monitorResize && ct != this.container){ - if(this.container){ - this.container.un('resize', this.onResize, this); - this.container.un('bodyresize', this.onResize, this); + var old = this.container; + if(old){ + old.un(old.resizeEvent, this.onResize, this); } if(ct){ - ct.on({ - scope: this, - resize: this.onResize, - bodyresize: this.onResize - }); + ct.on(ct.resizeEvent, this.onResize, this); } } this.container = ct; @@ -4566,21 +5072,17 @@ Ext.layout.ContainerLayout.prototype = { // private parseMargins : function(v){ - if(typeof v == 'number'){ + if(Ext.isNumber(v)){ v = v.toString(); } var ms = v.split(' '); var len = ms.length; if(len == 1){ - ms[1] = ms[0]; - ms[2] = ms[0]; - ms[3] = ms[0]; - } - if(len == 2){ + ms[1] = ms[2] = ms[3] = ms[0]; + } else if(len == 2){ ms[2] = ms[0]; ms[3] = ms[1]; - } - if(len == 3){ + } else if(len == 3){ ms[3] = ms[1]; } return { @@ -4592,7 +5094,7 @@ Ext.layout.ContainerLayout.prototype = { }, /** - * The {@link Template Ext.Template} used by Field rendering layout classes (such as + * The {@link Ext.Template Ext.Template} used by Field rendering layout classes (such as * {@link Ext.layout.FormLayout}) to create the DOM structure of a fully wrapped, * labeled and styled form Field. A default Template is supplied, but this may be * overriden to create custom field structures. The template processes values returned from @@ -4611,15 +5113,39 @@ Ext.layout.ContainerLayout.prototype = { t.disableFormats = true; return t.compile(); })(), - + /* * Destroys this layout. This is a template method that is empty by default, but should be implemented * by subclasses that require explicit destruction to purge event handlers or remove DOM nodes. * @protected */ - destroy : Ext.emptyFn -}; -Ext.Container.LAYOUTS['auto'] = Ext.layout.ContainerLayout;/** + destroy : function(){ + if(!Ext.isEmpty(this.targetCls)){ + var target = this.container.getLayoutTarget(); + if(target){ + target.removeClass(this.targetCls); + } + } + } +});/** + * @class Ext.layout.AutoLayout + *

      The AutoLayout is the default layout manager delegated by {@link Ext.Container} to + * render any child Components when no {@link Ext.Container#layout layout} is configured into + * a {@link Ext.Container Container}. ContainerLayout provides the basic foundation for all other layout + * classes in Ext. It simply renders all child Components into the Container, performing no sizing or + * positioning services. To utilize a layout that provides sizing and positioning of child Components, + * specify an appropriate {@link Ext.Container#layout layout}.

      + */ +Ext.layout.AutoLayout = Ext.extend(Ext.layout.ContainerLayout, { + runLayout: function(){ + var ct = this.container; + ct.doLayout(); + delete ct.layoutPending; + } +}); + +Ext.Container.LAYOUTS['auto'] = Ext.layout.AutoLayout; +/** * @class Ext.layout.FitLayout * @extends Ext.layout.ContainerLayout *

      This is a base class for layouts that contain a single item that automatically expands to fill the layout's @@ -4644,12 +5170,22 @@ Ext.layout.FitLayout = Ext.extend(Ext.layout.ContainerLayout, { // private monitorResize:true, + type: 'fit', + + getLayoutTargetSize : function() { + var target = this.container.getLayoutTarget(); + if (!target) { + return {}; + } + // Style Sized (scrollbars not included) + return target.getStyleSize(); + }, + // private onLayout : function(ct, target){ Ext.layout.FitLayout.superclass.onLayout.call(this, ct, target); - if(!this.container.collapsed){ - var sz = (Ext.isIE6 && Ext.isStrict && target.dom == document.body) ? target.getViewSize() : target.getStyleSize(); - this.setItemSize(this.activeItem || ct.items.itemAt(0), sz); + if(!ct.collapsed){ + this.setItemSize(this.activeItem || ct.items.itemAt(0), this.getLayoutTargetSize()); } }, @@ -4734,7 +5270,7 @@ Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, { * true might improve performance. */ deferredRender : false, - + /** * @cfg {Boolean} layoutOnCardChange * True to force a layout of the active item when the active card is changed. Defaults to false. @@ -4746,10 +5282,11 @@ Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, { */ // private renderHidden : true, - + + type: 'card', + constructor: function(config){ Ext.layout.CardLayout.superclass.constructor.call(this, config); - this.forceLayout = (this.deferredRender === false); }, /** @@ -4757,17 +5294,37 @@ Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, { * @param {String/Number} item The string component id or numeric index of the item to activate */ setActiveItem : function(item){ - item = this.container.getComponent(item); - if(this.activeItem != item){ - if(this.activeItem){ - this.activeItem.hide(); + var ai = this.activeItem, + ct = this.container; + item = ct.getComponent(item); + + // Is this a valid, different card? + if(item && ai != item){ + + // Changing cards, hide the current one + if(ai){ + ai.hide(); + if (ai.hidden !== true) { + return false; + } + ai.fireEvent('deactivate', ai); } + // Change activeItem reference this.activeItem = item; + + // The container is about to get a recursive layout, remove any deferLayout reference + // because it will trigger a redundant layout. + delete item.deferLayout; + + // Show the new component item.show(); - this.container.doLayout(); - if(this.layoutOnCardChange && item.doLayout){ + + this.layout(); + + if(item.doLayout){ item.doLayout(); } + item.fireEvent('activate', item); } }, @@ -4780,235 +5337,240 @@ Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, { } } }); -Ext.Container.LAYOUTS['card'] = Ext.layout.CardLayout;/** - * @class Ext.layout.AnchorLayout +Ext.Container.LAYOUTS['card'] = Ext.layout.CardLayout;/** + * @class Ext.layout.AnchorLayout + * @extends Ext.layout.ContainerLayout + *

      This is a layout that enables anchoring of contained elements relative to the container's dimensions. + * If the container is resized, all anchored items are automatically rerendered according to their + * {@link #anchor} rules.

      + *

      This class is intended to be extended or created via the layout:'anchor' {@link Ext.Container#layout} + * config, and should generally not need to be created directly via the new keyword.

      + *

      AnchorLayout does not have any direct config options (other than inherited ones). By default, + * AnchorLayout will calculate anchor measurements based on the size of the container itself. However, the + * container using the AnchorLayout can supply an anchoring-specific config property of anchorSize. + * If anchorSize is specifed, the layout will use it as a virtual container for the purposes of calculating + * anchor measurements based on it instead, allowing the container to be sized independently of the anchoring + * logic if necessary. For example:

      + *
      
      +var viewport = new Ext.Viewport({
      +    layout:'anchor',
      +    anchorSize: {width:800, height:600},
      +    items:[{
      +        title:'Item 1',
      +        html:'Content 1',
      +        width:800,
      +        anchor:'right 20%'
      +    },{
      +        title:'Item 2',
      +        html:'Content 2',
      +        width:300,
      +        anchor:'50% 30%'
      +    },{
      +        title:'Item 3',
      +        html:'Content 3',
      +        width:600,
      +        anchor:'-100 50%'
      +    }]
      +});
      + * 
      + */ +Ext.layout.AnchorLayout = Ext.extend(Ext.layout.ContainerLayout, { + /** + * @cfg {String} anchor + *

      This configuation option is to be applied to child items of a container managed by + * this layout (ie. configured with layout:'anchor').


      + * + *

      This value is what tells the layout how an item should be anchored to the container. items + * added to an AnchorLayout accept an anchoring-specific config property of anchor which is a string + * containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%'). + * The following types of anchor values are supported:

        + * + *
      • Percentage : Any value between 1 and 100, expressed as a percentage.
        + * The first anchor is the percentage width that the item should take up within the container, and the + * second is the percentage height. For example:
        
        +// two values specified
        +anchor: '100% 50%' // render item complete width of the container and
        +                   // 1/2 height of the container
        +// one value specified
        +anchor: '100%'     // the width value; the height will default to auto
        +     * 
      • + * + *
      • Offsets : Any positive or negative integer value.
        + * This is a raw adjustment where the first anchor is the offset from the right edge of the container, + * and the second is the offset from the bottom edge. For example:
        
        +// two values specified
        +anchor: '-50 -100' // render item the complete width of the container
        +                   // minus 50 pixels and
        +                   // the complete height minus 100 pixels.
        +// one value specified
        +anchor: '-50'      // anchor value is assumed to be the right offset value
        +                   // bottom offset will default to 0
        +     * 
      • + * + *
      • Sides : Valid values are 'right' (or 'r') and 'bottom' + * (or 'b').
        + * Either the container must have a fixed size or an anchorSize config value defined at render time in + * order for these to have any effect.
      • + * + *
      • Mixed :
        + * Anchor values can also be mixed as needed. For example, to render the width offset from the container + * right edge by 50 pixels and 75% of the container's height use: + *
        
        +anchor: '-50 75%'
        +     * 
      • + * + * + *
      + */ + + // private + monitorResize:true, + type: 'anchor', + + getLayoutTargetSize : function() { + var target = this.container.getLayoutTarget(); + if (!target) { + return {}; + } + // Style Sized (scrollbars not included) + return target.getStyleSize(); + }, + + // private + onLayout : function(ct, target){ + Ext.layout.AnchorLayout.superclass.onLayout.call(this, ct, target); + var size = this.getLayoutTargetSize(); + + var w = size.width, h = size.height; + + if(w < 20 && h < 20){ + return; + } + + // find the container anchoring size + var aw, ah; + if(ct.anchorSize){ + if(typeof ct.anchorSize == 'number'){ + aw = ct.anchorSize; + }else{ + aw = ct.anchorSize.width; + ah = ct.anchorSize.height; + } + }else{ + aw = ct.initialConfig.width; + ah = ct.initialConfig.height; + } + + var cs = this.getRenderedItems(ct), len = cs.length, i, c, a, cw, ch, el, vs; + for(i = 0; i < len; i++){ + c = cs[i]; + el = c.getPositionEl(); + if(c.anchor){ + a = c.anchorSpec; + if(!a){ // cache all anchor values + vs = c.anchor.split(' '); + c.anchorSpec = a = { + right: this.parseAnchor(vs[0], c.initialConfig.width, aw), + bottom: this.parseAnchor(vs[1], c.initialConfig.height, ah) + }; + } + cw = a.right ? this.adjustWidthAnchor(a.right(w) - el.getMargins('lr'), c) : undefined; + ch = a.bottom ? this.adjustHeightAnchor(a.bottom(h) - el.getMargins('tb'), c) : undefined; + + if(cw || ch){ + c.setSize(cw || undefined, ch || undefined); + } + } + } + }, + + // private + parseAnchor : function(a, start, cstart){ + if(a && a != 'none'){ + var last; + if(/^(r|right|b|bottom)$/i.test(a)){ // standard anchor + var diff = cstart - start; + return function(v){ + if(v !== last){ + last = v; + return v - diff; + } + } + }else if(a.indexOf('%') != -1){ + var ratio = parseFloat(a.replace('%', ''))*.01; // percentage + return function(v){ + if(v !== last){ + last = v; + return Math.floor(v*ratio); + } + } + }else{ + a = parseInt(a, 10); + if(!isNaN(a)){ // simple offset adjustment + return function(v){ + if(v !== last){ + last = v; + return v + a; + } + } + } + } + } + return false; + }, + + // private + adjustWidthAnchor : function(value, comp){ + return value; + }, + + // private + adjustHeightAnchor : function(value, comp){ + return value; + } + + /** + * @property activeItem + * @hide + */ +}); +Ext.Container.LAYOUTS['anchor'] = Ext.layout.AnchorLayout; +/** + * @class Ext.layout.ColumnLayout * @extends Ext.layout.ContainerLayout - *

      This is a layout that enables anchoring of contained elements relative to the container's dimensions. - * If the container is resized, all anchored items are automatically rerendered according to their - * {@link #anchor} rules.

      - *

      This class is intended to be extended or created via the layout:'anchor' {@link Ext.Container#layout} - * config, and should generally not need to be created directly via the new keyword.

      - *

      AnchorLayout does not have any direct config options (other than inherited ones). By default, - * AnchorLayout will calculate anchor measurements based on the size of the container itself. However, the - * container using the AnchorLayout can supply an anchoring-specific config property of anchorSize. - * If anchorSize is specifed, the layout will use it as a virtual container for the purposes of calculating - * anchor measurements based on it instead, allowing the container to be sized independently of the anchoring - * logic if necessary. For example:

      + *

      This is the layout style of choice for creating structural layouts in a multi-column format where the width of + * each column can be specified as a percentage or fixed width, but the height is allowed to vary based on the content. + * This class is intended to be extended or created via the layout:'column' {@link Ext.Container#layout} config, + * and should generally not need to be created directly via the new keyword.

      + *

      ColumnLayout does not have any direct config options (other than inherited ones), but it does support a + * specific config property of columnWidth that can be included in the config of any panel added to it. The + * layout will use the columnWidth (if present) or width of each panel during layout to determine how to size each panel. + * If width or columnWidth is not specified for a given panel, its width will default to the panel's width (or auto).

      + *

      The width property is always evaluated as pixels, and must be a number greater than or equal to 1. + * The columnWidth property is always evaluated as a percentage, and must be a decimal value greater than 0 and + * less than 1 (e.g., .25).

      + *

      The basic rules for specifying column widths are pretty simple. The logic makes two passes through the + * set of contained panels. During the first layout pass, all panels that either have a fixed width or none + * specified (auto) are skipped, but their widths are subtracted from the overall container width. During the second + * pass, all panels with columnWidths are assigned pixel widths in proportion to their percentages based on + * the total remaining container width. In other words, percentage width panels are designed to fill the space + * left over by all the fixed-width and/or auto-width panels. Because of this, while you can specify any number of columns + * with different percentages, the columnWidths must always add up to 1 (or 100%) when added together, otherwise your + * layout may not render as expected. Example usage:

      *
      
      -var viewport = new Ext.Viewport({
      -    layout:'anchor',
      -    anchorSize: {width:800, height:600},
      -    items:[{
      -        title:'Item 1',
      -        html:'Content 1',
      -        width:800,
      -        anchor:'right 20%'
      +// All columns are percentages -- they must add up to 1
      +var p = new Ext.Panel({
      +    title: 'Column Layout - Percentage Only',
      +    layout:'column',
      +    items: [{
      +        title: 'Column 1',
      +        columnWidth: .25
           },{
      -        title:'Item 2',
      -        html:'Content 2',
      -        width:300,
      -        anchor:'50% 30%'
      +        title: 'Column 2',
      +        columnWidth: .6
           },{
      -        title:'Item 3',
      -        html:'Content 3',
      -        width:600,
      -        anchor:'-100 50%'
      -    }]
      -});
      - * 
      - */ -Ext.layout.AnchorLayout = Ext.extend(Ext.layout.ContainerLayout, { - /** - * @cfg {String} anchor - *

      This configuation option is to be applied to child items of a container managed by - * this layout (ie. configured with layout:'anchor').


      - * - *

      This value is what tells the layout how an item should be anchored to the container. items - * added to an AnchorLayout accept an anchoring-specific config property of anchor which is a string - * containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%'). - * The following types of anchor values are supported:

        - * - *
      • Percentage : Any value between 1 and 100, expressed as a percentage.
        - * The first anchor is the percentage width that the item should take up within the container, and the - * second is the percentage height. For example:
        
        -// two values specified
        -anchor: '100% 50%' // render item complete width of the container and
        -                   // 1/2 height of the container
        -// one value specified
        -anchor: '100%'     // the width value; the height will default to auto
        -     * 
      • - * - *
      • Offsets : Any positive or negative integer value.
        - * This is a raw adjustment where the first anchor is the offset from the right edge of the container, - * and the second is the offset from the bottom edge. For example:
        
        -// two values specified
        -anchor: '-50 -100' // render item the complete width of the container
        -                   // minus 50 pixels and
        -                   // the complete height minus 100 pixels.
        -// one value specified
        -anchor: '-50'      // anchor value is assumed to be the right offset value
        -                   // bottom offset will default to 0
        -     * 
      • - * - *
      • Sides : Valid values are 'right' (or 'r') and 'bottom' - * (or 'b').
        - * Either the container must have a fixed size or an anchorSize config value defined at render time in - * order for these to have any effect.
      • - * - *
      • Mixed :
        - * Anchor values can also be mixed as needed. For example, to render the width offset from the container - * right edge by 50 pixels and 75% of the container's height use: - *
        
        -anchor: '-50 75%' 
        -     * 
      • - * - * - *
      - */ - - // private - monitorResize:true, - - // private - getAnchorViewSize : function(ct, target){ - return target.dom == document.body ? - target.getViewSize() : target.getStyleSize(); - }, - - // private - onLayout : function(ct, target){ - Ext.layout.AnchorLayout.superclass.onLayout.call(this, ct, target); - - var size = this.getAnchorViewSize(ct, target); - - var w = size.width, h = size.height; - - if(w < 20 && h < 20){ - return; - } - - // find the container anchoring size - var aw, ah; - if(ct.anchorSize){ - if(typeof ct.anchorSize == 'number'){ - aw = ct.anchorSize; - }else{ - aw = ct.anchorSize.width; - ah = ct.anchorSize.height; - } - }else{ - aw = ct.initialConfig.width; - ah = ct.initialConfig.height; - } - - var cs = ct.items.items, len = cs.length, i, c, a, cw, ch; - for(i = 0; i < len; i++){ - c = cs[i]; - if(c.anchor){ - a = c.anchorSpec; - if(!a){ // cache all anchor values - var vs = c.anchor.split(' '); - c.anchorSpec = a = { - right: this.parseAnchor(vs[0], c.initialConfig.width, aw), - bottom: this.parseAnchor(vs[1], c.initialConfig.height, ah) - }; - } - cw = a.right ? this.adjustWidthAnchor(a.right(w), c) : undefined; - ch = a.bottom ? this.adjustHeightAnchor(a.bottom(h), c) : undefined; - - if(cw || ch){ - c.setSize(cw || undefined, ch || undefined); - } - } - } - }, - - // private - parseAnchor : function(a, start, cstart){ - if(a && a != 'none'){ - var last; - if(/^(r|right|b|bottom)$/i.test(a)){ // standard anchor - var diff = cstart - start; - return function(v){ - if(v !== last){ - last = v; - return v - diff; - } - } - }else if(a.indexOf('%') != -1){ - var ratio = parseFloat(a.replace('%', ''))*.01; // percentage - return function(v){ - if(v !== last){ - last = v; - return Math.floor(v*ratio); - } - } - }else{ - a = parseInt(a, 10); - if(!isNaN(a)){ // simple offset adjustment - return function(v){ - if(v !== last){ - last = v; - return v + a; - } - } - } - } - } - return false; - }, - - // private - adjustWidthAnchor : function(value, comp){ - return value; - }, - - // private - adjustHeightAnchor : function(value, comp){ - return value; - } - - /** - * @property activeItem - * @hide - */ -}); -Ext.Container.LAYOUTS['anchor'] = Ext.layout.AnchorLayout;/** - * @class Ext.layout.ColumnLayout - * @extends Ext.layout.ContainerLayout - *

      This is the layout style of choice for creating structural layouts in a multi-column format where the width of - * each column can be specified as a percentage or fixed width, but the height is allowed to vary based on the content. - * This class is intended to be extended or created via the layout:'column' {@link Ext.Container#layout} config, - * and should generally not need to be created directly via the new keyword.

      - *

      ColumnLayout does not have any direct config options (other than inherited ones), but it does support a - * specific config property of columnWidth that can be included in the config of any panel added to it. The - * layout will use the columnWidth (if present) or width of each panel during layout to determine how to size each panel. - * If width or columnWidth is not specified for a given panel, its width will default to the panel's width (or auto).

      - *

      The width property is always evaluated as pixels, and must be a number greater than or equal to 1. - * The columnWidth property is always evaluated as a percentage, and must be a decimal value greater than 0 and - * less than 1 (e.g., .25).

      - *

      The basic rules for specifying column widths are pretty simple. The logic makes two passes through the - * set of contained panels. During the first layout pass, all panels that either have a fixed width or none - * specified (auto) are skipped, but their widths are subtracted from the overall container width. During the second - * pass, all panels with columnWidths are assigned pixel widths in proportion to their percentages based on - * the total remaining container width. In other words, percentage width panels are designed to fill the space - * left over by all the fixed-width and/or auto-width panels. Because of this, while you can specify any number of columns - * with different percentages, the columnWidths must always add up to 1 (or 100%) when added together, otherwise your - * layout may not render as expected. Example usage:

      - *
      
      -// All columns are percentages -- they must add up to 1
      -var p = new Ext.Panel({
      -    title: 'Column Layout - Percentage Only',
      -    layout:'column',
      -    items: [{
      -        title: 'Column 1',
      -        columnWidth: .25 
      -    },{
      -        title: 'Column 2',
      -        columnWidth: .6
      -    },{
      -        title: 'Column 3',
      -        columnWidth: .15
      +        title: 'Column 3',
      +        columnWidth: .15
           }]
       });
       
      @@ -5034,49 +5596,66 @@ var p = new Ext.Panel({
       Ext.layout.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, {
           // private
           monitorResize:true,
      -    
      +
      +    type: 'column',
      +
           extraCls: 'x-column',
       
           scrollOffset : 0,
       
           // private
      +
      +    targetCls: 'x-column-layout-ct',
      +
           isValidParent : function(c, target){
      -        return (c.getPositionEl ? c.getPositionEl() : c.getEl()).dom.parentNode == this.innerCt.dom;
      +        return this.innerCt && c.getPositionEl().dom.parentNode == this.innerCt.dom;
           },
       
      -    // private
      -    onLayout : function(ct, target){
      -        var cs = ct.items.items, len = cs.length, c, i;
      +    getLayoutTargetSize : function() {
      +        var target = this.container.getLayoutTarget(), ret;
      +        if (target) {
      +            ret = target.getViewSize();
      +            ret.width -= target.getPadding('lr');
      +            ret.height -= target.getPadding('tb');
      +        }
      +        return ret;
      +    },
       
      +    renderAll : function(ct, target) {
               if(!this.innerCt){
      -            target.addClass('x-column-layout-ct');
      -
                   // the innerCt prevents wrapping and shuffling while
                   // the container is resizing
                   this.innerCt = target.createChild({cls:'x-column-inner'});
                   this.innerCt.createChild({cls:'x-clear'});
               }
      -        this.renderAll(ct, this.innerCt);
      +        Ext.layout.ColumnLayout.superclass.renderAll.call(this, ct, this.innerCt);
      +    },
      +
      +    // private
      +    onLayout : function(ct, target){
      +        var cs = ct.items.items, len = cs.length, c, i;
      +
      +        this.renderAll(ct, target);
       
      -        var size = Ext.isIE && target.dom != Ext.getBody().dom ? target.getStyleSize() : target.getViewSize();
      +        var size = this.getLayoutTargetSize();
       
               if(size.width < 1 && size.height < 1){ // display none?
                   return;
               }
       
      -        var w = size.width - target.getPadding('lr') - this.scrollOffset,
      -            h = size.height - target.getPadding('tb'),
      +        var w = size.width - this.scrollOffset,
      +            h = size.height,
                   pw = w;
       
               this.innerCt.setWidth(w);
      -        
      +
               // some columns can be percentages while others are fixed
               // so we need to make 2 passes
       
               for(i = 0; i < len; i++){
                   c = cs[i];
                   if(!c.columnWidth){
      -                pw -= (c.getSize().width + c.getEl().getMargins('lr'));
      +                pw -= (c.getWidth() + c.getPositionEl().getMargins('lr'));
                   }
               }
       
      @@ -5085,11 +5664,24 @@ Ext.layout.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, {
               for(i = 0; i < len; i++){
                   c = cs[i];
                   if(c.columnWidth){
      -                c.setSize(Math.floor(c.columnWidth*pw) - c.getEl().getMargins('lr'));
      +                c.setSize(Math.floor(c.columnWidth * pw) - c.getPositionEl().getMargins('lr'));
      +            }
      +        }
      +
      +        // Browsers differ as to when they account for scrollbars.  We need to re-measure to see if the scrollbar
      +        // spaces were accounted for properly.  If not, re-layout.
      +        if (Ext.isIE) {
      +            if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) {
      +                var ts = this.getLayoutTargetSize();
      +                if (ts.width != size.width){
      +                    this.adjustmentPass = true;
      +                    this.onLayout(ct, target);
      +                }
                   }
               }
      +        delete this.adjustmentPass;
           }
      -    
      +
           /**
            * @property activeItem
            * @hide
      @@ -5123,7 +5715,7 @@ var myBorderPanel = new Ext.Panel({
               {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'south',     // position for region
               {@link Ext.BoxComponent#height height}: 100,
               {@link Ext.layout.BorderLayout.Region#split split}: true,         // enable resizing
      -        {@link Ext.SplitBar#minSize minSize}: 75,         // defaults to {@link Ext.layout.BorderLayout.Region#minHeight 50} 
      +        {@link Ext.SplitBar#minSize minSize}: 75,         // defaults to {@link Ext.layout.BorderLayout.Region#minHeight 50}
               {@link Ext.SplitBar#maxSize maxSize}: 150,
               {@link Ext.layout.BorderLayout.Region#margins margins}: '0 5 5 5'
           },{
      @@ -5181,23 +5773,30 @@ Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {
           // private
           rendered : false,
       
      +    type: 'border',
      +
      +    targetCls: 'x-border-layout-ct',
      +
      +    getLayoutTargetSize : function() {
      +        var target = this.container.getLayoutTarget();
      +        return target ? target.getViewSize() : {};
      +    },
      +
           // private
           onLayout : function(ct, target){
      -        var collapsed;
      +        var collapsed, i, c, pos, items = ct.items.items, len = items.length;
               if(!this.rendered){
      -            target.addClass('x-border-layout-ct');
      -            var items = ct.items.items;
                   collapsed = [];
      -            for(var i = 0, len = items.length; i < len; i++) {
      -                var c = items[i];
      -                var pos = c.region;
      +            for(i = 0; i < len; i++) {
      +                c = items[i];
      +                pos = c.region;
                       if(c.collapsed){
                           collapsed.push(c);
                       }
                       c.collapsed = false;
                       if(!c.rendered){
      -                    c.cls = c.cls ? c.cls +' x-border-panel' : 'x-border-panel';
                           c.render(target, i);
      +                    c.getPositionEl().addClass('x-border-panel');
                       }
                       this[pos] = pos != 'center' && c.split ?
                           new Ext.layout.BorderLayout.SplitRegion(this, c.initialConfig, pos) :
      @@ -5207,7 +5806,7 @@ Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {
                   this.rendered = true;
               }
       
      -        var size = target.getViewSize();
      +        var size = this.getLayoutTargetSize();
               if(size.width < 20 || size.height < 20){ // display none?
                   if(collapsed){
                       this.restoreCollapsed = collapsed;
      @@ -5218,17 +5817,17 @@ Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {
                   delete this.restoreCollapsed;
               }
       
      -        var w = size.width, h = size.height;
      -        var centerW = w, centerH = h, centerY = 0, centerX = 0;
      -
      -        var n = this.north, s = this.south, west = this.west, e = this.east, c = this.center;
      +        var w = size.width, h = size.height,
      +            centerW = w, centerH = h, centerY = 0, centerX = 0,
      +            n = this.north, s = this.south, west = this.west, e = this.east, c = this.center,
      +            b, m, totalWidth, totalHeight;
               if(!c && Ext.layout.BorderLayout.WARN !== false){
                   throw 'No center region defined in BorderLayout ' + ct.id;
               }
       
               if(n && n.isVisible()){
      -            var b = n.getSize();
      -            var m = n.getMargins();
      +            b = n.getSize();
      +            m = n.getMargins();
                   b.width = w - (m.left+m.right);
                   b.x = m.left;
                   b.y = m.top;
      @@ -5237,38 +5836,38 @@ Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {
                   n.applyLayout(b);
               }
               if(s && s.isVisible()){
      -            var b = s.getSize();
      -            var m = s.getMargins();
      +            b = s.getSize();
      +            m = s.getMargins();
                   b.width = w - (m.left+m.right);
                   b.x = m.left;
      -            var totalHeight = (b.height + m.top + m.bottom);
      +            totalHeight = (b.height + m.top + m.bottom);
                   b.y = h - totalHeight + m.top;
                   centerH -= totalHeight;
                   s.applyLayout(b);
               }
               if(west && west.isVisible()){
      -            var b = west.getSize();
      -            var m = west.getMargins();
      +            b = west.getSize();
      +            m = west.getMargins();
                   b.height = centerH - (m.top+m.bottom);
                   b.x = m.left;
                   b.y = centerY + m.top;
      -            var totalWidth = (b.width + m.left + m.right);
      +            totalWidth = (b.width + m.left + m.right);
                   centerX += totalWidth;
                   centerW -= totalWidth;
                   west.applyLayout(b);
               }
               if(e && e.isVisible()){
      -            var b = e.getSize();
      -            var m = e.getMargins();
      +            b = e.getSize();
      +            m = e.getMargins();
                   b.height = centerH - (m.top+m.bottom);
      -            var totalWidth = (b.width + m.left + m.right);
      +            totalWidth = (b.width + m.left + m.right);
                   b.x = w - totalWidth + m.left;
                   b.y = centerY + m.top;
                   centerW -= totalWidth;
                   e.applyLayout(b);
               }
               if(c){
      -            var m = c.getMargins();
      +            m = c.getMargins();
                   var centerBox = {
                       x: centerX + m.left,
                       y: centerY + m.top,
      @@ -5278,19 +5877,28 @@ Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {
                   c.applyLayout(centerBox);
               }
               if(collapsed){
      -            for(var i = 0, len = collapsed.length; i < len; i++){
      +            for(i = 0, len = collapsed.length; i < len; i++){
                       collapsed[i].collapse(false);
                   }
               }
               if(Ext.isIE && Ext.isStrict){ // workaround IE strict repainting issue
                   target.repaint();
               }
      +        // Putting a border layout into an overflowed container is NOT correct and will make a second layout pass necessary.
      +        if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) {
      +            var ts = this.getLayoutTargetSize();
      +            if (ts.width != size.width || ts.height != size.height){
      +                this.adjustmentPass = true;
      +                this.onLayout(ct, target);
      +            }
      +        }
      +        delete this.adjustmentPass;
           },
       
           destroy: function() {
      -        var r = ['north', 'south', 'east', 'west'];
      -        for (var i = 0; i < r.length; i++) {
      -            var region = this[r[i]];
      +        var r = ['north', 'south', 'east', 'west'], i, region;
      +        for (i = 0; i < r.length; i++) {
      +            region = this[r[i]];
                   if(region){
                       if(region.destroy){
                           region.destroy();
      @@ -5434,19 +6042,19 @@ Ext.layout.BorderLayout.Region.prototype = {
           collapsible : false,
           /**
            * @cfg {Boolean} split
      -     * 

      true to create a {@link Ext.layout.BorderLayout.SplitRegion SplitRegion} and + *

      true to create a {@link Ext.layout.BorderLayout.SplitRegion SplitRegion} and * display a 5px wide {@link Ext.SplitBar} between this region and its neighbor, allowing the user to * resize the regions dynamically. Defaults to false creating a * {@link Ext.layout.BorderLayout.Region Region}.


      *

      Notes:

        - *
      • this configuration option is ignored if region='center'
      • + *
      • this configuration option is ignored if region='center'
      • *
      • when split == true, it is common to specify a * {@link Ext.SplitBar#minSize minSize} and {@link Ext.SplitBar#maxSize maxSize} * for the {@link Ext.BoxComponent BoxComponent} representing the region. These are not native * configs of {@link Ext.BoxComponent BoxComponent}, and are used only by this class.
      • *
      • if {@link #collapseMode} = 'mini' requires split = true to reserve space - * for the collapse tool
      • - *
      + * for the collapse tool
    • + *
    */ split:false, /** @@ -5460,8 +6068,8 @@ Ext.layout.BorderLayout.Region.prototype = { * @cfg {Number} minWidth *

    The minimum allowable width in pixels for this region (defaults to 50). * maxWidth may also be specified.


    - *

    Note: setting the {@link Ext.SplitBar#minSize minSize} / - * {@link Ext.SplitBar#maxSize maxSize} supersedes any specified + *

    Note: setting the {@link Ext.SplitBar#minSize minSize} / + * {@link Ext.SplitBar#maxSize maxSize} supersedes any specified * minWidth / maxWidth.

    */ minWidth:50, @@ -5469,8 +6077,8 @@ Ext.layout.BorderLayout.Region.prototype = { * @cfg {Number} minHeight * The minimum allowable height in pixels for this region (defaults to 50) * maxHeight may also be specified.


    - *

    Note: setting the {@link Ext.SplitBar#minSize minSize} / - * {@link Ext.SplitBar#maxSize maxSize} supersedes any specified + *

    Note: setting the {@link Ext.SplitBar#minSize minSize} / + * {@link Ext.SplitBar#maxSize maxSize} supersedes any specified * minHeight / maxHeight.

    */ minHeight:50, @@ -5585,7 +6193,6 @@ Ext.layout.BorderLayout.Region.prototype = { // private onExpandClick : function(e){ if(this.isSlid){ - this.afterSlideIn(); this.panel.expand(false); }else{ this.panel.expand(); @@ -5604,7 +6211,9 @@ Ext.layout.BorderLayout.Region.prototype = { this.splitEl.hide(); } this.getCollapsedEl().show(); - this.panel.el.setStyle('z-index', 100); + var el = this.panel.getEl(); + this.originalZIndex = el.getStyle('z-index'); + el.setStyle('z-index', 100); this.isCollapsed = true; this.layout.layout(); }, @@ -5623,6 +6232,9 @@ Ext.layout.BorderLayout.Region.prototype = { // private beforeExpand : function(animate){ + if(this.isSlid){ + this.afterSlideIn(); + } var c = this.getCollapsedEl(); this.el.show(); if(this.position == 'east' || this.position == 'west'){ @@ -5642,7 +6254,7 @@ Ext.layout.BorderLayout.Region.prototype = { this.splitEl.show(); } this.layout.layout(); - this.panel.el.setStyle('z-index', 1); + this.panel.el.setStyle('z-index', this.originalZIndex); this.state.collapsed = false; this.panel.saveState(); }, @@ -5774,6 +6386,7 @@ Ext.layout.BorderLayout.Region.prototype = { }; } this.el.on(this.autoHideHd); + this.collapsedEl.on(this.autoHideHd); } }, @@ -5782,6 +6395,8 @@ Ext.layout.BorderLayout.Region.prototype = { if(this.autoHide !== false){ this.el.un("mouseout", this.autoHideHd.mouseout); this.el.un("mouseover", this.autoHideHd.mouseover); + this.collapsedEl.un("mouseout", this.autoHideHd.mouseout); + this.collapsedEl.un("mouseover", this.autoHideHd.mouseover); } }, @@ -5800,16 +6415,32 @@ Ext.layout.BorderLayout.Region.prototype = { return; } this.isSlid = true; - var ts = this.panel.tools; + var ts = this.panel.tools, dh, pc; if(ts && ts.toggle){ ts.toggle.hide(); } this.el.show(); + + // Temporarily clear the collapsed flag so we can onResize the panel on the slide + pc = this.panel.collapsed; + this.panel.collapsed = false; + if(this.position == 'east' || this.position == 'west'){ + // Temporarily clear the deferHeight flag so we can size the height on the slide + dh = this.panel.deferHeight; + this.panel.deferHeight = false; + this.panel.setSize(undefined, this.collapsedEl.getHeight()); + + // Put the deferHeight flag back after setSize + this.panel.deferHeight = dh; }else{ this.panel.setSize(this.collapsedEl.getWidth(), undefined); } + + // Put the collapsed flag back after onResize + this.panel.collapsed = pc; + this.restoreLT = [this.el.dom.style.left, this.el.dom.style.top]; this.el.alignTo(this.collapsedEl, this.getCollapseAnchor()); this.el.setStyle("z-index", this.floatingZIndex+2); @@ -5957,6 +6588,10 @@ Ext.layout.BorderLayout.Region.prototype = { return [0, cm.top+cm.bottom+c.getHeight()]; break; } + }, + + destroy : function(){ + Ext.destroy(this.miniCollapsedEl, this.collapsedEl); } }; @@ -6189,11 +6824,8 @@ Ext.extend(Ext.layout.BorderLayout.SplitRegion, Ext.layout.BorderLayout.Region, // inherit docs destroy : function() { - Ext.destroy( - this.miniSplitEl, - this.split, - this.splitEl - ); + Ext.destroy(this.miniSplitEl, this.split, this.splitEl); + Ext.layout.BorderLayout.SplitRegion.superclass.destroy.call(this); } }); @@ -6308,6 +6940,36 @@ Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, { * @property labelStyle */ + /** + * @cfg {Boolean} trackLabels + * True to show/hide the field label when the field is hidden. Defaults to false. + */ + trackLabels: false, + + type: 'form', + + + onRemove: function(c){ + Ext.layout.FormLayout.superclass.onRemove.call(this, c); + if(this.trackLabels){ + c.un('show', this.onFieldShow, this); + c.un('hide', this.onFieldHide, this); + } + // check for itemCt, since we may be removing a fieldset or something similar + var el = c.getPositionEl(), + ct = c.getItemCt && c.getItemCt(); + if(c.rendered && ct){ + if (el && el.dom) { + el.insertAfter(ct); + } + Ext.destroy(ct); + Ext.destroyMembers(c, 'label', 'itemCt'); + if(c.customItemCt){ + Ext.destroyMembers(c, 'getItemCt', 'customItemCt'); + } + } + }, + // private setContainer : function(ct){ Ext.layout.FormLayout.superclass.setContainer.call(this, ct); @@ -6316,26 +6978,45 @@ Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, { } if(ct.hideLabels){ - this.labelStyle = "display:none"; - this.elementStyle = "padding-left:0;"; - this.labelAdjust = 0; + Ext.apply(this, { + labelStyle: 'display:none', + elementStyle: 'padding-left:0;', + labelAdjust: 0 + }); }else{ this.labelSeparator = ct.labelSeparator || this.labelSeparator; ct.labelWidth = ct.labelWidth || 100; - if(typeof ct.labelWidth == 'number'){ - var pad = (typeof ct.labelPad == 'number' ? ct.labelPad : 5); - this.labelAdjust = ct.labelWidth+pad; - this.labelStyle = "width:"+ct.labelWidth+"px;"; - this.elementStyle = "padding-left:"+(ct.labelWidth+pad)+'px'; + if(Ext.isNumber(ct.labelWidth)){ + var pad = Ext.isNumber(ct.labelPad) ? ct.labelPad : 5; + Ext.apply(this, { + labelAdjust: ct.labelWidth + pad, + labelStyle: 'width:' + ct.labelWidth + 'px;', + elementStyle: 'padding-left:' + (ct.labelWidth + pad) + 'px' + }); } if(ct.labelAlign == 'top'){ - this.labelStyle = "width:auto;"; - this.labelAdjust = 0; - this.elementStyle = "padding-left:0;"; + Ext.apply(this, { + labelStyle: 'width:auto;', + labelAdjust: 0, + elementStyle: 'padding-left:0;' + }); } } }, + // private + isHide: function(c){ + return c.hideLabel || this.container.hideLabels; + }, + + onFieldShow: function(c){ + c.getItemCt().removeClass('x-hide-' + c.hideMode); + }, + + onFieldHide: function(c){ + c.getItemCt().addClass('x-hide-' + c.hideMode); + }, + //private getLabelStyle: function(s){ var ls = '', items = [this.labelStyle, s]; @@ -6386,17 +7067,43 @@ new Ext.Template( // private renderItem : function(c, position, target){ - if(c && !c.rendered && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){ + if(c && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){ var args = this.getTemplateArgs(c); - if(typeof position == 'number'){ + if(Ext.isNumber(position)){ position = target.dom.childNodes[position] || null; } if(position){ - this.fieldTpl.insertBefore(position, args); + c.itemCt = this.fieldTpl.insertBefore(position, args, true); }else{ - this.fieldTpl.append(target, args); + c.itemCt = this.fieldTpl.append(target, args, true); + } + if(!c.getItemCt){ + // Non form fields don't have getItemCt, apply it here + // This will get cleaned up in onRemove + Ext.apply(c, { + getItemCt: function(){ + return c.itemCt; + }, + customItemCt: true + }); + } + c.label = c.getItemCt().child('label.x-form-item-label'); + if(!c.rendered){ + c.render('x-form-el-' + c.id); + }else if(!this.isValidParent(c, target)){ + Ext.fly('x-form-el-' + c.id).appendChild(c.getPositionEl()); + } + if(this.trackLabels){ + if(c.hidden){ + this.onFieldHide(c); + } + c.on({ + scope: this, + show: this.onFieldShow, + hide: this.onFieldHide + }); } - c.render('x-form-el-'+c.id); + this.configureItem(c); }else { Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments); } @@ -6424,7 +7131,7 @@ new Ext.Template( *
  • clearCls : String
    The CSS class to apply to the special clearing div * rendered directly after each form field wrapper (defaults to 'x-form-clear-left')
  • * - * @param field The {@link Field Ext.form.Field} being rendered. + * @param (Ext.form.Field} field The {@link Ext.form.Field Field} being rendered. * @return An object hash containing the properties required to render the Field. */ getTemplateArgs: function(field) { @@ -6432,22 +7139,33 @@ new Ext.Template( return { id: field.id, label: field.fieldLabel, - labelStyle: field.labelStyle||this.labelStyle||'', + labelStyle: this.getLabelStyle(field.labelStyle), elementStyle: this.elementStyle||'', - labelSeparator: noLabelSep ? '' : (typeof field.labelSeparator == 'undefined' ? this.labelSeparator : field.labelSeparator), + labelSeparator: noLabelSep ? '' : (Ext.isDefined(field.labelSeparator) ? field.labelSeparator : this.labelSeparator), itemCls: (field.itemCls||this.container.itemCls||'') + (field.hideLabel ? ' x-hide-label' : ''), clearCls: field.clearCls || 'x-form-clear-left' }; }, // private - adjustWidthAnchor : function(value, comp){ - return value - (comp.isFormField || comp.fieldLabel ? (comp.hideLabel ? 0 : this.labelAdjust) : 0); + adjustWidthAnchor: function(value, c){ + if(c.label && !this.isHide(c) && (this.container.labelAlign != 'top')){ + var adjust = Ext.isIE6 || (Ext.isIE && !Ext.isStrict); + return value - this.labelAdjust + (adjust ? -3 : 0); + } + return value; + }, + + adjustHeightAnchor : function(value, c){ + if(c.label && !this.isHide(c) && (this.container.labelAlign == 'top')){ + return value - c.label.getHeight(); + } + return value; }, // private isValidParent : function(c, target){ - return true; + return target && this.container.getEl().contains(c.getPositionEl()); } /** @@ -6456,11 +7174,13 @@ new Ext.Template( */ }); -Ext.Container.LAYOUTS['form'] = Ext.layout.FormLayout;/** +Ext.Container.LAYOUTS['form'] = Ext.layout.FormLayout; +/** * @class Ext.layout.AccordionLayout * @extends Ext.layout.FitLayout - *

    This is a layout that contains multiple panels in an expandable accordion style such that only - * one panel can be open at any given time. Each panel has built-in support for expanding and collapsing. + *

    This is a layout that manages multiple Panels in an expandable accordion style such that only + * one Panel can be expanded at any given time. Each Panel has built-in support for expanding and collapsing.

    + *

    Note: Only Ext.Panels and all subclasses of Ext.Panel may be used in an accordion layout Container.

    *

    This class is intended to be extended or created via the {@link Ext.Container#layout layout} * configuration property. See {@link Ext.Container#layout} for additional details.

    *

    Example usage:

    @@ -6543,6 +7263,8 @@ Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, { */ activeOnTop : false, + type: 'accordion', + renderItem : function(c){ if(this.animate === false){ c.animCollapse = false; @@ -6561,7 +7283,7 @@ Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, { c.collapseFirst = this.collapseFirst; } if(!this.activeItem && !c.collapsed){ - this.activeItem = c; + this.setActiveItem(c, true); }else if(this.activeItem && this.activeItem != c){ c.collapsed = true; } @@ -6570,6 +7292,14 @@ Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, { c.on('beforeexpand', this.beforeExpand, this); }, + onRemove: function(c){ + Ext.layout.AccordionLayout.superclass.onRemove.call(this, c); + if(c.rendered){ + c.header.removeClass('x-accordion-hd'); + } + c.un('beforeexpand', this.beforeExpand, this); + }, + // private beforeExpand : function(p, anim){ var ai = this.activeItem; @@ -6586,23 +7316,28 @@ Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, { ai.collapse(this.animate); } } - this.activeItem = p; + this.setActive(p); if(this.activeOnTop){ p.el.dom.parentNode.insertBefore(p.el.dom, p.el.dom.parentNode.firstChild); } + // Items have been hidden an possibly rearranged, we need to get the container size again. this.layout(); }, // private setItemSize : function(item, size){ if(this.fill && item){ - var hh = 0; - this.container.items.each(function(p){ - if(p != item){ + var hh = 0, i, ct = this.getRenderedItems(this.container), len = ct.length, p; + // Add up all the header heights + for (i = 0; i < len; i++) { + if((p = ct[i]) != item){ hh += p.header.getHeight(); - } - }); + } + }; + // Subtract the header heights from the container size size.height -= hh; + // Call setSize on the container to set the correct height. For Panels, deferedHeight + // will simply store this size for when the expansion is done. item.setSize(size); } }, @@ -6612,15 +7347,24 @@ Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, { * @param {String/Number} item The string component id or numeric index of the item to activate */ setActiveItem : function(item){ + this.setActive(item, true); + }, + + // private + setActive : function(item, expand){ + var ai = this.activeItem; item = this.container.getComponent(item); - if(this.activeItem != item){ - if(item.rendered && item.collapsed){ + if(ai != item){ + if(item.rendered && item.collapsed && expand){ item.expand(); }else{ + if(ai){ + ai.fireEvent('deactivate', ai); + } this.activeItem = item; + item.fireEvent('activate', item); } } - } }); Ext.Container.LAYOUTS.accordion = Ext.layout.AccordionLayout; @@ -6695,6 +7439,10 @@ Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, { // private monitorResize:false, + type: 'table', + + targetCls: 'x-table-layout-ct', + /** * @cfg {Object} tableAttrs *

    An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification @@ -6704,16 +7452,16 @@ Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, { layout: 'table', layoutConfig: { tableAttrs: { - style: { - width: '100%' - } + style: { + width: '100%' + } }, columns: 3 } }

    */ tableAttrs:null, - + // private setContainer : function(ct){ Ext.layout.TableLayout.superclass.setContainer.call(this, ct); @@ -6722,7 +7470,7 @@ Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, { this.currentColumn = 0; this.cells = []; }, - + // private onLayout : function(ct, target){ var cs = ct.items.items, len = cs.length, c, i; @@ -6776,7 +7524,7 @@ Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, { this.getRow(curRow).appendChild(td); return td; }, - + // private getNextNonSpan: function(colIndex, rowIndex){ var cols = this.columns; @@ -6793,18 +7541,25 @@ Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, { // private renderItem : function(c, position, target){ + // Ensure we have our inner table to get cells to render into. + if(!this.table){ + this.table = target.createChild( + Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true); + } if(c && !c.rendered){ c.render(this.getNextCell(c)); - if(this.extraCls){ - var t = c.getPositionEl ? c.getPositionEl() : c; - t.addClass(this.extraCls); - } + this.configureItem(c, position); + }else if(c && !this.isValidParent(c, target)){ + var container = this.getNextCell(c); + container.insertBefore(c.getPositionEl().dom, null); + c.container = Ext.get(container); + this.configureItem(c, position); } }, // private isValidParent : function(c, target){ - return true; + return c.getPositionEl().up('table', 5).dom.parentNode === (target.dom || target); } /** @@ -6813,3660 +7568,4124 @@ Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, { */ }); -Ext.Container.LAYOUTS['table'] = Ext.layout.TableLayout;/** - * @class Ext.layout.AbsoluteLayout - * @extends Ext.layout.AnchorLayout - *

    This is a layout that inherits the anchoring of {@link Ext.layout.AnchorLayout} and adds the - * ability for x/y positioning using the standard x and y component config options.

    - *

    This class is intended to be extended or created via the {@link Ext.Container#layout layout} - * configuration property. See {@link Ext.Container#layout} for additional details.

    - *

    Example usage:

    - *
    
    -var form = new Ext.form.FormPanel({
    -    title: 'Absolute Layout',
    -    layout:'absolute',
    -    layoutConfig: {
    -        // layout-specific configs go here
    -        extraCls: 'x-abs-layout-item',
    -    },
    -    baseCls: 'x-plain',
    -    url:'save-form.php',
    -    defaultType: 'textfield',
    -    items: [{
    -        x: 0,
    -        y: 5,
    -        xtype:'label',
    -        text: 'Send To:'
    -    },{
    -        x: 60,
    -        y: 0,
    -        name: 'to',
    -        anchor:'100%'  // anchor width by percentage
    -    },{
    -        x: 0,
    -        y: 35,
    -        xtype:'label',
    -        text: 'Subject:'
    -    },{
    -        x: 60,
    -        y: 30,
    -        name: 'subject',
    -        anchor: '100%'  // anchor width by percentage
    -    },{
    -        x:0,
    -        y: 60,
    -        xtype: 'textarea',
    -        name: 'msg',
    -        anchor: '100% 100%'  // anchor width and height
    -    }]
    -});
    -
    - */ -Ext.layout.AbsoluteLayout = Ext.extend(Ext.layout.AnchorLayout, { - - extraCls: 'x-abs-layout-item', - - onLayout : function(ct, target){ - target.position(); - this.paddingLeft = target.getPadding('l'); - this.paddingTop = target.getPadding('t'); - - Ext.layout.AbsoluteLayout.superclass.onLayout.call(this, ct, target); - }, - - // private - adjustWidthAnchor : function(value, comp){ - return value ? value - comp.getPosition(true)[0] + this.paddingLeft : value; - }, - - // private - adjustHeightAnchor : function(value, comp){ - return value ? value - comp.getPosition(true)[1] + this.paddingTop : value; - } - /** - * @property activeItem - * @hide - */ -}); -Ext.Container.LAYOUTS['absolute'] = Ext.layout.AbsoluteLayout; -/** - * @class Ext.layout.BoxLayout - * @extends Ext.layout.ContainerLayout - *

    Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.

    - */ -Ext.layout.BoxLayout = Ext.extend(Ext.layout.ContainerLayout, { - /** - * @cfg {Object} defaultMargins - *

    If the individual contained items do not have a margins - * property specified, the default margins from this property will be - * applied to each item.

    - *

    This property may be specified as an object containing margins - * to apply in the format:

    
    -{
    -    top: (top margin),
    -    right: (right margin),
    -    bottom: (bottom margin),
    -    left: (left margin)
    -}
    - *

    This property may also be specified as a string containing - * space-separated, numeric margin values. The order of the sides associated - * with each value matches the way CSS processes margin values:

    - *
      - *
    • If there is only one value, it applies to all sides.
    • - *
    • If there are two values, the top and bottom borders are set to the - * first value and the right and left are set to the second.
    • - *
    • If there are three values, the top is set to the first value, the left - * and right are set to the second, and the bottom is set to the third.
    • - *
    • If there are four values, they apply to the top, right, bottom, and - * left, respectively.
    • - *
    - *

    Defaults to:

    
    -     * {top:0, right:0, bottom:0, left:0}
    -     * 
    - */ - defaultMargins : {left:0,top:0,right:0,bottom:0}, - /** - * @cfg {String} padding - * Defaults to '0'. Sets the padding to be applied to all child items managed by this - * container's layout. - */ - padding : '0', - // documented in subclasses - pack : 'start', - - // private - monitorResize : true, - scrollOffset : 0, - extraCls : 'x-box-item', - ctCls : 'x-box-layout-ct', - innerCls : 'x-box-inner', - - // private - isValidParent : function(c, target){ - return c.getEl().dom.parentNode == this.innerCt.dom; - }, - - // private - onLayout : function(ct, target){ - var cs = ct.items.items, len = cs.length, c, i, last = len-1, cm; - - if(!this.innerCt){ - target.addClass(this.ctCls); - - // the innerCt prevents wrapping and shuffling while - // the container is resizing - this.innerCt = target.createChild({cls:this.innerCls}); - this.padding = this.parseMargins(this.padding); - } - this.renderAll(ct, this.innerCt); - }, - - // private - renderItem : function(c){ - if(typeof c.margins == 'string'){ - c.margins = this.parseMargins(c.margins); - }else if(!c.margins){ - c.margins = this.defaultMargins; - } - Ext.layout.BoxLayout.superclass.renderItem.apply(this, arguments); - }, - - getTargetSize : function(target){ - return (Ext.isIE6 && Ext.isStrict && target.dom == document.body) ? target.getStyleSize() : target.getViewSize(); - }, - - getItems: function(ct){ - var items = []; - ct.items.each(function(c){ - if(c.isVisible()){ - items.push(c); - } - }); - return items; - } - - /** - * @property activeItem - * @hide - */ -}); - -/** - * @class Ext.layout.VBoxLayout - * @extends Ext.layout.BoxLayout - * A layout that arranges items vertically - */ -Ext.layout.VBoxLayout = Ext.extend(Ext.layout.BoxLayout, { - /** - * @cfg {String} align - * Controls how the child items of the container are aligned. Acceptable configuration values for this - * property are: - *
      - *
    • left : Default
      child items are aligned horizontally - * at the left side of the container
    • - *
    • center :
      child items are aligned horizontally at the - * mid-width of the container
    • - *
    • stretch :
      child items are stretched horizontally to fill - * the width of the container
    • - *
    • stretchmax :
      child items are stretched horizontally to - * the size of the largest item.
    • - *
    - */ - align : 'left', // left, center, stretch, strechmax - /** - * @cfg {String} pack - * Controls how the child items of the container are packed together. Acceptable configuration values - * for this property are: - *
      - *
    • start : Default
      child items are packed together at - * top side of container
    • - *
    • center :
      child items are packed together at - * mid-height of container
    • - *
    • end :
      child items are packed together at bottom - * side of container
    • - *
    - */ - /** - * @cfg {Number} flex - * This configuation option is to be applied to child items of the container managed - * by this layout. Each child item with a flex property will be flexed vertically - * according to each item's relative flex value compared to the sum of all items with - * a flex value specified. Any child items that have either a flex = 0 or - * flex = undefined will not be 'flexed' (the initial size will not be changed). - */ - - // private - onLayout : function(ct, target){ - Ext.layout.VBoxLayout.superclass.onLayout.call(this, ct, target); - - - var cs = this.getItems(ct), cm, ch, margin, - size = this.getTargetSize(target), - w = size.width - target.getPadding('lr') - this.scrollOffset, - h = size.height - target.getPadding('tb'), - l = this.padding.left, t = this.padding.top, - isStart = this.pack == 'start', - isRestore = ['stretch', 'stretchmax'].indexOf(this.align) == -1, - stretchWidth = w - (this.padding.left + this.padding.right), - extraHeight = 0, - maxWidth = 0, - totalFlex = 0, - flexHeight = 0, - usedHeight = 0; - - Ext.each(cs, function(c){ - cm = c.margins; - totalFlex += c.flex || 0; - ch = c.getHeight(); - margin = cm.top + cm.bottom; - extraHeight += ch + margin; - flexHeight += margin + (c.flex ? 0 : ch); - maxWidth = Math.max(maxWidth, c.getWidth() + cm.left + cm.right); - }); - extraHeight = h - extraHeight - this.padding.top - this.padding.bottom; - - var innerCtWidth = maxWidth + this.padding.left + this.padding.right; - switch(this.align){ - case 'stretch': - this.innerCt.setSize(w, h); - break; - case 'stretchmax': - case 'left': - this.innerCt.setSize(innerCtWidth, h); - break; - case 'center': - this.innerCt.setSize(w = Math.max(w, innerCtWidth), h); - break; - } - - var availHeight = Math.max(0, h - this.padding.top - this.padding.bottom - flexHeight), - leftOver = availHeight, - heights = [], - restore = [], - idx = 0, - availableWidth = Math.max(0, w - this.padding.left - this.padding.right); - - - Ext.each(cs, function(c){ - if(isStart && c.flex){ - ch = Math.floor(availHeight * (c.flex / totalFlex)); - leftOver -= ch; - heights.push(ch); - } - }); - - if(this.pack == 'center'){ - t += extraHeight ? extraHeight / 2 : 0; - }else if(this.pack == 'end'){ - t += extraHeight; - } - Ext.each(cs, function(c){ - cm = c.margins; - t += cm.top; - c.setPosition(l + cm.left, t); - if(isStart && c.flex){ - ch = Math.max(0, heights[idx++] + (leftOver-- > 0 ? 1 : 0)); - if(isRestore){ - restore.push(c.getWidth()); - } - c.setSize(availableWidth, ch); - }else{ - ch = c.getHeight(); - } - t += ch + cm.bottom; - }); - - idx = 0; - Ext.each(cs, function(c){ - cm = c.margins; - if(this.align == 'stretch'){ - c.setWidth((stretchWidth - (cm.left + cm.right)).constrain( - c.minWidth || 0, c.maxWidth || 1000000)); - }else if(this.align == 'stretchmax'){ - c.setWidth((maxWidth - (cm.left + cm.right)).constrain( - c.minWidth || 0, c.maxWidth || 1000000)); - }else{ - if(this.align == 'center'){ - var diff = availableWidth - (c.getWidth() + cm.left + cm.right); - if(diff > 0){ - c.setPosition(l + cm.left + (diff/2), c.y); - } - } - if(isStart && c.flex){ - c.setWidth(restore[idx++]); - } - } - }, this); - } - /** - * @property activeItem - * @hide - */ -}); - -Ext.Container.LAYOUTS.vbox = Ext.layout.VBoxLayout; - -/** - * @class Ext.layout.HBoxLayout - * @extends Ext.layout.BoxLayout - * A layout that arranges items horizontally - */ -Ext.layout.HBoxLayout = Ext.extend(Ext.layout.BoxLayout, { - /** - * @cfg {String} align - * Controls how the child items of the container are aligned. Acceptable configuration values for this - * property are: - *
      - *
    • top : Default
      child items are aligned vertically - * at the left side of the container
    • - *
    • middle :
      child items are aligned vertically at the - * mid-height of the container
    • - *
    • stretch :
      child items are stretched vertically to fill - * the height of the container
    • - *
    • stretchmax :
      child items are stretched vertically to - * the size of the largest item.
    • - */ - align : 'top', // top, middle, stretch, strechmax - /** - * @cfg {String} pack - * Controls how the child items of the container are packed together. Acceptable configuration values - * for this property are: - *
        - *
      • start : Default
        child items are packed together at - * left side of container
      • - *
      • center :
        child items are packed together at - * mid-width of container
      • - *
      • end :
        child items are packed together at right - * side of container
      • - *
      - */ - /** - * @cfg {Number} flex - * This configuation option is to be applied to child items of the container managed - * by this layout. Each child item with a flex property will be flexed horizontally - * according to each item's relative flex value compared to the sum of all items with - * a flex value specified. Any child items that have either a flex = 0 or - * flex = undefined will not be 'flexed' (the initial size will not be changed). - */ - - // private - onLayout : function(ct, target){ - Ext.layout.HBoxLayout.superclass.onLayout.call(this, ct, target); - - var cs = this.getItems(ct), cm, cw, margin, - size = this.getTargetSize(target), - w = size.width - target.getPadding('lr') - this.scrollOffset, - h = size.height - target.getPadding('tb'), - l = this.padding.left, t = this.padding.top, - isStart = this.pack == 'start', - isRestore = ['stretch', 'stretchmax'].indexOf(this.align) == -1, - stretchHeight = h - (this.padding.top + this.padding.bottom), - extraWidth = 0, - maxHeight = 0, - totalFlex = 0, - flexWidth = 0, - usedWidth = 0; - - Ext.each(cs, function(c){ - cm = c.margins; - totalFlex += c.flex || 0; - cw = c.getWidth(); - margin = cm.left + cm.right; - extraWidth += cw + margin; - flexWidth += margin + (c.flex ? 0 : cw); - maxHeight = Math.max(maxHeight, c.getHeight() + cm.top + cm.bottom); - }); - extraWidth = w - extraWidth - this.padding.left - this.padding.right; - - var innerCtHeight = maxHeight + this.padding.top + this.padding.bottom; - switch(this.align){ - case 'stretch': - this.innerCt.setSize(w, h); - break; - case 'stretchmax': - case 'top': - this.innerCt.setSize(w, innerCtHeight); - break; - case 'middle': - this.innerCt.setSize(w, h = Math.max(h, innerCtHeight)); - break; - } - - - var availWidth = Math.max(0, w - this.padding.left - this.padding.right - flexWidth), - leftOver = availWidth, - widths = [], - restore = [], - idx = 0, - availableHeight = Math.max(0, h - this.padding.top - this.padding.bottom); - - - Ext.each(cs, function(c){ - if(isStart && c.flex){ - cw = Math.floor(availWidth * (c.flex / totalFlex)); - leftOver -= cw; - widths.push(cw); - } - }); - - if(this.pack == 'center'){ - l += extraWidth ? extraWidth / 2 : 0; - }else if(this.pack == 'end'){ - l += extraWidth; - } - Ext.each(cs, function(c){ - cm = c.margins; - l += cm.left; - c.setPosition(l, t + cm.top); - if(isStart && c.flex){ - cw = Math.max(0, widths[idx++] + (leftOver-- > 0 ? 1 : 0)); - if(isRestore){ - restore.push(c.getHeight()); - } - c.setSize(cw, availableHeight); - }else{ - cw = c.getWidth(); - } - l += cw + cm.right; - }); - - idx = 0; - Ext.each(cs, function(c){ - var cm = c.margins; - if(this.align == 'stretch'){ - c.setHeight((stretchHeight - (cm.top + cm.bottom)).constrain( - c.minHeight || 0, c.maxHeight || 1000000)); - }else if(this.align == 'stretchmax'){ - c.setHeight((maxHeight - (cm.top + cm.bottom)).constrain( - c.minHeight || 0, c.maxHeight || 1000000)); - }else{ - if(this.align == 'middle'){ - var diff = availableHeight - (c.getHeight() + cm.top + cm.bottom); - if(diff > 0){ - c.setPosition(c.x, t + cm.top + (diff/2)); - } - } - if(isStart && c.flex){ - c.setHeight(restore[idx++]); - } - } - }, this); - } - - /** - * @property activeItem - * @hide - */ -}); - -Ext.Container.LAYOUTS.hbox = Ext.layout.HBoxLayout; -/** - * @class Ext.Viewport - * @extends Ext.Container - *

      A specialized container representing the viewable application area (the browser viewport).

      - *

      The Viewport renders itself to the document body, and automatically sizes itself to the size of - * the browser viewport and manages window resizing. There may only be one Viewport created - * in a page. Inner layouts are available by virtue of the fact that all {@link Ext.Panel Panel}s - * added to the Viewport, either through its {@link #items}, or through the items, or the {@link #add} - * method of any of its child Panels may themselves have a layout.

      - *

      The Viewport does not provide scrolling, so child Panels within the Viewport should provide - * for scrolling if needed using the {@link #autoScroll} config.

      - *

      An example showing a classic application border layout:

      
      -new Ext.Viewport({
      -    layout: 'border',
      -    items: [{
      -        region: 'north',
      -        html: '<h1 class="x-panel-header">Page Title</h1>',
      -        autoHeight: true,
      -        border: false,
      -        margins: '0 0 5 0'
      -    }, {
      -        region: 'west',
      -        collapsible: true,
      -        title: 'Navigation',
      -        width: 200
      -        // the west region might typically utilize a {@link Ext.tree.TreePanel TreePanel} or a Panel with {@link Ext.layout.AccordionLayout Accordion layout} 
      -    }, {
      -        region: 'south',
      -        title: 'Title for Panel',
      -        collapsible: true,
      -        html: 'Information goes here',
      -        split: true,
      -        height: 100,
      -        minHeight: 100
      -    }, {
      -        region: 'east',
      -        title: 'Title for the Grid Panel',
      -        collapsible: true,
      -        split: true,
      -        width: 200,
      -        xtype: 'grid',
      -        // remaining grid configuration not shown ...
      -        // notice that the GridPanel is added directly as the region
      -        // it is not "overnested" inside another Panel
      -    }, {
      -        region: 'center',
      -        xtype: 'tabpanel', // TabPanel itself has no title
      -        items: {
      -            title: 'Default Tab',
      -            html: 'The first tab\'s content. Others may be added dynamically'
      -        }
      -    }]
      -});
      -
      - * @constructor - * Create a new Viewport - * @param {Object} config The config object - * @xtype viewport - */ -Ext.Viewport = Ext.extend(Ext.Container, { - /* - * Privatize config options which, if used, would interfere with the - * correct operation of the Viewport as the sole manager of the - * layout of the document body. - */ - /** - * @cfg {Mixed} applyTo @hide - */ - /** - * @cfg {Boolean} allowDomMove @hide - */ - /** - * @cfg {Boolean} hideParent @hide - */ - /** - * @cfg {Mixed} renderTo @hide - */ - /** - * @cfg {Boolean} hideParent @hide - */ - /** - * @cfg {Number} height @hide - */ - /** - * @cfg {Number} width @hide - */ - /** - * @cfg {Boolean} autoHeight @hide - */ - /** - * @cfg {Boolean} autoWidth @hide - */ - /** - * @cfg {Boolean} deferHeight @hide - */ - /** - * @cfg {Boolean} monitorResize @hide - */ - initComponent : function() { - Ext.Viewport.superclass.initComponent.call(this); - document.getElementsByTagName('html')[0].className += ' x-viewport'; - this.el = Ext.getBody(); - this.el.setHeight = Ext.emptyFn; - this.el.setWidth = Ext.emptyFn; - this.el.setSize = Ext.emptyFn; - this.el.dom.scroll = 'no'; - this.allowDomMove = false; - this.autoWidth = true; - this.autoHeight = true; - Ext.EventManager.onWindowResize(this.fireResize, this); - this.renderTo = this.el; - }, - - fireResize : function(w, h){ - this.fireEvent('resize', this, w, h, w, h); - } -}); -Ext.reg('viewport', Ext.Viewport);/** - * @class Ext.Panel - * @extends Ext.Container - *

      Panel is a container that has specific functionality and structural components that make - * it the perfect building block for application-oriented user interfaces.

      - *

      Panels are, by virtue of their inheritance from {@link Ext.Container}, capable - * of being configured with a {@link Ext.Container#layout layout}, and containing child Components.

      - *

      When either specifying child {@link Ext.Component#items items} of a Panel, or dynamically {@link Ext.Container#add adding} Components - * to a Panel, remember to consider how you wish the Panel to arrange those child elements, and whether - * those child elements need to be sized using one of Ext's built-in {@link Ext.Container#layout layout} schemes. By - * default, Panels use the {@link Ext.layout.ContainerLayout ContainerLayout} scheme. This simply renders - * child components, appending them one after the other inside the Container, and does not apply any sizing - * at all.

      - *

      A Panel may also contain {@link #bbar bottom} and {@link #tbar top} toolbars, along with separate - * {@link #header}, {@link #footer} and {@link #body} sections (see {@link #frame} for additional - * information).

      - *

      Panel also provides built-in {@link #collapsible expandable and collapsible behavior}, along with - * a variety of {@link #tools prebuilt tool buttons} that can be wired up to provide other customized - * behavior. Panels can be easily dropped into any {@link Ext.Container Container} or layout, and the - * layout and rendering pipeline is {@link Ext.Container#add completely managed by the framework}.

      - * @constructor - * @param {Object} config The config object - * @xtype panel +Ext.Container.LAYOUTS['table'] = Ext.layout.TableLayout;/** + * @class Ext.layout.AbsoluteLayout + * @extends Ext.layout.AnchorLayout + *

      This is a layout that inherits the anchoring of {@link Ext.layout.AnchorLayout} and adds the + * ability for x/y positioning using the standard x and y component config options.

      + *

      This class is intended to be extended or created via the {@link Ext.Container#layout layout} + * configuration property. See {@link Ext.Container#layout} for additional details.

      + *

      Example usage:

      + *
      
      +var form = new Ext.form.FormPanel({
      +    title: 'Absolute Layout',
      +    layout:'absolute',
      +    layoutConfig: {
      +        // layout-specific configs go here
      +        extraCls: 'x-abs-layout-item',
      +    },
      +    baseCls: 'x-plain',
      +    url:'save-form.php',
      +    defaultType: 'textfield',
      +    items: [{
      +        x: 0,
      +        y: 5,
      +        xtype:'label',
      +        text: 'Send To:'
      +    },{
      +        x: 60,
      +        y: 0,
      +        name: 'to',
      +        anchor:'100%'  // anchor width by percentage
      +    },{
      +        x: 0,
      +        y: 35,
      +        xtype:'label',
      +        text: 'Subject:'
      +    },{
      +        x: 60,
      +        y: 30,
      +        name: 'subject',
      +        anchor: '100%'  // anchor width by percentage
      +    },{
      +        x:0,
      +        y: 60,
      +        xtype: 'textarea',
      +        name: 'msg',
      +        anchor: '100% 100%'  // anchor width and height
      +    }]
      +});
      +
      */ -Ext.Panel = Ext.extend(Ext.Container, { - /** - * The Panel's header {@link Ext.Element Element}. Read-only. - *

      This Element is used to house the {@link #title} and {@link #tools}

      - *

      Note: see the Note for {@link Ext.Component#el el} also.

      - * @type Ext.Element - * @property header - */ +Ext.layout.AbsoluteLayout = Ext.extend(Ext.layout.AnchorLayout, { + + extraCls: 'x-abs-layout-item', + + type: 'anchor', + + onLayout : function(ct, target){ + target.position(); + this.paddingLeft = target.getPadding('l'); + this.paddingTop = target.getPadding('t'); + Ext.layout.AbsoluteLayout.superclass.onLayout.call(this, ct, target); + }, + + // private + adjustWidthAnchor : function(value, comp){ + return value ? value - comp.getPosition(true)[0] + this.paddingLeft : value; + }, + + // private + adjustHeightAnchor : function(value, comp){ + return value ? value - comp.getPosition(true)[1] + this.paddingTop : value; + } /** - * The Panel's body {@link Ext.Element Element} which may be used to contain HTML content. - * The content may be specified in the {@link #html} config, or it may be loaded using the - * {@link autoLoad} config, or through the Panel's {@link #getUpdater Updater}. Read-only. - *

      If this is used to load visible HTML elements in either way, then - * the Panel may not be used as a Layout for hosting nested Panels.

      - *

      If this Panel is intended to be used as the host of a Layout (See {@link #layout} - * then the body Element must not be loaded or changed - it is under the control - * of the Panel's Layout. - *

      Note: see the Note for {@link Ext.Component#el el} also.

      - * @type Ext.Element - * @property body + * @property activeItem + * @hide */ - /** - * The Panel's bwrap {@link Ext.Element Element} used to contain other Panel elements - * (tbar, body, bbar, footer). See {@link #bodyCfg}. Read-only. - * @type Ext.Element - * @property bwrap +}); +Ext.Container.LAYOUTS['absolute'] = Ext.layout.AbsoluteLayout; +/** + * @class Ext.layout.BoxLayout + * @extends Ext.layout.ContainerLayout + *

      Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.

      + */ +Ext.layout.BoxLayout = Ext.extend(Ext.layout.ContainerLayout, { + /** + * @cfg {Object} defaultMargins + *

      If the individual contained items do not have a margins + * property specified, the default margins from this property will be + * applied to each item.

      + *

      This property may be specified as an object containing margins + * to apply in the format:

      
      +{
      +    top: (top margin),
      +    right: (right margin),
      +    bottom: (bottom margin),
      +    left: (left margin)
      +}
      + *

      This property may also be specified as a string containing + * space-separated, numeric margin values. The order of the sides associated + * with each value matches the way CSS processes margin values:

      + *
        + *
      • If there is only one value, it applies to all sides.
      • + *
      • If there are two values, the top and bottom borders are set to the + * first value and the right and left are set to the second.
      • + *
      • If there are three values, the top is set to the first value, the left + * and right are set to the second, and the bottom is set to the third.
      • + *
      • If there are four values, they apply to the top, right, bottom, and + * left, respectively.
      • + *
      + *

      Defaults to:

      
      +     * {top:0, right:0, bottom:0, left:0}
      +     * 
      */ + defaultMargins : {left:0,top:0,right:0,bottom:0}, /** - * True if this panel is collapsed. Read-only. - * @type Boolean - * @property collapsed + * @cfg {String} padding + *

      Sets the padding to be applied to all child items managed by this layout.

      + *

      This property must be specified as a string containing + * space-separated, numeric padding values. The order of the sides associated + * with each value matches the way CSS processes padding values:

      + *
        + *
      • If there is only one value, it applies to all sides.
      • + *
      • If there are two values, the top and bottom borders are set to the + * first value and the right and left are set to the second.
      • + *
      • If there are three values, the top is set to the first value, the left + * and right are set to the second, and the bottom is set to the third.
      • + *
      • If there are four values, they apply to the top, right, bottom, and + * left, respectively.
      • + *
      + *

      Defaults to: "0"

      */ - /** - * @cfg {Object} bodyCfg - *

      A {@link Ext.DomHelper DomHelper} element specification object may be specified for any - * Panel Element.

      - *

      By default, the Default element in the table below will be used for the html markup to - * create a child element with the commensurate Default class name (baseCls will be - * replaced by {@link #baseCls}):

      - *
      -     * Panel      Default  Default             Custom      Additional       Additional
      -     * Element    element  class               element     class            style
      -     * ========   ==========================   =========   ==============   ===========
      -     * {@link #header}     div      {@link #baseCls}+'-header'   {@link #headerCfg}   headerCssClass   headerStyle
      -     * {@link #bwrap}      div      {@link #baseCls}+'-bwrap'     {@link #bwrapCfg}    bwrapCssClass    bwrapStyle
      -     * + tbar     div      {@link #baseCls}+'-tbar'       {@link #tbarCfg}     tbarCssClass     tbarStyle
      -     * + {@link #body}     div      {@link #baseCls}+'-body'       {@link #bodyCfg}     {@link #bodyCssClass}     {@link #bodyStyle}
      -     * + bbar     div      {@link #baseCls}+'-bbar'       {@link #bbarCfg}     bbarCssClass     bbarStyle
      -     * + {@link #footer}   div      {@link #baseCls}+'-footer'   {@link #footerCfg}   footerCssClass   footerStyle
      -     * 
      - *

      Configuring a Custom element may be used, for example, to force the {@link #body} Element - * to use a different form of markup than is created by default. An example of this might be - * to {@link Ext.Element#createChild create a child} Panel containing a custom content, such as - * a header, or forcing centering of all Panel content by having the body be a <center> - * element:

      - *
      
      -new Ext.Panel({
      -    title: 'Message Title',
      -    renderTo: Ext.getBody(),
      -    width: 200, height: 130,
      -    bodyCfg: {
      -        tag: 'center',
      -        cls: 'x-panel-body',  // Default class not applied if Custom element specified
      -        html: 'Message'
      +    padding : '0',
      +    // documented in subclasses
      +    pack : 'start',
      +
      +    // private
      +    monitorResize : true,
      +    type: 'box',
      +    scrollOffset : 0,
      +    extraCls : 'x-box-item',
      +    targetCls : 'x-box-layout-ct',
      +    innerCls : 'x-box-inner',
      +
      +    constructor : function(config){
      +        Ext.layout.BoxLayout.superclass.constructor.call(this, config);
      +        if(Ext.isString(this.defaultMargins)){
      +            this.defaultMargins = this.parseMargins(this.defaultMargins);
      +        }
           },
      -    footerCfg: {
      -        tag: 'h2',
      -        cls: 'x-panel-footer'        // same as the Default class
      -        html: 'footer html'
      +
      +    // private
      +    isValidParent : function(c, target){
      +        return this.innerCt && c.getPositionEl().dom.parentNode == this.innerCt.dom;
           },
      -    footerCssClass: 'custom-footer', // additional css class, see {@link Ext.element#addClass addClass}
      -    footerStyle:    'background-color:red' // see {@link #bodyStyle}
      +
      +    // private
      +    renderAll : function(ct, target){
      +        if(!this.innerCt){
      +            // the innerCt prevents wrapping and shuffling while
      +            // the container is resizing
      +            this.innerCt = target.createChild({cls:this.innerCls});
      +            this.padding = this.parseMargins(this.padding);
      +        }
      +        Ext.layout.BoxLayout.superclass.renderAll.call(this, ct, this.innerCt);
      +    },
      +
      +    onLayout : function(ct, target){
      +        this.renderAll(ct, target);
      +    },
      +
      +    getLayoutTargetSize : function(){
      +        var target = this.container.getLayoutTarget(), ret;
      +        if (target) {
      +            ret = target.getViewSize();
      +            ret.width -= target.getPadding('lr');
      +            ret.height -= target.getPadding('tb');
      +        }
      +        return ret;
      +    },
      +
      +    // private
      +    renderItem : function(c){
      +        if(Ext.isString(c.margins)){
      +            c.margins = this.parseMargins(c.margins);
      +        }else if(!c.margins){
      +            c.margins = this.defaultMargins;
      +        }
      +        Ext.layout.BoxLayout.superclass.renderItem.apply(this, arguments);
      +    }
       });
      -     * 
      - *

      The example above also explicitly creates a {@link #footer} with custom markup and - * styling applied.

      - */ - /** - * @cfg {Object} headerCfg - *

      A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure - * of this Panel's {@link #header} Element. See {@link #bodyCfg} also.

      - */ - /** - * @cfg {Object} bwrapCfg - *

      A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure - * of this Panel's {@link #bwrap} Element. See {@link #bodyCfg} also.

      - */ - /** - * @cfg {Object} tbarCfg - *

      A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure - * of this Panel's {@link #tbar} Element. See {@link #bodyCfg} also.

      - */ - /** - * @cfg {Object} bbarCfg - *

      A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure - * of this Panel's {@link #bbar} Element. See {@link #bodyCfg} also.

      - */ - /** - * @cfg {Object} footerCfg - *

      A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure - * of this Panel's {@link #footer} Element. See {@link #bodyCfg} also.

      - */ - /** - * @cfg {Boolean} closable - * Panels themselves do not directly support being closed, but some Panel subclasses do (like - * {@link Ext.Window}) or a Panel Class within an {@link Ext.TabPanel}. Specify true - * to enable closing in such situations. Defaults to false. - */ - /** - * The Panel's footer {@link Ext.Element Element}. Read-only. - *

      This Element is used to house the Panel's {@link #buttons} or {@link #fbar}.

      - *

      Note: see the Note for {@link Ext.Component#el el} also.

      - * @type Ext.Element - * @property footer - */ - /** - * @cfg {Mixed} applyTo - *

      The id of the node, a DOM node or an existing Element corresponding to a DIV that is already present in - * the document that specifies some panel-specific structural markup. When applyTo is used, - * constituent parts of the panel can be specified by CSS class name within the main element, and the panel - * will automatically create those components from that markup. Any required components not specified in the - * markup will be autogenerated if necessary.

      - *

      The following class names are supported (baseCls will be replaced by {@link #baseCls}):

      - *
      • baseCls + '-header'
      • - *
      • baseCls + '-header-text'
      • - *
      • baseCls + '-bwrap'
      • - *
      • baseCls + '-tbar'
      • - *
      • baseCls + '-body'
      • - *
      • baseCls + '-bbar'
      • - *
      • baseCls + '-footer'
      - *

      Using this config, a call to render() is not required. If applyTo is specified, any value passed for - * {@link #renderTo} will be ignored and the target element's parent node will automatically be used as the - * panel's container.

      - */ - /** - * @cfg {Object/Array} tbar - *

      The top toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of - * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render. - * To access the top toolbar after render, use {@link #getTopToolbar}.

      - *

      Note: Although a Toolbar may contain Field components, these will not be updated by a load - * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and - * so are not scanned to collect form items. However, the values will be submitted because form - * submission parameters are collected from the DOM tree.

      - */ - /** - * @cfg {Object/Array} bbar - *

      The bottom toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of - * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render. - * To access the bottom toolbar after render, use {@link #getBottomToolbar}.

      - *

      Note: Although a Toolbar may contain Field components, these will not be updated by a load - * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and - * so are not scanned to collect form items. However, the values will be submitted because form - * submission parameters are collected from the DOM tree.

      - */ - /** @cfg {Object/Array} fbar - *

      A {@link Ext.Toolbar Toolbar} object, a Toolbar config, or an array of - * {@link Ext.Button Button}s/{@link Ext.Button Button} configs, describing a {@link Ext.Toolbar Toolbar} to be rendered into this Panel's footer element.

      - *

      After render, the fbar property will be an {@link Ext.Toolbar Toolbar} instance.

      - *

      If {@link #buttons} are specified, they will supersede the fbar configuration property.

      - * The Panel's {@link #buttonAlign} configuration affects the layout of these items, for example: - *
      
      -var w = new Ext.Window({
      -    height: 250,
      -    width: 500,
      -    bbar: new Ext.Toolbar({
      -        items: [{
      -            text: 'bbar Left'
      -        },'->',{
      -            text: 'bbar Right'
      -        }]
      -    }),
      -    {@link #buttonAlign}: 'left', // anything but 'center' or 'right' and you can use "-", and "->"
      -                                  // to control the alignment of fbar items
      -    fbar: [{
      -        text: 'fbar Left'
      -    },'->',{
      -        text: 'fbar Right'
      -    }]
      -}).show();
      -     * 
      - *

      Note: Although a Toolbar may contain Field components, these will not be updated by a load - * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and - * so are not scanned to collect form items. However, the values will be submitted because form - * submission parameters are collected from the DOM tree.

      - */ - /** - * @cfg {Boolean} header - * true to create the Panel's header element explicitly, false to skip creating - * it. If a {@link #title} is set the header will be created automatically, otherwise it will not. - * If a {@link #title} is set but header is explicitly set to false, the header - * will not be rendered. - */ - /** - * @cfg {Boolean} footer - * true to create the footer element explicitly, false to skip creating it. The footer - * will be created automatically if {@link #buttons} or a {@link #fbar} have - * been configured. See {@link #bodyCfg} for an example. - */ + +/** + * @class Ext.layout.VBoxLayout + * @extends Ext.layout.BoxLayout + *

      A layout that arranges items vertically down a Container. This layout optionally divides available vertical + * space between child items containing a numeric flex configuration.

      + * This layout may also be used to set the widths of child items by configuring it with the {@link #align} option. + */ +Ext.layout.VBoxLayout = Ext.extend(Ext.layout.BoxLayout, { /** - * @cfg {String} title - * The title text to be used as innerHTML (html tags are accepted) to display in the panel - * {@link #header} (defaults to ''). When a title is specified the - * {@link #header} element will automatically be created and displayed unless - * {@link #header} is explicitly set to false. If you do not want to specify a - * title at config time, but you may want one later, you must either specify a non-empty - * title (a blank space ' ' will do) or header:true so that the container - * element will get created. + * @cfg {String} align + * Controls how the child items of the container are aligned. Acceptable configuration values for this + * property are: + *
        + *
      • left : Default
        child items are aligned horizontally + * at the left side of the container
      • + *
      • center :
        child items are aligned horizontally at the + * mid-width of the container
      • + *
      • stretch :
        child items are stretched horizontally to fill + * the width of the container
      • + *
      • stretchmax :
        child items are stretched horizontally to + * the size of the largest item.
      • + *
      */ + align : 'left', // left, center, stretch, strechmax + type: 'vbox', /** - * @cfg {Array} buttons - * buttons will be used as {@link Ext.Container#items items} for the toolbar in - * the footer ({@link #fbar}). Typically the value of this configuration property will be - * an array of {@link Ext.Button}s or {@link Ext.Button} configuration objects. - * If an item is configured with minWidth or the Panel is configured with minButtonWidth, - * that width will be applied to the item. + * @cfg {String} pack + * Controls how the child items of the container are packed together. Acceptable configuration values + * for this property are: + *
        + *
      • start : Default
        child items are packed together at + * top side of container
      • + *
      • center :
        child items are packed together at + * mid-height of container
      • + *
      • end :
        child items are packed together at bottom + * side of container
      • + *
      */ /** - * @cfg {Object/String/Function} autoLoad - * A valid url spec according to the Updater {@link Ext.Updater#update} method. - * If autoLoad is not null, the panel will attempt to load its contents - * immediately upon render.

      - * The URL will become the default URL for this panel's {@link #body} element, - * so it may be {@link Ext.Element#refresh refresh}ed at any time.

      + * @cfg {Number} flex + * This configuation option is to be applied to child items of the container managed + * by this layout. Each child item with a flex property will be flexed vertically + * according to each item's relative flex value compared to the sum of all items with + * a flex value specified. Any child items that have either a flex = 0 or + * flex = undefined will not be 'flexed' (the initial size will not be changed). */ - /** - * @cfg {Boolean} frame - * false by default to render with plain 1px square borders. true to render with - * 9 elements, complete with custom rounded corners (also see {@link Ext.Element#boxWrap}). - *

      The template generated for each condition is depicted below:

      
      -     *
      -// frame = false
      -<div id="developer-specified-id-goes-here" class="x-panel">
       
      -    <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:false)</span></div>
      +    // private
      +    onLayout : function(ct, target){
      +        Ext.layout.VBoxLayout.superclass.onLayout.call(this, ct, target);
      +
      +        var cs = this.getRenderedItems(ct), csLen = cs.length,
      +            c, i, cm, ch, margin, cl, diff, aw, availHeight,
      +            size = this.getLayoutTargetSize(),
      +            w = size.width,
      +            h = size.height - this.scrollOffset,
      +            l = this.padding.left,
      +            t = this.padding.top,
      +            isStart = this.pack == 'start',
      +            extraHeight = 0,
      +            maxWidth = 0,
      +            totalFlex = 0,
      +            usedHeight = 0,
      +            idx = 0,
      +            heights = [],
      +            restore = [];
      +
      +        // Do only width calculations and apply those first, as they can affect height
      +        for (i = 0 ; i < csLen; i++) {
      +            c = cs[i];
      +            cm = c.margins;
      +            margin = cm.top + cm.bottom;
      +            // Max height for align
      +            maxWidth = Math.max(maxWidth, c.getWidth() + cm.left + cm.right);
      +        }
      +
      +        var innerCtWidth = maxWidth + this.padding.left + this.padding.right;
      +        switch(this.align){
      +            case 'stretch':
      +                this.innerCt.setSize(w, h);
      +                break;
      +            case 'stretchmax':
      +            case 'left':
      +                this.innerCt.setSize(innerCtWidth, h);
      +                break;
      +            case 'center':
      +                this.innerCt.setSize(w = Math.max(w, innerCtWidth), h);
      +                break;
      +        }
       
      -    <div class="x-panel-bwrap">
      -        <div class="x-panel-body"><p>html value goes here</p></div>
      -    </div>
      -</div>
      +        var availableWidth = Math.max(0, w - this.padding.left - this.padding.right);
      +        // Apply widths
      +        for (i = 0 ; i < csLen; i++) {
      +            c = cs[i];
      +            cm = c.margins;
      +            if(this.align == 'stretch'){
      +                c.setWidth(((w - (this.padding.left + this.padding.right)) - (cm.left + cm.right)).constrain(
      +                    c.minWidth || 0, c.maxWidth || 1000000));
      +            }else if(this.align == 'stretchmax'){
      +                c.setWidth((maxWidth - (cm.left + cm.right)).constrain(
      +                    c.minWidth || 0, c.maxWidth || 1000000));
      +            }else if(isStart && c.flex){
      +                c.setWidth();
      +            }
       
      -// frame = true (create 9 elements)
      -<div id="developer-specified-id-goes-here" class="x-panel">
      -    <div class="x-panel-tl"><div class="x-panel-tr"><div class="x-panel-tc">
      -        <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:true)</span></div>
      -    </div></div></div>
      +        }
       
      -    <div class="x-panel-bwrap">
      -        <div class="x-panel-ml"><div class="x-panel-mr"><div class="x-panel-mc">
      -            <div class="x-panel-body"><p>html value goes here</p></div>
      -        </div></div></div>
      +        // Height calculations
      +        for (i = 0 ; i < csLen; i++) {
      +            c = cs[i];
      +            // Total of all the flex values
      +            totalFlex += c.flex || 0;
      +            // Don't run height calculations on flexed items
      +            if (!c.flex) {
      +                // Render and layout sub-containers without a flex or height, once
      +                if (!c.height && !c.hasLayout && c.doLayout) {
      +                    c.doLayout();
      +                }
      +                ch = c.getHeight();
      +            } else {
      +                ch = 0;
      +            }
       
      -        <div class="x-panel-bl"><div class="x-panel-br"><div class="x-panel-bc"/>
      -        </div></div></div>
      -</div>
      -     * 
      - */ - /** - * @cfg {Boolean} border - * True to display the borders of the panel's body element, false to hide them (defaults to true). By default, - * the border is a 2px wide inset border, but this can be further altered by setting {@link #bodyBorder} to false. - */ - /** - * @cfg {Boolean} bodyBorder - * True to display an interior border on the body element of the panel, false to hide it (defaults to true). - * This only applies when {@link #border} == true. If border == true and bodyBorder == false, the border will display - * as a 1px wide inset border, giving the entire body element an inset appearance. - */ - /** - * @cfg {String/Object/Function} bodyCssClass - * Additional css class selector to be applied to the {@link #body} element in the format expected by - * {@link Ext.Element#addClass} (defaults to null). See {@link #bodyCfg}. - */ - /** - * @cfg {String/Object/Function} bodyStyle - * Custom CSS styles to be applied to the {@link #body} element in the format expected by - * {@link Ext.Element#applyStyles} (defaults to null). See {@link #bodyCfg}. - */ - /** - * @cfg {String} iconCls - * The CSS class selector that specifies a background image to be used as the header icon (defaults to ''). - *

      An example of specifying a custom icon class would be something like: - *

      
      -// specify the property in the config for the class:
      -     ...
      -     iconCls: 'my-icon'
      +            cm = c.margins;
      +            // Determine how much height is available to flex
      +            extraHeight += ch + cm.top + cm.bottom;
      +        }
      +        // Final avail height calc
      +        availHeight = Math.max(0, (h - extraHeight - this.padding.top - this.padding.bottom));
       
      -// css class that specifies background image to be used as the icon image:
      -.my-icon { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
      -
      - */ - /** - * @cfg {Boolean} collapsible - * True to make the panel collapsible and have the expand/collapse toggle button automatically rendered into - * the header tool button area, false to keep the panel statically sized with no button (defaults to false). - */ - /** - * @cfg {Array} tools - * An array of tool button configs to be added to the header tool area. When rendered, each tool is - * stored as an {@link Ext.Element Element} referenced by a public property called tools.<tool-type> - *

      Each tool config may contain the following properties: - *

        - *
      • id : String
        Required. The type - * of tool to create. By default, this assigns a CSS class of the form x-tool-<tool-type> to the - * resulting tool Element. Ext provides CSS rules, and an icon sprite containing images for the tool types listed below. - * The developer may implement custom tools by supplying alternate CSS rules and background images: - *
          - *
          toggle (Created by default when {@link #collapsible} is true)
          - *
          close
          - *
          minimize
          - *
          maximize
          - *
          restore
          - *
          gear
          - *
          pin
          - *
          unpin
          - *
          right
          - *
          left
          - *
          up
          - *
          down
          - *
          refresh
          - *
          minus
          - *
          plus
          - *
          help
          - *
          search
          - *
          save
          - *
          print
          - *
      • - *
      • handler : Function
        Required. The function to - * call when clicked. Arguments passed are:
          - *
        • event : Ext.EventObject
          The click event.
        • - *
        • toolEl : Ext.Element
          The tool Element.
        • - *
        • panel : Ext.Panel
          The host Panel
        • - *
        • tc : Ext.Panel
          The tool configuration object
        • - *
      • - *
      • stopEvent : Boolean
        Defaults to true. Specify as false to allow click event to propagate.
      • - *
      • scope : Object
        The scope in which to call the handler.
      • - *
      • qtip : String/Object
        A tip string, or - * a config argument to {@link Ext.QuickTip#register}
      • - *
      • hidden : Boolean
        True to initially render hidden.
      • - *
      • on : Object
        A listener config object specifiying - * event listeners in the format of an argument to {@link #addListener}
      • - *
      - *

      Note that, apart from the toggle tool which is provided when a panel is collapsible, these - * tools only provide the visual button. Any required functionality must be provided by adding - * handlers that implement the necessary behavior.

      - *

      Example usage:

      - *
      
      -tools:[{
      -    id:'refresh',
      -    qtip: 'Refresh form Data',
      -    // hidden:true,
      -    handler: function(event, toolEl, panel){
      -        // refresh logic
      -    }
      -},
      -{
      -    id:'help',
      -    qtip: 'Get Help',
      -    handler: function(event, toolEl, panel){
      -        // whatever
      +        var leftOver = availHeight;
      +        for (i = 0 ; i < csLen; i++) {
      +            c = cs[i];
      +            if(isStart && c.flex){
      +                ch = Math.floor(availHeight * (c.flex / totalFlex));
      +                leftOver -= ch;
      +                heights.push(ch);
      +            }
      +        }
      +        if(this.pack == 'center'){
      +            t += availHeight ? availHeight / 2 : 0;
      +        }else if(this.pack == 'end'){
      +            t += availHeight;
      +        }
      +        idx = 0;
      +        // Apply heights
      +        for (i = 0 ; i < csLen; i++) {
      +            c = cs[i];
      +            cm = c.margins;
      +            t += cm.top;
      +            aw = availableWidth;
      +            cl = l + cm.left // default left pos
      +
      +            // Adjust left pos for centering
      +            if(this.align == 'center'){
      +                if((diff = availableWidth - (c.getWidth() + cm.left + cm.right)) > 0){
      +                    cl += (diff/2);
      +                    aw -= diff;
      +                }
      +            }
      +
      +            c.setPosition(cl, t);
      +            if(isStart && c.flex){
      +                ch = Math.max(0, heights[idx++] + (leftOver-- > 0 ? 1 : 0));
      +                c.setSize(aw, ch);
      +            }else{
      +                ch = c.getHeight();
      +            }
      +            t += ch + cm.bottom;
      +        }
      +        // Putting a box layout into an overflowed container is NOT correct and will make a second layout pass necessary.
      +        if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) {
      +            var ts = this.getLayoutTargetSize();
      +            if (ts.width != size.width || ts.height != size.height){
      +                this.adjustmentPass = true;
      +                this.onLayout(ct, target);
      +            }
      +        }
      +        delete this.adjustmentPass;
           }
      -}]
      -
      - *

      For the custom id of 'help' define two relevant css classes with a link to - * a 15x15 image:

      - *
      
      -.x-tool-help {background-image: url(images/help.png);}
      -.x-tool-help-over {background-image: url(images/help_over.png);}
      -// if using an image sprite:
      -.x-tool-help {background-image: url(images/help.png) no-repeat 0 0;}
      -.x-tool-help-over {background-position:-15px 0;}
      -
      - */ - /** - * @cfg {Ext.Template/Ext.XTemplate} toolTemplate - *

      A Template used to create {@link #tools} in the {@link #header} Element. Defaults to:

      
      -new Ext.Template('<div class="x-tool x-tool-{id}">&#160;</div>')
      - *

      This may may be overridden to provide a custom DOM structure for tools based upon a more - * complex XTemplate. The template's data is a single tool configuration object (Not the entire Array) - * as specified in {@link #tools}. In the following example an <a> tag is used to provide a - * visual indication when hovering over the tool:

      
      -var win = new Ext.Window({
      -    tools: [{
      -        id: 'download',
      -        href: '/MyPdfDoc.pdf'
      -    }],
      -    toolTemplate: new Ext.XTemplate(
      -        '<tpl if="id==\'download\'">',
      -            '<a class="x-tool x-tool-pdf" href="{href}"></a>',
      -        '</tpl>',
      -        '<tpl if="id!=\'download\'">',
      -            '<div class="x-tool x-tool-{id}">&#160;</div>',
      -        '</tpl>'
      -    ),
      -    width:500,
      -    height:300,
      -    closeAction:'hide'
      -});
      - *

      Note that the CSS class "x-tool-pdf" should have an associated style rule which provides an - * appropriate background image, something like:

      -
      
      -    a.x-tool-pdf {background-image: url(../shared/extjs/images/pdf.gif)!important;}
      -    
      - */ - /** - * @cfg {Boolean} hideCollapseTool - * true to hide the expand/collapse toggle button when {@link #collapsible} == true, - * false to display it (defaults to false). - */ - /** - * @cfg {Boolean} titleCollapse - * true to allow expanding and collapsing the panel (when {@link #collapsible} = true) - * by clicking anywhere in the header bar, false) to allow it only by clicking to tool button - * (defaults to false)). If this panel is a child item of a border layout also see the - * {@link Ext.layout.BorderLayout.Region BorderLayout.Region} - * {@link Ext.layout.BorderLayout.Region#floatable floatable} config option. - */ - /** - * @cfg {Boolean} autoScroll - * true to use overflow:'auto' on the panel's body element and show scroll bars automatically when - * necessary, false to clip any overflowing content (defaults to false). - */ - /** - * @cfg {Mixed} floating - *

      This property is used to configure the underlying {@link Ext.Layer}. Acceptable values for this - * configuration property are:

        - *
      • false : Default.
        Display the panel inline where it is - * rendered.
      • - *
      • true :
        Float the panel (absolute position it with automatic - * shimming and shadow).
          - *
          Setting floating to true will create an Ext.Layer for this panel and display the - * panel at negative offsets so that it is hidden.
          - *
          Since the panel will be absolute positioned, the position must be set explicitly - * after render (e.g., myPanel.setPosition(100,100);).
          - *
          Note: when floating a panel you should always assign a fixed width, - * otherwise it will be auto width and will expand to fill to the right edge of the viewport.
          - *
      • - *
      • {@link Ext.Layer object} :
        The specified object will be used - * as the configuration object for the {@link Ext.Layer} that will be created.
      • - *
      - */ - /** - * @cfg {Boolean/String} shadow - * true (or a valid Ext.Shadow {@link Ext.Shadow#mode} value) to display a shadow behind the - * panel, false to display no shadow (defaults to 'sides'). Note that this option - * only applies when {@link #floating} = true. - */ - /** - * @cfg {Number} shadowOffset - * The number of pixels to offset the shadow if displayed (defaults to 4). Note that this - * option only applies when {@link #floating} = true. - */ - /** - * @cfg {Boolean} shim - * false to disable the iframe shim in browsers which need one (defaults to true). - * Note that this option only applies when {@link #floating} = true. - */ - /** - * @cfg {String/Object} html - * An HTML fragment, or a {@link Ext.DomHelper DomHelper} specification to use as the panel's body - * content (defaults to ''). The HTML content is added by the Panel's {@link #afterRender} method, - * and so the document will not contain this HTML at the time the {@link #render} event is fired. - * This content is inserted into the body before any configured {@link #contentEl} is appended. - */ +}); + +Ext.Container.LAYOUTS.vbox = Ext.layout.VBoxLayout; + +/** + * @class Ext.layout.HBoxLayout + * @extends Ext.layout.BoxLayout + *

      A layout that arranges items horizontally across a Container. This layout optionally divides available horizontal + * space between child items containing a numeric flex configuration.

      + * This layout may also be used to set the heights of child items by configuring it with the {@link #align} option. + */ +Ext.layout.HBoxLayout = Ext.extend(Ext.layout.BoxLayout, { /** - * @cfg {String} contentEl - *

      Specify the id of an existing HTML node to use as the panel's body content - * (defaults to '').

        - *
      • Description :
          - *
          This config option is used to take an existing HTML element and place it in the body - * of a new panel (it simply moves the specified DOM element into the body element of the Panel - * when the Panel is rendered to use as the content (it is not going to be the - * actual panel itself).
          - *
      • - *
      • Notes :
          - *
          The specified HTML Element is appended to the Panel's {@link #body} Element by the - * Panel's {@link #afterRender} method after any configured {@link #html HTML} has - * been inserted, and so the document will not contain this HTML at the time the - * {@link #render} event is fired.
          - *
          The specified HTML element used will not participate in any layout scheme that the - * Panel may use. It's just HTML. Layouts operate on child items.
          - *
          Add either the x-hidden or the x-hide-display CSS class to - * prevent a brief flicker of the content before it is rendered to the panel.
          - *
      • + * @cfg {String} align + * Controls how the child items of the container are aligned. Acceptable configuration values for this + * property are: + *
          + *
        • top : Default
          child items are aligned vertically + * at the top of the container
        • + *
        • middle :
          child items are aligned vertically in the + * middle of the container
        • + *
        • stretch :
          child items are stretched vertically to fill + * the height of the container
        • + *
        • stretchmax :
          child items are stretched vertically to + * the height of the largest item.
        • + */ + align : 'top', // top, middle, stretch, strechmax + type: 'hbox', + /** + * @cfg {String} pack + * Controls how the child items of the container are packed together. Acceptable configuration values + * for this property are: + *
            + *
          • start : Default
            child items are packed together at + * left side of container
          • + *
          • center :
            child items are packed together at + * mid-width of container
          • + *
          • end :
            child items are packed together at right + * side of container
          • *
          */ /** - * @cfg {Object/Array} keys - * A {@link Ext.KeyMap} config object (in the format expected by {@link Ext.KeyMap#addBinding} - * used to assign custom key handling to this panel (defaults to null). + * @cfg {Number} flex + * This configuation option is to be applied to child items of the container managed + * by this layout. Each child item with a flex property will be flexed horizontally + * according to each item's relative flex value compared to the sum of all items with + * a flex value specified. Any child items that have either a flex = 0 or + * flex = undefined will not be 'flexed' (the initial size will not be changed). */ - /** - * @cfg {Boolean/Object} draggable - *

          true to enable dragging of this Panel (defaults to false).

          - *

          For custom drag/drop implementations, an Ext.Panel.DD config could also be passed - * in this config instead of true. Ext.Panel.DD is an internal, undocumented class which - * moves a proxy Element around in place of the Panel's element, but provides no other behaviour - * during dragging or on drop. It is a subclass of {@link Ext.dd.DragSource}, so behaviour may be - * added by implementing the interface methods of {@link Ext.dd.DragDrop} e.g.: - *

          
          -new Ext.Panel({
          -    title: 'Drag me',
          -    x: 100,
          -    y: 100,
          -    renderTo: Ext.getBody(),
          -    floating: true,
          -    frame: true,
          -    width: 400,
          -    height: 200,
          -    draggable: {
          -//      Config option of Ext.Panel.DD class.
          -//      It's a floating Panel, so do not show a placeholder proxy in the original position.
          -        insertProxy: false,
           
          -//      Called for each mousemove event while dragging the DD object.
          -        onDrag : function(e){
          -//          Record the x,y position of the drag proxy so that we can
          -//          position the Panel at end of drag.
          -            var pel = this.proxy.getEl();
          -            this.x = pel.getLeft(true);
          -            this.y = pel.getTop(true);
          +    // private
          +    onLayout : function(ct, target){
          +        Ext.layout.HBoxLayout.superclass.onLayout.call(this, ct, target);
          +
          +        var cs = this.getRenderedItems(ct), csLen = cs.length,
          +            c, i, cm, cw, ch, diff, availWidth,
          +            size = this.getLayoutTargetSize(),
          +            w = size.width - this.scrollOffset,
          +            h = size.height,
          +            l = this.padding.left,
          +            t = this.padding.top,
          +            isStart = this.pack == 'start',
          +            isRestore = ['stretch', 'stretchmax'].indexOf(this.align) == -1,
          +            extraWidth = 0,
          +            maxHeight = 0,
          +            totalFlex = 0,
          +            usedWidth = 0;
          +
          +        for (i = 0 ; i < csLen; i++) {
          +            c = cs[i];
          +            // Total of all the flex values
          +            totalFlex += c.flex || 0;
          +            // Don't run width calculations on flexed items
          +            if (!c.flex) {
          +                // Render and layout sub-containers without a flex or width, once
          +                if (!c.width && !c.hasLayout && c.doLayout) {
          +                    c.doLayout();
          +                }
          +                cw = c.getWidth();
          +            } else {
          +                cw = 0;
          +            }
          +            cm = c.margins;
          +            // Determine how much width is available to flex
          +            extraWidth += cw + cm.left + cm.right;
          +            // Max height for align
          +            maxHeight = Math.max(maxHeight, c.getHeight() + cm.top + cm.bottom);
          +        }
          +        // Final avail width calc
          +        availWidth = Math.max(0, (w - extraWidth - this.padding.left - this.padding.right));
          +
          +        var innerCtHeight = maxHeight + this.padding.top + this.padding.bottom;
          +        switch(this.align){
          +            case 'stretch':
          +                this.innerCt.setSize(w, h);
          +                break;
          +            case 'stretchmax':
          +            case 'top':
          +                this.innerCt.setSize(w, innerCtHeight);
          +                break;
          +            case 'middle':
          +                this.innerCt.setSize(w, h = Math.max(h, innerCtHeight));
          +                break;
          +        }
           
          -//          Keep the Shadow aligned if there is one.
          -            var s = this.panel.getEl().shadow;
          -            if (s) {
          -                s.realign(this.x, this.y, pel.getWidth(), pel.getHeight());
          +        var leftOver = availWidth,
          +            widths = [],
          +            restore = [],
          +            idx = 0,
          +            availableHeight = Math.max(0, h - this.padding.top - this.padding.bottom);
          +
          +        for (i = 0 ; i < csLen; i++) {
          +            c = cs[i];
          +            if(isStart && c.flex){
          +                cw = Math.floor(availWidth * (c.flex / totalFlex));
          +                leftOver -= cw;
          +                widths.push(cw);
                       }
          -        },
          +        }
           
          -//      Called on the mouseup event.
          -        endDrag : function(e){
          -            this.panel.setPosition(this.x, this.y);
          +        if(this.pack == 'center'){
          +            l += availWidth ? availWidth / 2 : 0;
          +        }else if(this.pack == 'end'){
          +            l += availWidth;
          +        }
          +        for (i = 0 ; i < csLen; i++) {
          +            c = cs[i];
          +            cm = c.margins;
          +            l += cm.left;
          +            c.setPosition(l, t + cm.top);
          +            if(isStart && c.flex){
          +                cw = Math.max(0, widths[idx++] + (leftOver-- > 0 ? 1 : 0));
          +                if(isRestore){
          +                    restore.push(c.getHeight());
          +                }
          +                c.setSize(cw, availableHeight);
          +            }else{
          +                cw = c.getWidth();
          +            }
          +            l += cw + cm.right;
                   }
          -    }
          -}).show();
          -
          - */ - /** - * @cfg {String} tabTip - * A string to be used as innerHTML (html tags are accepted) to show in a tooltip when mousing over - * the tab of a Ext.Panel which is an item of a {@link Ext.TabPanel}. {@link Ext.QuickTips}.init() - * must be called in order for the tips to render. - */ - /** - * @cfg {Boolean} disabled - * Render this panel disabled (default is false). An important note when using the disabled - * config on panels is that IE will often fail to initialize the disabled mask element correectly if - * the panel's layout has not yet completed by the time the Panel is disabled during the render process. - * If you experience this issue, you may need to instead use the {@link #afterlayout} event to initialize - * the disabled state: - *
          
          -new Ext.Panel({
          -    ...
          -    listeners: {
          -        'afterlayout': {
          -            fn: function(p){
          -                p.disable();
          -            },
          -            single: true // important, as many layouts can occur
          +
          +        idx = 0;
          +        for (i = 0 ; i < csLen; i++) {
          +            c = cs[i];
          +            cm = c.margins;
          +            ch = c.getHeight();
          +            if(isStart && c.flex){
          +                ch = restore[idx++];
          +            }
          +            if(this.align == 'stretch'){
          +                c.setHeight(((h - (this.padding.top + this.padding.bottom)) - (cm.top + cm.bottom)).constrain(
          +                    c.minHeight || 0, c.maxHeight || 1000000));
          +            }else if(this.align == 'stretchmax'){
          +                c.setHeight((maxHeight - (cm.top + cm.bottom)).constrain(
          +                    c.minHeight || 0, c.maxHeight || 1000000));
          +            }else{
          +                if(this.align == 'middle'){
          +                    diff = availableHeight - (ch + cm.top + cm.bottom);
          +                    ch = t + cm.top + (diff/2);
          +                    if(diff > 0){
          +                        c.setPosition(c.x, ch);
          +                    }
          +                }
          +                if(isStart && c.flex){
          +                    c.setHeight(ch);
          +                }
          +            }
          +        }
          +        // Putting a box layout into an overflowed container is NOT correct and will make a second layout pass necessary.
          +        if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) {
          +            var ts = this.getLayoutTargetSize();
          +            if (ts.width != size.width || ts.height != size.height){
          +                this.adjustmentPass = true;
          +                this.onLayout(ct, target);
          +            }
                   }
          +        delete this.adjustmentPass;
               }
           });
          -
          - */ - /** - * @cfg {Boolean} autoHeight - * true to use height:'auto', false to use fixed height (defaults to false). - * Note: Setting autoHeight:true means that the browser will manage the panel's height - * based on its contents, and that Ext will not manage it at all. If the panel is within a layout that - * manages dimensions (fit, border, etc.) then setting autoHeight:true - * can cause issues with scrolling and will not generally work as expected since the panel will take - * on the height of its contents rather than the height required by the Ext layout. - */ - - /** - * @cfg {String} baseCls - * The base CSS class to apply to this panel's element (defaults to 'x-panel'). - *

          Another option available by default is to specify 'x-plain' which strips all styling - * except for required attributes for Ext layouts to function (e.g. overflow:hidden). - * See {@link #unstyled} also.

          - */ - baseCls : 'x-panel', - /** - * @cfg {String} collapsedCls - * A CSS class to add to the panel's element after it has been collapsed (defaults to - * 'x-panel-collapsed'). - */ - collapsedCls : 'x-panel-collapsed', - /** - * @cfg {Boolean} maskDisabled - * true to mask the panel when it is {@link #disabled}, false to not mask it (defaults - * to true). Either way, the panel will always tell its contained elements to disable themselves - * when it is disabled, but masking the panel can provide an additional visual cue that the panel is - * disabled. - */ - maskDisabled : true, - /** - * @cfg {Boolean} animCollapse - * true to animate the transition when the panel is collapsed, false to skip the - * animation (defaults to true if the {@link Ext.Fx} class is available, otherwise false). - */ - animCollapse : Ext.enableFx, - /** - * @cfg {Boolean} headerAsText - * true to display the panel {@link #title} in the {@link #header}, - * false to hide it (defaults to true). - */ - headerAsText : true, - /** - * @cfg {String} buttonAlign - * The alignment of any {@link #buttons} added to this panel. Valid values are 'right', - * 'left' and 'center' (defaults to 'right'). - */ - buttonAlign : 'right', - /** - * @cfg {Boolean} collapsed - * true to render the panel collapsed, false to render it expanded (defaults to - * false). - */ - collapsed : false, - /** - * @cfg {Boolean} collapseFirst - * true to make sure the collapse/expand toggle button always renders first (to the left of) - * any other tools in the panel's title bar, false to render it last (defaults to true). - */ - collapseFirst : true, - /** - * @cfg {Number} minButtonWidth - * Minimum width in pixels of all {@link #buttons} in this panel (defaults to 75) - */ - minButtonWidth : 75, - /** - * @cfg {Boolean} unstyled - * Overrides the {@link #baseCls} setting to {@link #baseCls} = 'x-plain' which renders - * the panel unstyled except for required attributes for Ext layouts to function (e.g. overflow:hidden). - */ - /** - * @cfg {String} elements - * A comma-delimited list of panel elements to initialize when the panel is rendered. Normally, this list will be - * generated automatically based on the items added to the panel at config time, but sometimes it might be useful to - * make sure a structural element is rendered even if not specified at config time (for example, you may want - * to add a button or toolbar dynamically after the panel has been rendered). Adding those elements to this - * list will allocate the required placeholders in the panel when it is rendered. Valid values are
            - *
          • header
          • - *
          • tbar (top bar)
          • - *
          • body
          • - *
          • bbar (bottom bar)
          • - *
          • footer
          • - *
          - * Defaults to 'body'. - */ - elements : 'body', - /** - * @cfg {Boolean} preventBodyReset - * Defaults to false. When set to true, an extra css class 'x-panel-normal' - * will be added to the panel's element, effectively applying css styles suggested by the W3C - * (see http://www.w3.org/TR/CSS21/sample.html) to the Panel's body element (not the header, - * footer, etc.). - */ - preventBodyReset : false, +Ext.Container.LAYOUTS.hbox = Ext.layout.HBoxLayout; +/** + * @class Ext.layout.ToolbarLayout + * @extends Ext.layout.ContainerLayout + * Layout manager implicitly used by Ext.Toolbar. + */ +Ext.layout.ToolbarLayout = Ext.extend(Ext.layout.ContainerLayout, { + monitorResize : true, + triggerWidth : 18, + lastOverflow : false, - // protected - these could be used to customize the behavior of the window, - // but changing them would not be useful without further mofifications and - // could lead to unexpected or undesirable results. - toolTarget : 'header', - collapseEl : 'bwrap', - slideAnchor : 't', - disabledClass : '', + noItemsMenuText : '
          (None)
          ', - // private, notify box this class will handle heights - deferHeight : true, // private - expandDefaults: { - duration : 0.25 + onLayout : function(ct, target){ + if(!this.leftTr){ + var align = ct.buttonAlign == 'center' ? 'center' : 'left'; + target.addClass('x-toolbar-layout-ct'); + target.insertHtml('beforeEnd', + '
          '); + this.leftTr = target.child('tr.x-toolbar-left-row', true); + this.rightTr = target.child('tr.x-toolbar-right-row', true); + this.extrasTr = target.child('tr.x-toolbar-extras-row', true); + } + + var side = ct.buttonAlign == 'right' ? this.rightTr : this.leftTr, + pos = 0, + items = ct.items.items; + + for(var i = 0, len = items.length, c; i < len; i++, pos++) { + c = items[i]; + if(c.isFill){ + side = this.rightTr; + pos = -1; + }else if(!c.rendered){ + c.render(this.insertCell(c, side, pos)); + }else{ + if(!c.xtbHidden && !this.isValidParent(c, side.childNodes[pos])){ + var td = this.insertCell(c, side, pos); + td.appendChild(c.getPositionEl().dom); + c.container = Ext.get(td); + } + } + } + //strip extra empty cells + this.cleanup(this.leftTr); + this.cleanup(this.rightTr); + this.cleanup(this.extrasTr); + this.fitToSize(target); }, - // private - collapseDefaults : { - duration : 0.25 + + cleanup : function(row){ + var cn = row.childNodes, i, c; + for(i = cn.length-1; i >= 0 && (c = cn[i]); i--){ + if(!c.firstChild){ + row.removeChild(c); + } + } }, - // private - initComponent : function(){ - Ext.Panel.superclass.initComponent.call(this); + insertCell : function(c, side, pos){ + var td = document.createElement('td'); + td.className='x-toolbar-cell'; + side.insertBefore(td, side.childNodes[pos]||null); + return td; + }, - this.addEvents( - /** - * @event bodyresize - * Fires after the Panel has been resized. - * @param {Ext.Panel} p the Panel which has been resized. - * @param {Number} width The Panel's new width. - * @param {Number} height The Panel's new height. - */ - 'bodyresize', - /** - * @event titlechange - * Fires after the Panel title has been {@link #title set} or {@link #setTitle changed}. - * @param {Ext.Panel} p the Panel which has had its title changed. - * @param {String} The new title. - */ - 'titlechange', - /** - * @event iconchange - * Fires after the Panel icon class has been {@link #iconCls set} or {@link #setIconClass changed}. - * @param {Ext.Panel} p the Panel which has had its {@link #iconCls icon class} changed. - * @param {String} The new icon class. - * @param {String} The old icon class. - */ - 'iconchange', - /** - * @event collapse - * Fires after the Panel has been collapsed. - * @param {Ext.Panel} p the Panel that has been collapsed. - */ - 'collapse', - /** - * @event expand - * Fires after the Panel has been expanded. - * @param {Ext.Panel} p The Panel that has been expanded. - */ - 'expand', - /** - * @event beforecollapse - * Fires before the Panel is collapsed. A handler can return false to cancel the collapse. - * @param {Ext.Panel} p the Panel being collapsed. - * @param {Boolean} animate True if the collapse is animated, else false. - */ - 'beforecollapse', - /** - * @event beforeexpand - * Fires before the Panel is expanded. A handler can return false to cancel the expand. - * @param {Ext.Panel} p The Panel being expanded. - * @param {Boolean} animate True if the expand is animated, else false. - */ - 'beforeexpand', - /** - * @event beforeclose - * Fires before the Panel is closed. Note that Panels do not directly support being closed, but some - * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel. This event only - * applies to such subclasses. - * A handler can return false to cancel the close. - * @param {Ext.Panel} p The Panel being closed. - */ - 'beforeclose', - /** - * @event close - * Fires after the Panel is closed. Note that Panels do not directly support being closed, but some - * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel. - * @param {Ext.Panel} p The Panel that has been closed. - */ - 'close', - /** - * @event activate - * Fires after the Panel has been visually activated. - * Note that Panels do not directly support being activated, but some Panel subclasses - * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the - * activate and deactivate events under the control of the TabPanel. - * @param {Ext.Panel} p The Panel that has been activated. - */ - 'activate', - /** - * @event deactivate - * Fires after the Panel has been visually deactivated. - * Note that Panels do not directly support being deactivated, but some Panel subclasses - * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the - * activate and deactivate events under the control of the TabPanel. - * @param {Ext.Panel} p The Panel that has been deactivated. - */ - 'deactivate' - ); + hideItem : function(item){ + var h = (this.hiddens = this.hiddens || []); + h.push(item); + item.xtbHidden = true; + item.xtbWidth = item.getPositionEl().dom.parentNode.offsetWidth; + item.hide(); + }, - if(this.unstyled){ - this.baseCls = 'x-plain'; + unhideItem : function(item){ + item.show(); + item.xtbHidden = false; + this.hiddens.remove(item); + if(this.hiddens.length < 1){ + delete this.hiddens; } + }, - // shortcuts - if(this.tbar){ - this.elements += ',tbar'; - if(Ext.isObject(this.tbar)){ - this.topToolbar = this.tbar; + getItemWidth : function(c){ + return c.hidden ? (c.xtbWidth || 0) : c.getPositionEl().dom.parentNode.offsetWidth; + }, + + fitToSize : function(t){ + if(this.container.enableOverflow === false){ + return; + } + var w = t.dom.clientWidth, + lw = this.lastWidth || 0, + iw = t.dom.firstChild.offsetWidth, + clipWidth = w - this.triggerWidth, + hideIndex = -1; + + this.lastWidth = w; + + if(iw > w || (this.hiddens && w >= lw)){ + var i, items = this.container.items.items, + len = items.length, c, + loopWidth = 0; + + for(i = 0; i < len; i++) { + c = items[i]; + if(!c.isFill){ + loopWidth += this.getItemWidth(c); + if(loopWidth > clipWidth){ + if(!(c.hidden || c.xtbHidden)){ + this.hideItem(c); + } + }else if(c.xtbHidden){ + this.unhideItem(c); + } + } } - delete this.tbar; } - if(this.bbar){ - this.elements += ',bbar'; - if(Ext.isObject(this.bbar)){ - this.bottomToolbar = this.bbar; + if(this.hiddens){ + this.initMore(); + if(!this.lastOverflow){ + this.container.fireEvent('overflowchange', this.container, true); + this.lastOverflow = true; + } + }else if(this.more){ + this.clearMenu(); + this.more.destroy(); + delete this.more; + if(this.lastOverflow){ + this.container.fireEvent('overflowchange', this.container, false); + this.lastOverflow = false; } - delete this.bbar; } + }, - if(this.header === true){ - this.elements += ',header'; - delete this.header; - }else if(this.headerCfg || (this.title && this.header !== false)){ - this.elements += ',header'; - } + createMenuConfig : function(c, hideOnClick){ + var cfg = Ext.apply({}, c.initialConfig), + group = c.toggleGroup; - if(this.footerCfg || this.footer === true){ - this.elements += ',footer'; - delete this.footer; + Ext.apply(cfg, { + text: c.overflowText || c.text, + iconCls: c.iconCls, + icon: c.icon, + itemId: c.itemId, + disabled: c.disabled, + handler: c.handler, + scope: c.scope, + menu: c.menu, + hideOnClick: hideOnClick + }); + if(group || c.enableToggle){ + Ext.apply(cfg, { + group: group, + checked: c.pressed, + listeners: { + checkchange: function(item, checked){ + c.toggle(checked); + } + } + }); } + delete cfg.ownerCt; + delete cfg.xtype; + delete cfg.id; + return cfg; + }, - if(this.buttons){ - this.elements += ',footer'; - var btns = this.buttons; - /** - * This Panel's Array of buttons as created from the {@link #buttons} - * config property. Read only. - * @type Array - * @property buttons - */ - this.buttons = []; - for(var i = 0, len = btns.length; i < len; i++) { - if(btns[i].render){ // button instance - this.buttons.push(btns[i]); - }else if(btns[i].xtype){ - this.buttons.push(Ext.create(btns[i], 'button')); - }else{ - this.addButton(btns[i]); - } + // private + addComponentToMenu : function(m, c){ + if(c instanceof Ext.Toolbar.Separator){ + m.add('-'); + }else if(Ext.isFunction(c.isXType)){ + if(c.isXType('splitbutton')){ + m.add(this.createMenuConfig(c, true)); + }else if(c.isXType('button')){ + m.add(this.createMenuConfig(c, !c.menu)); + }else if(c.isXType('buttongroup')){ + c.items.each(function(item){ + this.addComponentToMenu(m, item); + }, this); } } - if(this.fbar){ - this.elements += ',footer'; - } - if(this.autoLoad){ - this.on('render', this.doAutoLoad, this, {delay:10}); + }, + + clearMenu : function(){ + var m = this.moreMenu; + if(m && m.items){ + m.items.each(function(item){ + delete item.menu; + }); } }, // private - createElement : function(name, pnode){ - if(this[name]){ - pnode.appendChild(this[name].dom); - return; - } + beforeMoreShow : function(m){ + var h = this.container.items.items, + len = h.length, + c, + prev, + needsSep = function(group, item){ + return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator); + }; - if(name === 'bwrap' || this.elements.indexOf(name) != -1){ - if(this[name+'Cfg']){ - this[name] = Ext.fly(pnode).createChild(this[name+'Cfg']); - }else{ - var el = document.createElement('div'); - el.className = this[name+'Cls']; - this[name] = Ext.get(pnode.appendChild(el)); - } - if(this[name+'CssClass']){ - this[name].addClass(this[name+'CssClass']); - } - if(this[name+'Style']){ - this[name].applyStyles(this[name+'Style']); + this.clearMenu(); + m.removeAll(); + for(var i = 0; i < len; i++){ + c = h[i]; + if(c.xtbHidden){ + if(prev && (needsSep(c, prev) || needsSep(prev, c))){ + m.add('-'); + } + this.addComponentToMenu(m, c); + prev = c; } } + // put something so the menu isn't empty + // if no compatible items found + if(m.items.length < 1){ + m.add(this.noItemsMenuText); + } }, - // private - onRender : function(ct, position){ - Ext.Panel.superclass.onRender.call(this, ct, position); - this.createClasses(); - - var el = this.el, - d = el.dom, - bw; - el.addClass(this.baseCls); - if(d.firstChild){ // existing markup - this.header = el.down('.'+this.headerCls); - this.bwrap = el.down('.'+this.bwrapCls); - var cp = this.bwrap ? this.bwrap : el; - this.tbar = cp.down('.'+this.tbarCls); - this.body = cp.down('.'+this.bodyCls); - this.bbar = cp.down('.'+this.bbarCls); - this.footer = cp.down('.'+this.footerCls); - this.fromMarkup = true; - } - if (this.preventBodyReset === true) { - el.addClass('x-panel-reset'); - } - if(this.cls){ - el.addClass(this.cls); - } - - if(this.buttons){ - this.elements += ',footer'; - } - - // This block allows for maximum flexibility and performance when using existing markup - - // framing requires special markup - if(this.frame){ - el.insertHtml('afterBegin', String.format(Ext.Element.boxMarkup, this.baseCls)); - - this.createElement('header', d.firstChild.firstChild.firstChild); - this.createElement('bwrap', d); - - // append the mid and bottom frame to the bwrap - bw = this.bwrap.dom; - var ml = d.childNodes[1], bl = d.childNodes[2]; - bw.appendChild(ml); - bw.appendChild(bl); - - var mc = bw.firstChild.firstChild.firstChild; - this.createElement('tbar', mc); - this.createElement('body', mc); - this.createElement('bbar', mc); - this.createElement('footer', bw.lastChild.firstChild.firstChild); - - if(!this.footer){ - this.bwrap.dom.lastChild.className += ' x-panel-nofooter'; - } - }else{ - this.createElement('header', d); - this.createElement('bwrap', d); - - // append the mid and bottom frame to the bwrap - bw = this.bwrap.dom; - this.createElement('tbar', bw); - this.createElement('body', bw); - this.createElement('bbar', bw); - this.createElement('footer', bw); - - if(!this.header){ - this.body.addClass(this.bodyCls + '-noheader'); - if(this.tbar){ - this.tbar.addClass(this.tbarCls + '-noheader'); + initMore : function(){ + if(!this.more){ + this.moreMenu = new Ext.menu.Menu({ + ownerCt : this.container, + listeners: { + beforeshow: this.beforeMoreShow, + scope: this } - } - } - - if(this.padding !== undefined) { - this.body.setStyle('padding', this.body.addUnits(this.padding)); - } - - if(this.border === false){ - this.el.addClass(this.baseCls + '-noborder'); - this.body.addClass(this.bodyCls + '-noborder'); - if(this.header){ - this.header.addClass(this.headerCls + '-noborder'); - } - if(this.footer){ - this.footer.addClass(this.footerCls + '-noborder'); - } - if(this.tbar){ - this.tbar.addClass(this.tbarCls + '-noborder'); - } - if(this.bbar){ - this.bbar.addClass(this.bbarCls + '-noborder'); - } - } - if(this.bodyBorder === false){ - this.body.addClass(this.bodyCls + '-noborder'); + }); + this.more = new Ext.Button({ + iconCls : 'x-toolbar-more-icon', + cls : 'x-toolbar-more', + menu : this.moreMenu, + ownerCt : this.container + }); + var td = this.insertCell(this.more, this.extrasTr, 100); + this.more.render(td); } + }, - this.bwrap.enableDisplayMode('block'); - - if(this.header){ - this.header.unselectable(); + destroy : function(){ + Ext.destroy(this.more, this.moreMenu); + delete this.leftTr; + delete this.rightTr; + delete this.extrasTr; + Ext.layout.ToolbarLayout.superclass.destroy.call(this); + } +}); - // for tools, we need to wrap any existing header markup - if(this.headerAsText){ - this.header.dom.innerHTML = - ''+this.header.dom.innerHTML+''; +Ext.Container.LAYOUTS.toolbar = Ext.layout.ToolbarLayout;/** + * @class Ext.layout.MenuLayout + * @extends Ext.layout.ContainerLayout + *

          Layout manager used by {@link Ext.menu.Menu}. Generally this class should not need to be used directly.

          + */ + Ext.layout.MenuLayout = Ext.extend(Ext.layout.ContainerLayout, { + monitorResize : true, - if(this.iconCls){ - this.setIconClass(this.iconCls); - } - } - } + setContainer : function(ct){ + this.monitorResize = !ct.floating; + // This event is only fired by the menu in IE, used so we don't couple + // the menu with the layout. + ct.on('autosize', this.doAutoSize, this); + Ext.layout.MenuLayout.superclass.setContainer.call(this, ct); + }, - if(this.floating){ - this.makeFloating(this.floating); + renderItem : function(c, position, target){ + if (!this.itemTpl) { + this.itemTpl = Ext.layout.MenuLayout.prototype.itemTpl = new Ext.XTemplate( + '
        • ', + '', + '', + '', + '
        • ' + ); } - if(this.collapsible){ - this.tools = this.tools ? this.tools.slice(0) : []; - if(!this.hideCollapseTool){ - this.tools[this.collapseFirst?'unshift':'push']({ - id: 'toggle', - handler : this.toggleCollapse, - scope: this - }); - } - if(this.titleCollapse && this.header){ - this.mon(this.header, 'click', this.toggleCollapse, this); - this.header.setStyle('cursor', 'pointer'); + if(c && !c.rendered){ + if(Ext.isNumber(position)){ + position = target.dom.childNodes[position]; } - } - if(this.tools){ - var ts = this.tools; - this.tools = {}; - this.addTool.apply(this, ts); - }else{ - this.tools = {}; - } + var a = this.getItemArgs(c); - if(this.buttons && this.buttons.length > 0){ - this.fbar = new Ext.Toolbar({ - items: this.buttons, - toolbarCls: 'x-panel-fbar' - }); - } - this.toolbars = []; - if(this.fbar){ - this.fbar = Ext.create(this.fbar, 'toolbar'); - this.fbar.enableOverflow = false; - if(this.fbar.items){ - this.fbar.items.each(function(c){ - c.minWidth = c.minWidth || this.minButtonWidth; - }, this); - } - this.fbar.toolbarCls = 'x-panel-fbar'; +// The Component's positionEl is the
        • it is rendered into + c.render(c.positionEl = position ? + this.itemTpl.insertBefore(position, a, true) : + this.itemTpl.append(target, a, true)); - var bct = this.footer.createChild({cls: 'x-panel-btns x-panel-btns-'+this.buttonAlign}); - this.fbar.ownerCt = this; - this.fbar.render(bct); - bct.createChild({cls:'x-clear'}); - this.toolbars.push(this.fbar); - } +// Link the containing
        • to the item. + c.positionEl.menuItemId = c.getItemId(); - if(this.tbar && this.topToolbar){ - if(Ext.isArray(this.topToolbar)){ - this.topToolbar = new Ext.Toolbar(this.topToolbar); - }else if(!this.topToolbar.events){ - this.topToolbar = Ext.create(this.topToolbar, 'toolbar'); - } - this.topToolbar.ownerCt = this; - this.topToolbar.render(this.tbar); - this.toolbars.push(this.topToolbar); - } - if(this.bbar && this.bottomToolbar){ - if(Ext.isArray(this.bottomToolbar)){ - this.bottomToolbar = new Ext.Toolbar(this.bottomToolbar); - }else if(!this.bottomToolbar.events){ - this.bottomToolbar = Ext.create(this.bottomToolbar, 'toolbar'); +// If rendering a regular Component, and it needs an icon, +// move the Component rightwards. + if (!a.isMenuItem && a.needsIcon) { + c.positionEl.addClass('x-menu-list-item-indent'); } - this.bottomToolbar.ownerCt = this; - this.bottomToolbar.render(this.bbar); - this.toolbars.push(this.bottomToolbar); - } - Ext.each(this.toolbars, function(tb){ - tb.on({ - scope: this, - afterlayout: this.syncHeight, - remove: this.syncHeight - }); - }, this); - }, - - /** - * Sets the CSS class that provides the icon image for this panel. This method will replace any existing - * icon class if one has already been set and fire the {@link #iconchange} event after completion. - * @param {String} cls The new CSS class name - */ - setIconClass : function(cls){ - var old = this.iconCls; - this.iconCls = cls; - if(this.rendered && this.header){ - if(this.frame){ - this.header.addClass('x-panel-icon'); - this.header.replaceClass(old, this.iconCls); - }else{ - var hd = this.header.dom; - var img = hd.firstChild && String(hd.firstChild.tagName).toLowerCase() == 'img' ? hd.firstChild : null; - if(img){ - Ext.fly(img).replaceClass(old, this.iconCls); - }else{ - Ext.DomHelper.insertBefore(hd.firstChild, { - tag:'img', src: Ext.BLANK_IMAGE_URL, cls:'x-panel-inline-icon '+this.iconCls - }); - } + this.configureItem(c, position); + }else if(c && !this.isValidParent(c, target)){ + if(Ext.isNumber(position)){ + position = target.dom.childNodes[position]; } + target.dom.insertBefore(c.getActionEl().dom, position || null); } - this.fireEvent('iconchange', this, cls, old); - }, - - // private - makeFloating : function(cfg){ - this.floating = true; - this.el = new Ext.Layer( - Ext.isObject(cfg) ? cfg : { - shadow: this.shadow !== undefined ? this.shadow : 'sides', - shadowOffset: this.shadowOffset, - constrain:false, - shim: this.shim === false ? false : undefined - }, this.el - ); }, - /** - * Returns the {@link Ext.Toolbar toolbar} from the top ({@link #tbar}) section of the panel. - * @return {Ext.Toolbar} The toolbar - */ - getTopToolbar : function(){ - return this.topToolbar; + getItemArgs : function(c) { + var isMenuItem = c instanceof Ext.menu.Item; + return { + isMenuItem: isMenuItem, + needsIcon: !isMenuItem && (c.icon || c.iconCls), + icon: c.icon || Ext.BLANK_IMAGE_URL, + iconCls: 'x-menu-item-icon ' + (c.iconCls || ''), + itemId: 'x-menu-el-' + c.id, + itemCls: 'x-menu-list-item ' + }; }, - /** - * Returns the {@link Ext.Toolbar toolbar} from the bottom ({@link #bbar}) section of the panel. - * @return {Ext.Toolbar} The toolbar - */ - getBottomToolbar : function(){ - return this.bottomToolbar; + // Valid if the Component is in a
        • which is part of our target
            + isValidParent : function(c, target) { + return c.el.up('li.x-menu-list-item', 5).dom.parentNode === (target.dom || target); }, - /** - * Adds a button to this panel. Note that this method must be called prior to rendering. The preferred - * approach is to add buttons via the {@link #buttons} config. - * @param {String/Object} config A valid {@link Ext.Button} config. A string will become the text for a default - * button config, an object will be treated as a button config object. - * @param {Function} handler The function to be called on button {@link Ext.Button#click} - * @param {Object} scope The scope to use for the button handler function - * @return {Ext.Button} The button that was added - */ - addButton : function(config, handler, scope){ - var bc = { - handler: handler, - scope: scope, - minWidth: this.minButtonWidth, - hideParent:true - }; - if(typeof config == "string"){ - bc.text = config; - }else{ - Ext.apply(bc, config); - } - var btn = new Ext.Button(bc); - if(!this.buttons){ - this.buttons = []; - } - this.buttons.push(btn); - return btn; + onLayout : function(ct, target){ + Ext.layout.MenuLayout.superclass.onLayout.call(this, ct, target); + this.doAutoSize(); }, - // private - addTool : function(){ - if(!this[this.toolTarget]) { // no where to render tools! - return; - } - if(!this.toolTemplate){ - // initialize the global tool template on first use - var tt = new Ext.Template( - '
             
            ' - ); - tt.disableFormats = true; - tt.compile(); - Ext.Panel.prototype.toolTemplate = tt; - } - for(var i = 0, a = arguments, len = a.length; i < len; i++) { - var tc = a[i]; - if(!this.tools[tc.id]){ - var overCls = 'x-tool-'+tc.id+'-over'; - var t = this.toolTemplate.insertFirst((tc.align !== 'left') ? this[this.toolTarget] : this[this.toolTarget].child('span'), tc, true); - this.tools[tc.id] = t; - t.enableDisplayMode('block'); - this.mon(t, 'click', this.createToolHandler(t, tc, overCls, this)); - if(tc.on){ - this.mon(t, tc.on); - } - if(tc.hidden){ - t.hide(); - } - if(tc.qtip){ - if(Ext.isObject(tc.qtip)){ - Ext.QuickTips.register(Ext.apply({ - target: t.id - }, tc.qtip)); - } else { - t.dom.qtip = tc.qtip; - } - } - t.addClassOnOver(overCls); + doAutoSize : function(){ + var ct = this.container, w = ct.width; + if(ct.floating){ + if(w){ + ct.setWidth(w); + }else if(Ext.isIE){ + ct.setWidth(Ext.isStrict && (Ext.isIE7 || Ext.isIE8) ? 'auto' : ct.minWidth); + var el = ct.getEl(), t = el.dom.offsetWidth; // force recalc + ct.setWidth(ct.getLayoutTarget().getWidth() + el.getFrameWidth('lr')); } } + } +}); +Ext.Container.LAYOUTS['menu'] = Ext.layout.MenuLayout;/** + * @class Ext.Viewport + * @extends Ext.Container + *

            A specialized container representing the viewable application area (the browser viewport).

            + *

            The Viewport renders itself to the document body, and automatically sizes itself to the size of + * the browser viewport and manages window resizing. There may only be one Viewport created + * in a page. Inner layouts are available by virtue of the fact that all {@link Ext.Panel Panel}s + * added to the Viewport, either through its {@link #items}, or through the items, or the {@link #add} + * method of any of its child Panels may themselves have a layout.

            + *

            The Viewport does not provide scrolling, so child Panels within the Viewport should provide + * for scrolling if needed using the {@link #autoScroll} config.

            + *

            An example showing a classic application border layout:

            
            +new Ext.Viewport({
            +    layout: 'border',
            +    items: [{
            +        region: 'north',
            +        html: '<h1 class="x-panel-header">Page Title</h1>',
            +        autoHeight: true,
            +        border: false,
            +        margins: '0 0 5 0'
            +    }, {
            +        region: 'west',
            +        collapsible: true,
            +        title: 'Navigation',
            +        width: 200
            +        // the west region might typically utilize a {@link Ext.tree.TreePanel TreePanel} or a Panel with {@link Ext.layout.AccordionLayout Accordion layout}
            +    }, {
            +        region: 'south',
            +        title: 'Title for Panel',
            +        collapsible: true,
            +        html: 'Information goes here',
            +        split: true,
            +        height: 100,
            +        minHeight: 100
            +    }, {
            +        region: 'east',
            +        title: 'Title for the Grid Panel',
            +        collapsible: true,
            +        split: true,
            +        width: 200,
            +        xtype: 'grid',
            +        // remaining grid configuration not shown ...
            +        // notice that the GridPanel is added directly as the region
            +        // it is not "overnested" inside another Panel
            +    }, {
            +        region: 'center',
            +        xtype: 'tabpanel', // TabPanel itself has no title
            +        items: {
            +            title: 'Default Tab',
            +            html: 'The first tab\'s content. Others may be added dynamically'
            +        }
            +    }]
            +});
            +
            + * @constructor + * Create a new Viewport + * @param {Object} config The config object + * @xtype viewport + */ +Ext.Viewport = Ext.extend(Ext.Container, { + /* + * Privatize config options which, if used, would interfere with the + * correct operation of the Viewport as the sole manager of the + * layout of the document body. + */ + /** + * @cfg {Mixed} applyTo @hide + */ + /** + * @cfg {Boolean} allowDomMove @hide + */ + /** + * @cfg {Boolean} hideParent @hide + */ + /** + * @cfg {Mixed} renderTo @hide + */ + /** + * @cfg {Boolean} hideParent @hide + */ + /** + * @cfg {Number} height @hide + */ + /** + * @cfg {Number} width @hide + */ + /** + * @cfg {Boolean} autoHeight @hide + */ + /** + * @cfg {Boolean} autoWidth @hide + */ + /** + * @cfg {Boolean} deferHeight @hide + */ + /** + * @cfg {Boolean} monitorResize @hide + */ + + initComponent : function() { + Ext.Viewport.superclass.initComponent.call(this); + document.getElementsByTagName('html')[0].className += ' x-viewport'; + this.el = Ext.getBody(); + this.el.setHeight = Ext.emptyFn; + this.el.setWidth = Ext.emptyFn; + this.el.setSize = Ext.emptyFn; + this.el.dom.scroll = 'no'; + this.allowDomMove = false; + this.autoWidth = true; + this.autoHeight = true; + Ext.EventManager.onWindowResize(this.fireResize, this); + this.renderTo = this.el; + }, + + fireResize : function(w, h){ + this.fireEvent('resize', this, w, h, w, h); + } +}); +Ext.reg('viewport', Ext.Viewport); +/** + * @class Ext.Panel + * @extends Ext.Container + *

            Panel is a container that has specific functionality and structural components that make + * it the perfect building block for application-oriented user interfaces.

            + *

            Panels are, by virtue of their inheritance from {@link Ext.Container}, capable + * of being configured with a {@link Ext.Container#layout layout}, and containing child Components.

            + *

            When either specifying child {@link Ext.Component#items items} of a Panel, or dynamically {@link Ext.Container#add adding} Components + * to a Panel, remember to consider how you wish the Panel to arrange those child elements, and whether + * those child elements need to be sized using one of Ext's built-in {@link Ext.Container#layout layout} schemes. By + * default, Panels use the {@link Ext.layout.ContainerLayout ContainerLayout} scheme. This simply renders + * child components, appending them one after the other inside the Container, and does not apply any sizing + * at all.

            + *

            A Panel may also contain {@link #bbar bottom} and {@link #tbar top} toolbars, along with separate + * {@link #header}, {@link #footer} and {@link #body} sections (see {@link #frame} for additional + * information).

            + *

            Panel also provides built-in {@link #collapsible expandable and collapsible behavior}, along with + * a variety of {@link #tools prebuilt tool buttons} that can be wired up to provide other customized + * behavior. Panels can be easily dropped into any {@link Ext.Container Container} or layout, and the + * layout and rendering pipeline is {@link Ext.Container#add completely managed by the framework}.

            + * @constructor + * @param {Object} config The config object + * @xtype panel + */ +Ext.Panel = Ext.extend(Ext.Container, { + /** + * The Panel's header {@link Ext.Element Element}. Read-only. + *

            This Element is used to house the {@link #title} and {@link #tools}

            + *

            Note: see the Note for {@link Ext.Component#el el} also.

            + * @type Ext.Element + * @property header + */ + /** + * The Panel's body {@link Ext.Element Element} which may be used to contain HTML content. + * The content may be specified in the {@link #html} config, or it may be loaded using the + * {@link autoLoad} config, or through the Panel's {@link #getUpdater Updater}. Read-only. + *

            If this is used to load visible HTML elements in either way, then + * the Panel may not be used as a Layout for hosting nested Panels.

            + *

            If this Panel is intended to be used as the host of a Layout (See {@link #layout} + * then the body Element must not be loaded or changed - it is under the control + * of the Panel's Layout. + *

            Note: see the Note for {@link Ext.Component#el el} also.

            + * @type Ext.Element + * @property body + */ + /** + * The Panel's bwrap {@link Ext.Element Element} used to contain other Panel elements + * (tbar, body, bbar, footer). See {@link #bodyCfg}. Read-only. + * @type Ext.Element + * @property bwrap + */ + /** + * True if this panel is collapsed. Read-only. + * @type Boolean + * @property collapsed + */ + /** + * @cfg {Object} bodyCfg + *

            A {@link Ext.DomHelper DomHelper} element specification object may be specified for any + * Panel Element.

            + *

            By default, the Default element in the table below will be used for the html markup to + * create a child element with the commensurate Default class name (baseCls will be + * replaced by {@link #baseCls}):

            + *
            +     * Panel      Default  Default             Custom      Additional       Additional
            +     * Element    element  class               element     class            style
            +     * ========   ==========================   =========   ==============   ===========
            +     * {@link #header}     div      {@link #baseCls}+'-header'   {@link #headerCfg}   headerCssClass   headerStyle
            +     * {@link #bwrap}      div      {@link #baseCls}+'-bwrap'     {@link #bwrapCfg}    bwrapCssClass    bwrapStyle
            +     * + tbar     div      {@link #baseCls}+'-tbar'       {@link #tbarCfg}     tbarCssClass     tbarStyle
            +     * + {@link #body}     div      {@link #baseCls}+'-body'       {@link #bodyCfg}     {@link #bodyCssClass}     {@link #bodyStyle}
            +     * + bbar     div      {@link #baseCls}+'-bbar'       {@link #bbarCfg}     bbarCssClass     bbarStyle
            +     * + {@link #footer}   div      {@link #baseCls}+'-footer'   {@link #footerCfg}   footerCssClass   footerStyle
            +     * 
            + *

            Configuring a Custom element may be used, for example, to force the {@link #body} Element + * to use a different form of markup than is created by default. An example of this might be + * to {@link Ext.Element#createChild create a child} Panel containing a custom content, such as + * a header, or forcing centering of all Panel content by having the body be a <center> + * element:

            + *
            
            +new Ext.Panel({
            +    title: 'Message Title',
            +    renderTo: Ext.getBody(),
            +    width: 200, height: 130,
            +    bodyCfg: {
            +        tag: 'center',
            +        cls: 'x-panel-body',  // Default class not applied if Custom element specified
            +        html: 'Message'
                 },
            -
            -    onLayout : function(){
            -        if(this.toolbars.length > 0){
            -            this.duringLayout = true;
            -            Ext.each(this.toolbars, function(tb){
            -                tb.doLayout();
            -            });
            -            delete this.duringLayout;
            -            this.syncHeight();
            -        }
            -    },
            -
            -    syncHeight : function(){
            -        if(!(this.autoHeight || this.duringLayout)){
            -            var last = this.lastSize;
            -            if(last && !Ext.isEmpty(last.height)){
            -                var old = last.height, h = this.el.getHeight();
            -                if(old != 'auto' && old != h){
            -                    var bd = this.body, bdh = bd.getHeight();
            -                    h = Math.max(bdh + old - h, 0);
            -                    if(bdh > 0 && bdh != h){
            -                        bd.setHeight(h);
            -                        if(Ext.isIE && h <= 0){
            -                            return;
            -                        }
            -                        var sz = bd.getSize();
            -                        this.fireEvent('bodyresize', sz.width, sz.height);
            -                    }
            -                }
            -            }
            -        }
            -    },
            -
            -    // private
            -    onShow : function(){
            -        if(this.floating){
            -            return this.el.show();
            -        }
            -        Ext.Panel.superclass.onShow.call(this);
            -    },
            -
            -    // private
            -    onHide : function(){
            -        if(this.floating){
            -            return this.el.hide();
            -        }
            -        Ext.Panel.superclass.onHide.call(this);
            -    },
            -
            -    // private
            -    createToolHandler : function(t, tc, overCls, panel){
            -        return function(e){
            -            t.removeClass(overCls);
            -            if(tc.stopEvent !== false){
            -                e.stopEvent();
            -            }
            -            if(tc.handler){
            -                tc.handler.call(tc.scope || t, e, t, panel, tc);
            -            }
            -        };
            -    },
            -
            -    // private
            -    afterRender : function(){
            -        if(this.floating && !this.hidden){
            -            this.el.show();
            -        }
            -        if(this.title){
            -            this.setTitle(this.title);
            -        }
            -        this.setAutoScroll();
            -        if(this.html){
            -            this.body.update(Ext.isObject(this.html) ?
            -                             Ext.DomHelper.markup(this.html) :
            -                             this.html);
            -            delete this.html;
            -        }
            -        if(this.contentEl){
            -            var ce = Ext.getDom(this.contentEl);
            -            Ext.fly(ce).removeClass(['x-hidden', 'x-hide-display']);
            -            this.body.dom.appendChild(ce);
            -        }
            -        if(this.collapsed){
            -            this.collapsed = false;
            -            this.collapse(false);
            -        }
            -        Ext.Panel.superclass.afterRender.call(this); // do sizing calcs last
            -        this.initEvents();
            -    },
            -
            -    // private
            -    setAutoScroll : function(){
            -        if(this.rendered && this.autoScroll){
            -            var el = this.body || this.el;
            -            if(el){
            -                el.setOverflow('auto');
            -            }
            -        }
            +    footerCfg: {
            +        tag: 'h2',
            +        cls: 'x-panel-footer'        // same as the Default class
            +        html: 'footer html'
                 },
            -
            -    // private
            -    getKeyMap : function(){
            -        if(!this.keyMap){
            -            this.keyMap = new Ext.KeyMap(this.el, this.keys);
            -        }
            -        return this.keyMap;
            -    },
            -
            -    // private
            -    initEvents : function(){
            -        if(this.keys){
            -            this.getKeyMap();
            -        }
            -        if(this.draggable){
            -            this.initDraggable();
            -        }
            -    },
            -
            -    // private
            -    initDraggable : function(){
            -        /**
            -         * 

            If this Panel is configured {@link #draggable}, this property will contain - * an instance of {@link Ext.dd.DragSource} which handles dragging the Panel.

            - * The developer must provide implementations of the abstract methods of {@link Ext.dd.DragSource} - * in order to supply behaviour for each stage of the drag/drop process. See {@link #draggable}. - * @type Ext.dd.DragSource. - * @property dd - */ - this.dd = new Ext.Panel.DD(this, typeof this.draggable == 'boolean' ? null : this.draggable); - }, - - // private - beforeEffect : function(){ - if(this.floating){ - this.el.beforeAction(); - } - this.el.addClass('x-panel-animated'); - }, - - // private - afterEffect : function(){ - this.syncShadow(); - this.el.removeClass('x-panel-animated'); - }, - - // private - wraps up an animation param with internal callbacks - createEffect : function(a, cb, scope){ - var o = { - scope:scope, - block:true - }; - if(a === true){ - o.callback = cb; - return o; - }else if(!a.callback){ - o.callback = cb; - }else { // wrap it up - o.callback = function(){ - cb.call(scope); - Ext.callback(a.callback, a.scope); - }; - } - return Ext.applyIf(o, a); - }, - - /** - * Collapses the panel body so that it becomes hidden. Fires the {@link #beforecollapse} event which will - * cancel the collapse action if it returns false. - * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the - * {@link #animCollapse} panel config) - * @return {Ext.Panel} this + footerCssClass: 'custom-footer', // additional css class, see {@link Ext.element#addClass addClass} + footerStyle: 'background-color:red' // see {@link #bodyStyle} +}); + *
            + *

            The example above also explicitly creates a {@link #footer} with custom markup and + * styling applied.

            */ - collapse : function(animate){ - if(this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforecollapse', this, animate) === false){ - return; - } - var doAnim = animate === true || (animate !== false && this.animCollapse); - this.beforeEffect(); - this.onCollapse(doAnim, animate); - return this; - }, - - // private - onCollapse : function(doAnim, animArg){ - if(doAnim){ - this[this.collapseEl].slideOut(this.slideAnchor, - Ext.apply(this.createEffect(animArg||true, this.afterCollapse, this), - this.collapseDefaults)); - }else{ - this[this.collapseEl].hide(); - this.afterCollapse(); - } - }, - - // private - afterCollapse : function(){ - this.collapsed = true; - this.el.addClass(this.collapsedCls); - this.afterEffect(); - this.fireEvent('collapse', this); - }, - /** - * Expands the panel body so that it becomes visible. Fires the {@link #beforeexpand} event which will - * cancel the expand action if it returns false. - * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the - * {@link #animCollapse} panel config) - * @return {Ext.Panel} this + * @cfg {Object} headerCfg + *

            A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure + * of this Panel's {@link #header} Element. See {@link #bodyCfg} also.

            */ - expand : function(animate){ - if(!this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforeexpand', this, animate) === false){ - return; - } - var doAnim = animate === true || (animate !== false && this.animCollapse); - this.el.removeClass(this.collapsedCls); - this.beforeEffect(); - this.onExpand(doAnim, animate); - return this; - }, - - // private - onExpand : function(doAnim, animArg){ - if(doAnim){ - this[this.collapseEl].slideIn(this.slideAnchor, - Ext.apply(this.createEffect(animArg||true, this.afterExpand, this), - this.expandDefaults)); - }else{ - this[this.collapseEl].show(); - this.afterExpand(); - } - }, - - // private - afterExpand : function(){ - this.collapsed = false; - this.afterEffect(); - if(this.deferLayout !== undefined){ - this.doLayout(true); - } - this.fireEvent('expand', this); - }, - /** - * Shortcut for performing an {@link #expand} or {@link #collapse} based on the current state of the panel. - * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the - * {@link #animCollapse} panel config) - * @return {Ext.Panel} this + * @cfg {Object} bwrapCfg + *

            A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure + * of this Panel's {@link #bwrap} Element. See {@link #bodyCfg} also.

            */ - toggleCollapse : function(animate){ - this[this.collapsed ? 'expand' : 'collapse'](animate); - return this; - }, - - // private - onDisable : function(){ - if(this.rendered && this.maskDisabled){ - this.el.mask(); - } - Ext.Panel.superclass.onDisable.call(this); - }, - - // private - onEnable : function(){ - if(this.rendered && this.maskDisabled){ - this.el.unmask(); - } - Ext.Panel.superclass.onEnable.call(this); - }, - - // private - onResize : function(w, h){ - if(w !== undefined || h !== undefined){ - if(!this.collapsed){ - if(typeof w == 'number'){ - w = this.adjustBodyWidth(w - this.getFrameWidth()); - if(this.tbar){ - this.tbar.setWidth(w); - if(this.topToolbar){ - this.topToolbar.setSize(w); - } - } - if(this.bbar){ - this.bbar.setWidth(w); - if(this.bottomToolbar){ - this.bottomToolbar.setSize(w); - } - } - if(this.fbar){ - var f = this.fbar, - fWidth = 1, - strict = Ext.isStrict; - if(this.buttonAlign == 'left'){ - fWidth = w - f.container.getFrameWidth('lr'); - }else{ - //center/right alignment off in webkit - if(Ext.isIE || Ext.isWebKit){ - //center alignment ok on webkit. - //right broken in both, center on IE - if(!(this.buttonAlign == 'center' && Ext.isWebKit) && (!strict || (!Ext.isIE8 && strict))){ - (function(){ - f.setWidth(f.getEl().child('.x-toolbar-ct').getWidth()); - }).defer(1); - }else{ - fWidth = 'auto'; - } - }else{ - fWidth = 'auto'; - } - } - f.setWidth(fWidth); - } - this.body.setWidth(w); - }else if(w == 'auto'){ - this.body.setWidth(w); - } - - if(typeof h == 'number'){ - h = Math.max(0, this.adjustBodyHeight(h - this.getFrameHeight())); - this.body.setHeight(h); - }else if(h == 'auto'){ - this.body.setHeight(h); - } - - if(this.disabled && this.el._mask){ - this.el._mask.setSize(this.el.dom.clientWidth, this.el.getHeight()); - } - }else{ - this.queuedBodySize = {width: w, height: h}; - if(!this.queuedExpand && this.allowQueuedExpand !== false){ - this.queuedExpand = true; - this.on('expand', function(){ - delete this.queuedExpand; - this.onResize(this.queuedBodySize.width, this.queuedBodySize.height); - this.doLayout(); - }, this, {single:true}); - } - } - this.fireEvent('bodyresize', this, w, h); - } - this.syncShadow(); - }, - - // private - adjustBodyHeight : function(h){ - return h; - }, - - // private - adjustBodyWidth : function(w){ - return w; - }, - - // private - onPosition : function(){ - this.syncShadow(); - }, - /** - * Returns the width in pixels of the framing elements of this panel (not including the body width). To - * retrieve the body width see {@link #getInnerWidth}. - * @return {Number} The frame width + * @cfg {Object} tbarCfg + *

            A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure + * of this Panel's {@link #tbar} Element. See {@link #bodyCfg} also.

            */ - getFrameWidth : function(){ - var w = this.el.getFrameWidth('lr')+this.bwrap.getFrameWidth('lr'); - - if(this.frame){ - var l = this.bwrap.dom.firstChild; - w += (Ext.fly(l).getFrameWidth('l') + Ext.fly(l.firstChild).getFrameWidth('r')); - var mc = this.bwrap.dom.firstChild.firstChild.firstChild; - w += Ext.fly(mc).getFrameWidth('lr'); - } - return w; - }, - /** - * Returns the height in pixels of the framing elements of this panel (including any top and bottom bars and - * header and footer elements, but not including the body height). To retrieve the body height see {@link #getInnerHeight}. - * @return {Number} The frame height + * @cfg {Object} bbarCfg + *

            A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure + * of this Panel's {@link #bbar} Element. See {@link #bodyCfg} also.

            */ - getFrameHeight : function(){ - var h = this.el.getFrameWidth('tb')+this.bwrap.getFrameWidth('tb'); - h += (this.tbar ? this.tbar.getHeight() : 0) + - (this.bbar ? this.bbar.getHeight() : 0); - - if(this.frame){ - var hd = this.el.dom.firstChild; - var ft = this.bwrap.dom.lastChild; - h += (hd.offsetHeight + ft.offsetHeight); - var mc = this.bwrap.dom.firstChild.firstChild.firstChild; - h += Ext.fly(mc).getFrameWidth('tb'); - }else{ - h += (this.header ? this.header.getHeight() : 0) + - (this.footer ? this.footer.getHeight() : 0); - } - return h; - }, - /** - * Returns the width in pixels of the body element (not including the width of any framing elements). - * For the frame width see {@link #getFrameWidth}. - * @return {Number} The body width + * @cfg {Object} footerCfg + *

            A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure + * of this Panel's {@link #footer} Element. See {@link #bodyCfg} also.

            */ - getInnerWidth : function(){ - return this.getSize().width - this.getFrameWidth(); - }, - /** - * Returns the height in pixels of the body element (not including the height of any framing elements). - * For the frame height see {@link #getFrameHeight}. - * @return {Number} The body height + * @cfg {Boolean} closable + * Panels themselves do not directly support being closed, but some Panel subclasses do (like + * {@link Ext.Window}) or a Panel Class within an {@link Ext.TabPanel}. Specify true + * to enable closing in such situations. Defaults to false. */ - getInnerHeight : function(){ - return this.getSize().height - this.getFrameHeight(); - }, - - // private - syncShadow : function(){ - if(this.floating){ - this.el.sync(true); - } - }, - - // private - getLayoutTarget : function(){ - return this.body; - }, - /** - *

            Sets the title text for the panel and optionally the {@link #iconCls icon class}.

            - *

            In order to be able to set the title, a header element must have been created - * for the Panel. This is triggered either by configuring the Panel with a non-blank {@link #title}, - * or configuring it with {@link #header}: true.

            - * @param {String} title The title text to set - * @param {String} iconCls (optional) {@link #iconCls iconCls} A user-defined CSS class that provides the icon image for this panel + * The Panel's footer {@link Ext.Element Element}. Read-only. + *

            This Element is used to house the Panel's {@link #buttons} or {@link #fbar}.

            + *

            Note: see the Note for {@link Ext.Component#el el} also.

            + * @type Ext.Element + * @property footer */ - setTitle : function(title, iconCls){ - this.title = title; - if(this.header && this.headerAsText){ - this.header.child('span').update(title); - } - if(iconCls){ - this.setIconClass(iconCls); - } - this.fireEvent('titlechange', this, title); - return this; - }, - /** - * Get the {@link Ext.Updater} for this panel. Enables you to perform Ajax updates of this panel's body. - * @return {Ext.Updater} The Updater - */ - getUpdater : function(){ - return this.body.getUpdater(); - }, - - /** - * Loads this content panel immediately with content returned from an XHR call. - * @param {Object/String/Function} config A config object containing any of the following options: -
            
            -panel.load({
            -    url: "your-url.php",
            -    params: {param1: "foo", param2: "bar"}, // or a URL encoded string
            -    callback: yourFunction,
            -    scope: yourObject, // optional scope for the callback
            -    discardUrl: false,
            -    nocache: false,
            -    text: "Loading...",
            -    timeout: 30,
            -    scripts: false
            -});
            -
            - * The only required property is url. The optional properties nocache, text and scripts - * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their - * associated property on this panel Updater instance. - * @return {Ext.Panel} this + * @cfg {Mixed} applyTo + *

            The id of the node, a DOM node or an existing Element corresponding to a DIV that is already present in + * the document that specifies some panel-specific structural markup. When applyTo is used, + * constituent parts of the panel can be specified by CSS class name within the main element, and the panel + * will automatically create those components from that markup. Any required components not specified in the + * markup will be autogenerated if necessary.

            + *

            The following class names are supported (baseCls will be replaced by {@link #baseCls}):

            + *
            • baseCls + '-header'
            • + *
            • baseCls + '-header-text'
            • + *
            • baseCls + '-bwrap'
            • + *
            • baseCls + '-tbar'
            • + *
            • baseCls + '-body'
            • + *
            • baseCls + '-bbar'
            • + *
            • baseCls + '-footer'
            + *

            Using this config, a call to render() is not required. If applyTo is specified, any value passed for + * {@link #renderTo} will be ignored and the target element's parent node will automatically be used as the + * panel's container.

            */ - load : function(){ - var um = this.body.getUpdater(); - um.update.apply(um, arguments); - return this; - }, - - // private - beforeDestroy : function(){ - if(this.header){ - this.header.removeAllListeners(); - if(this.headerAsText){ - Ext.Element.uncache(this.header.child('span')); - } - } - Ext.Element.uncache( - this.header, - this.tbar, - this.bbar, - this.footer, - this.body, - this.bwrap - ); - if(this.tools){ - for(var k in this.tools){ - Ext.destroy(this.tools[k]); - } - } - if(this.buttons){ - for(var b in this.buttons){ - Ext.destroy(this.buttons[b]); - } - } - Ext.destroy(this.toolbars); - Ext.Panel.superclass.beforeDestroy.call(this); - }, - - // private - createClasses : function(){ - this.headerCls = this.baseCls + '-header'; - this.headerTextCls = this.baseCls + '-header-text'; - this.bwrapCls = this.baseCls + '-bwrap'; - this.tbarCls = this.baseCls + '-tbar'; - this.bodyCls = this.baseCls + '-body'; - this.bbarCls = this.baseCls + '-bbar'; - this.footerCls = this.baseCls + '-footer'; - }, - - // private - createGhost : function(cls, useShim, appendTo){ - var el = document.createElement('div'); - el.className = 'x-panel-ghost ' + (cls ? cls : ''); - if(this.header){ - el.appendChild(this.el.dom.firstChild.cloneNode(true)); - } - Ext.fly(el.appendChild(document.createElement('ul'))).setHeight(this.bwrap.getHeight()); - el.style.width = this.el.dom.offsetWidth + 'px';; - if(!appendTo){ - this.container.dom.appendChild(el); - }else{ - Ext.getDom(appendTo).appendChild(el); - } - if(useShim !== false && this.el.useShim !== false){ - var layer = new Ext.Layer({shadow:false, useDisplay:true, constrain:false}, el); - layer.show(); - return layer; - }else{ - return new Ext.Element(el); - } - }, - - // private - doAutoLoad : function(){ - var u = this.body.getUpdater(); - if(this.renderer){ - u.setRenderer(this.renderer); - } - u.update(Ext.isObject(this.autoLoad) ? this.autoLoad : {url: this.autoLoad}); - }, - /** - * Retrieve a tool by id. - * @param {String} id - * @return {Object} tool + * @cfg {Object/Array} tbar + *

            The top toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of + * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render. + * To access the top toolbar after render, use {@link #getTopToolbar}.

            + *

            Note: Although a Toolbar may contain Field components, these will not be updated by a load + * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and + * so are not scanned to collect form items. However, the values will be submitted because form + * submission parameters are collected from the DOM tree.

            */ - getTool : function(id) { - return this.tools[id]; - } - -/** - * @cfg {String} autoEl @hide - */ -}); -Ext.reg('panel', Ext.Panel); -/** - * @class Ext.Editor - * @extends Ext.Component - * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic. - * @constructor - * Create a new Editor - * @param {Object} config The config object - * @xtype editor - */ -Ext.Editor = function(field, config){ - if(field.field){ - this.field = Ext.create(field.field, 'textfield'); - config = Ext.apply({}, field); // copy so we don't disturb original config - delete config.field; - }else{ - this.field = field; - } - Ext.Editor.superclass.constructor.call(this, config); -}; - -Ext.extend(Ext.Editor, Ext.Component, { - /** - * @cfg {Ext.form.Field} field - * The Field object (or descendant) or config object for field - */ /** - * @cfg {Boolean} allowBlur - * True to {@link #completeEdit complete the editing process} if in edit mode when the - * field is blurred. Defaults to false. + * @cfg {Object/Array} bbar + *

            The bottom toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of + * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render. + * To access the bottom toolbar after render, use {@link #getBottomToolbar}.

            + *

            Note: Although a Toolbar may contain Field components, these will not be updated by a load + * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and + * so are not scanned to collect form items. However, the values will be submitted because form + * submission parameters are collected from the DOM tree.

            */ - /** - * @cfg {Boolean/String} autoSize - * True for the editor to automatically adopt the size of the element being edited, "width" to adopt the width only, - * or "height" to adopt the height only (defaults to false) + /** @cfg {Object/Array} fbar + *

            A {@link Ext.Toolbar Toolbar} object, a Toolbar config, or an array of + * {@link Ext.Button Button}s/{@link Ext.Button Button} configs, describing a {@link Ext.Toolbar Toolbar} to be rendered into this Panel's footer element.

            + *

            After render, the fbar property will be an {@link Ext.Toolbar Toolbar} instance.

            + *

            If {@link #buttons} are specified, they will supersede the fbar configuration property.

            + * The Panel's {@link #buttonAlign} configuration affects the layout of these items, for example: + *
            
            +var w = new Ext.Window({
            +    height: 250,
            +    width: 500,
            +    bbar: new Ext.Toolbar({
            +        items: [{
            +            text: 'bbar Left'
            +        },'->',{
            +            text: 'bbar Right'
            +        }]
            +    }),
            +    {@link #buttonAlign}: 'left', // anything but 'center' or 'right' and you can use '-', and '->'
            +                                  // to control the alignment of fbar items
            +    fbar: [{
            +        text: 'fbar Left'
            +    },'->',{
            +        text: 'fbar Right'
            +    }]
            +}).show();
            +     * 
            + *

            Note: Although a Toolbar may contain Field components, these will not be updated by a load + * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and + * so are not scanned to collect form items. However, the values will be submitted because form + * submission parameters are collected from the DOM tree.

            */ /** - * @cfg {Boolean} revertInvalid - * True to automatically revert the field value and cancel the edit when the user completes an edit and the field - * validation fails (defaults to true) + * @cfg {Boolean} header + * true to create the Panel's header element explicitly, false to skip creating + * it. If a {@link #title} is set the header will be created automatically, otherwise it will not. + * If a {@link #title} is set but header is explicitly set to false, the header + * will not be rendered. */ /** - * @cfg {Boolean} ignoreNoChange - * True to skip the edit completion process (no save, no events fired) if the user completes an edit and - * the value has not changed (defaults to false). Applies only to string values - edits for other data types - * will never be ignored. + * @cfg {Boolean} footer + * true to create the footer element explicitly, false to skip creating it. The footer + * will be created automatically if {@link #buttons} or a {@link #fbar} have + * been configured. See {@link #bodyCfg} for an example. */ /** - * @cfg {Boolean} hideEl - * False to keep the bound element visible while the editor is displayed (defaults to true) + * @cfg {String} title + * The title text to be used as innerHTML (html tags are accepted) to display in the panel + * {@link #header} (defaults to ''). When a title is specified the + * {@link #header} element will automatically be created and displayed unless + * {@link #header} is explicitly set to false. If you do not want to specify a + * title at config time, but you may want one later, you must either specify a non-empty + * title (a blank space ' ' will do) or header:true so that the container + * element will get created. */ /** - * @cfg {Mixed} value - * The data value of the underlying field (defaults to "") + * @cfg {Array} buttons + * buttons will be used as {@link Ext.Container#items items} for the toolbar in + * the footer ({@link #fbar}). Typically the value of this configuration property will be + * an array of {@link Ext.Button}s or {@link Ext.Button} configuration objects. + * If an item is configured with minWidth or the Panel is configured with minButtonWidth, + * that width will be applied to the item. */ - value : "", /** - * @cfg {String} alignment - * The position to align to (see {@link Ext.Element#alignTo} for more details, defaults to "c-c?"). + * @cfg {Object/String/Function} autoLoad + * A valid url spec according to the Updater {@link Ext.Updater#update} method. + * If autoLoad is not null, the panel will attempt to load its contents + * immediately upon render.

            + * The URL will become the default URL for this panel's {@link #body} element, + * so it may be {@link Ext.Element#refresh refresh}ed at any time.

            */ - alignment: "c-c?", - /** - * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop" - * for bottom-right shadow (defaults to "frame") - */ - shadow : "frame", - /** - * @cfg {Boolean} constrain True to constrain the editor to the viewport - */ - constrain : false, /** - * @cfg {Boolean} swallowKeys Handle the keydown/keypress events so they don't propagate (defaults to true) + * @cfg {Boolean} frame + * false by default to render with plain 1px square borders. true to render with + * 9 elements, complete with custom rounded corners (also see {@link Ext.Element#boxWrap}). + *

            The template generated for each condition is depicted below:

            
            +     *
            +// frame = false
            +<div id="developer-specified-id-goes-here" class="x-panel">
            +
            +    <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:false)</span></div>
            +
            +    <div class="x-panel-bwrap">
            +        <div class="x-panel-body"><p>html value goes here</p></div>
            +    </div>
            +</div>
            +
            +// frame = true (create 9 elements)
            +<div id="developer-specified-id-goes-here" class="x-panel">
            +    <div class="x-panel-tl"><div class="x-panel-tr"><div class="x-panel-tc">
            +        <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:true)</span></div>
            +    </div></div></div>
            +
            +    <div class="x-panel-bwrap">
            +        <div class="x-panel-ml"><div class="x-panel-mr"><div class="x-panel-mc">
            +            <div class="x-panel-body"><p>html value goes here</p></div>
            +        </div></div></div>
            +
            +        <div class="x-panel-bl"><div class="x-panel-br"><div class="x-panel-bc"/>
            +        </div></div></div>
            +</div>
            +     * 
            */ - swallowKeys : true, /** - * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false) + * @cfg {Boolean} border + * True to display the borders of the panel's body element, false to hide them (defaults to true). By default, + * the border is a 2px wide inset border, but this can be further altered by setting {@link #bodyBorder} to false. */ - completeOnEnter : false, /** - * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false) + * @cfg {Boolean} bodyBorder + * True to display an interior border on the body element of the panel, false to hide it (defaults to true). + * This only applies when {@link #border} == true. If border == true and bodyBorder == false, the border will display + * as a 1px wide inset border, giving the entire body element an inset appearance. */ - cancelOnEsc : false, /** - * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false) + * @cfg {String/Object/Function} bodyCssClass + * Additional css class selector to be applied to the {@link #body} element in the format expected by + * {@link Ext.Element#addClass} (defaults to null). See {@link #bodyCfg}. */ - updateEl : false, - - initComponent : function(){ - Ext.Editor.superclass.initComponent.call(this); - this.addEvents( - /** - * @event beforestartedit - * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning - * false from the handler of this event. - * @param {Editor} this - * @param {Ext.Element} boundEl The underlying element bound to this editor - * @param {Mixed} value The field value being set - */ - "beforestartedit", - /** - * @event startedit - * Fires when this editor is displayed - * @param {Ext.Element} boundEl The underlying element bound to this editor - * @param {Mixed} value The starting field value - */ - "startedit", - /** - * @event beforecomplete - * Fires after a change has been made to the field, but before the change is reflected in the underlying - * field. Saving the change to the field can be canceled by returning false from the handler of this event. - * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this - * event will not fire since no edit actually occurred. - * @param {Editor} this - * @param {Mixed} value The current field value - * @param {Mixed} startValue The original field value - */ - "beforecomplete", - /** - * @event complete - * Fires after editing is complete and any changed value has been written to the underlying field. - * @param {Editor} this - * @param {Mixed} value The current field value - * @param {Mixed} startValue The original field value - */ - "complete", - /** - * @event canceledit - * Fires after editing has been canceled and the editor's value has been reset. - * @param {Editor} this - * @param {Mixed} value The user-entered field value that was discarded - * @param {Mixed} startValue The original field value that was set back into the editor after cancel - */ - "canceledit", - /** - * @event specialkey - * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check - * {@link Ext.EventObject#getKey} to determine which key was pressed. - * @param {Ext.form.Field} this - * @param {Ext.EventObject} e The event object - */ - "specialkey" - ); - }, - - // private - onRender : function(ct, position){ - this.el = new Ext.Layer({ - shadow: this.shadow, - cls: "x-editor", - parentEl : ct, - shim : this.shim, - shadowOffset: this.shadowOffset || 4, - id: this.id, - constrain: this.constrain - }); - if(this.zIndex){ - this.el.setZIndex(this.zIndex); - } - this.el.setStyle("overflow", Ext.isGecko ? "auto" : "hidden"); - if(this.field.msgTarget != 'title'){ - this.field.msgTarget = 'qtip'; - } - this.field.inEditor = true; - this.field.render(this.el); - if(Ext.isGecko){ - this.field.el.dom.setAttribute('autocomplete', 'off'); - } - this.mon(this.field, "specialkey", this.onSpecialKey, this); - if(this.swallowKeys){ - this.field.el.swallowEvent(['keydown','keypress']); - } - this.field.show(); - this.mon(this.field, "blur", this.onBlur, this); - if(this.field.grow){ - this.mon(this.field, "autosize", this.el.sync, this.el, {delay:1}); - } - }, - - // private - onSpecialKey : function(field, e){ - var key = e.getKey(); - if(this.completeOnEnter && key == e.ENTER){ - e.stopEvent(); - this.completeEdit(); - }else if(this.cancelOnEsc && key == e.ESC){ - this.cancelEdit(); - }else{ - this.fireEvent('specialkey', field, e); - } - if(this.field.triggerBlur && (key == e.ENTER || key == e.ESC || key == e.TAB)){ - this.field.triggerBlur(); - } - }, - /** - * Starts the editing process and shows the editor. - * @param {Mixed} el The element to edit - * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults - * to the innerHTML of el. + * @cfg {String/Object/Function} bodyStyle + * Custom CSS styles to be applied to the {@link #body} element in the format expected by + * {@link Ext.Element#applyStyles} (defaults to null). See {@link #bodyCfg}. */ - startEdit : function(el, value){ - if(this.editing){ - this.completeEdit(); - } - this.boundEl = Ext.get(el); - var v = value !== undefined ? value : this.boundEl.dom.innerHTML; - if(!this.rendered){ - this.render(this.parentEl || document.body); - } - if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){ - return; - } - this.startValue = v; - this.field.setValue(v); - this.doAutoSize(); - this.el.alignTo(this.boundEl, this.alignment); - this.editing = true; - this.show(); - }, - - // private - doAutoSize : function(){ - if(this.autoSize){ - var sz = this.boundEl.getSize(); - switch(this.autoSize){ - case "width": - this.setSize(sz.width, ""); - break; - case "height": - this.setSize("", sz.height); - break; - default: - this.setSize(sz.width, sz.height); - } - } - }, - /** - * Sets the height and width of this editor. - * @param {Number} width The new width - * @param {Number} height The new height - */ - setSize : function(w, h){ - delete this.field.lastSize; - this.field.setSize(w, h); - if(this.el){ - if(Ext.isGecko2 || Ext.isOpera){ - // prevent layer scrollbars - this.el.setSize(w, h); - } - this.el.sync(); - } - }, + * @cfg {String} iconCls + * The CSS class selector that specifies a background image to be used as the header icon (defaults to ''). + *

            An example of specifying a custom icon class would be something like: + *

            
            +// specify the property in the config for the class:
            +     ...
            +     iconCls: 'my-icon'
             
            -    /**
            -     * Realigns the editor to the bound field based on the current alignment config value.
            +// css class that specifies background image to be used as the icon image:
            +.my-icon { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
            +
            */ - realign : function(){ - this.el.alignTo(this.boundEl, this.alignment); - }, - /** - * Ends the editing process, persists the changed value to the underlying field, and hides the editor. - * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false) + * @cfg {Boolean} collapsible + * True to make the panel collapsible and have the expand/collapse toggle button automatically rendered into + * the header tool button area, false to keep the panel statically sized with no button (defaults to false). */ - completeEdit : function(remainVisible){ - if(!this.editing){ - return; - } - var v = this.getValue(); - if(!this.field.isValid()){ - if(this.revertInvalid !== false){ - this.cancelEdit(remainVisible); - } - return; - } - if(String(v) === String(this.startValue) && this.ignoreNoChange){ - this.hideEdit(remainVisible); - return; - } - if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){ - v = this.getValue(); - if(this.updateEl && this.boundEl){ - this.boundEl.update(v); - } - this.hideEdit(remainVisible); - this.fireEvent("complete", this, v, this.startValue); - } - }, - - // private - onShow : function(){ - this.el.show(); - if(this.hideEl !== false){ - this.boundEl.hide(); - } - this.field.show(); - if(Ext.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time - this.fixIEFocus = true; - this.deferredFocus.defer(50, this); - }else{ - this.field.focus(); - } - this.fireEvent("startedit", this.boundEl, this.startValue); - }, - - deferredFocus : function(){ - if(this.editing){ - this.field.focus(); - } - }, - /** - * Cancels the editing process and hides the editor without persisting any changes. The field value will be - * reverted to the original starting value. - * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after - * cancel (defaults to false) + * @cfg {Array} tools + * An array of tool button configs to be added to the header tool area. When rendered, each tool is + * stored as an {@link Ext.Element Element} referenced by a public property called tools.<tool-type> + *

            Each tool config may contain the following properties: + *

              + *
            • id : String
              Required. The type + * of tool to create. By default, this assigns a CSS class of the form x-tool-<tool-type> to the + * resulting tool Element. Ext provides CSS rules, and an icon sprite containing images for the tool types listed below. + * The developer may implement custom tools by supplying alternate CSS rules and background images: + *
                + *
                toggle (Created by default when {@link #collapsible} is true)
                + *
                close
                + *
                minimize
                + *
                maximize
                + *
                restore
                + *
                gear
                + *
                pin
                + *
                unpin
                + *
                right
                + *
                left
                + *
                up
                + *
                down
                + *
                refresh
                + *
                minus
                + *
                plus
                + *
                help
                + *
                search
                + *
                save
                + *
                print
                + *
            • + *
            • handler : Function
              Required. The function to + * call when clicked. Arguments passed are:
                + *
              • event : Ext.EventObject
                The click event.
              • + *
              • toolEl : Ext.Element
                The tool Element.
              • + *
              • panel : Ext.Panel
                The host Panel
              • + *
              • tc : Object
                The tool configuration object
              • + *
            • + *
            • stopEvent : Boolean
              Defaults to true. Specify as false to allow click event to propagate.
            • + *
            • scope : Object
              The scope in which to call the handler.
            • + *
            • qtip : String/Object
              A tip string, or + * a config argument to {@link Ext.QuickTip#register}
            • + *
            • hidden : Boolean
              True to initially render hidden.
            • + *
            • on : Object
              A listener config object specifiying + * event listeners in the format of an argument to {@link #addListener}
            • + *
            + *

            Note that, apart from the toggle tool which is provided when a panel is collapsible, these + * tools only provide the visual button. Any required functionality must be provided by adding + * handlers that implement the necessary behavior.

            + *

            Example usage:

            + *
            
            +tools:[{
            +    id:'refresh',
            +    qtip: 'Refresh form Data',
            +    // hidden:true,
            +    handler: function(event, toolEl, panel){
            +        // refresh logic
            +    }
            +},
            +{
            +    id:'help',
            +    qtip: 'Get Help',
            +    handler: function(event, toolEl, panel){
            +        // whatever
            +    }
            +}]
            +
            + *

            For the custom id of 'help' define two relevant css classes with a link to + * a 15x15 image:

            + *
            
            +.x-tool-help {background-image: url(images/help.png);}
            +.x-tool-help-over {background-image: url(images/help_over.png);}
            +// if using an image sprite:
            +.x-tool-help {background-image: url(images/help.png) no-repeat 0 0;}
            +.x-tool-help-over {background-position:-15px 0;}
            +
            */ - cancelEdit : function(remainVisible){ - if(this.editing){ - var v = this.getValue(); - this.setValue(this.startValue); - this.hideEdit(remainVisible); - this.fireEvent("canceledit", this, v, this.startValue); - } - }, - - // private - hideEdit: function(remainVisible){ - if(remainVisible !== true){ - this.editing = false; - this.hide(); - } - }, - - // private - onBlur : function(){ - if(this.allowBlur !== true && this.editing){ - this.completeEdit(); - } - }, - - // private - onHide : function(){ - if(this.editing){ - this.completeEdit(); - return; - } - this.field.blur(); - if(this.field.collapse){ - this.field.collapse(); - } - this.el.hide(); - if(this.hideEl !== false){ - this.boundEl.show(); - } - }, - /** - * Sets the data value of the editor - * @param {Mixed} value Any valid value supported by the underlying field + * @cfg {Ext.Template/Ext.XTemplate} toolTemplate + *

            A Template used to create {@link #tools} in the {@link #header} Element. Defaults to:

            
            +new Ext.Template('<div class="x-tool x-tool-{id}">&#160;</div>')
            + *

            This may may be overridden to provide a custom DOM structure for tools based upon a more + * complex XTemplate. The template's data is a single tool configuration object (Not the entire Array) + * as specified in {@link #tools}. In the following example an <a> tag is used to provide a + * visual indication when hovering over the tool:

            
            +var win = new Ext.Window({
            +    tools: [{
            +        id: 'download',
            +        href: '/MyPdfDoc.pdf'
            +    }],
            +    toolTemplate: new Ext.XTemplate(
            +        '<tpl if="id==\'download\'">',
            +            '<a class="x-tool x-tool-pdf" href="{href}"></a>',
            +        '</tpl>',
            +        '<tpl if="id!=\'download\'">',
            +            '<div class="x-tool x-tool-{id}">&#160;</div>',
            +        '</tpl>'
            +    ),
            +    width:500,
            +    height:300,
            +    closeAction:'hide'
            +});
            + *

            Note that the CSS class 'x-tool-pdf' should have an associated style rule which provides an + * appropriate background image, something like:

            +
            
            +    a.x-tool-pdf {background-image: url(../shared/extjs/images/pdf.gif)!important;}
            +    
            */ - setValue : function(v){ - this.field.setValue(v); - }, - /** - * Gets the data value of the editor - * @return {Mixed} The data value + * @cfg {Boolean} hideCollapseTool + * true to hide the expand/collapse toggle button when {@link #collapsible} == true, + * false to display it (defaults to false). */ - getValue : function(){ - return this.field.getValue(); - }, - - beforeDestroy : function(){ - Ext.destroy(this.field); - this.field = null; - } -}); -Ext.reg('editor', Ext.Editor);/** - * @class Ext.ColorPalette - * @extends Ext.Component - * Simple color palette class for choosing colors. The palette can be rendered to any container.
            - * Here's an example of typical usage: - *
            
            -var cp = new Ext.ColorPalette({value:'993300'});  // initial selected color
            -cp.render('my-div');
            -
            -cp.on('select', function(palette, selColor){
            -    // do something with selColor
            -});
            -
            - * @constructor - * Create a new ColorPalette - * @param {Object} config The config object - * @xtype colorpalette - */ -Ext.ColorPalette = function(config){ - Ext.ColorPalette.superclass.constructor.call(this, config); - this.addEvents( - /** - * @event select - * Fires when a color is selected - * @param {ColorPalette} this - * @param {String} color The 6-digit color hex code (without the # symbol) - */ - 'select' - ); - - if(this.handler){ - this.on("select", this.handler, this.scope, true); - } -}; -Ext.extend(Ext.ColorPalette, Ext.Component, { - /** - * @cfg {String} tpl An existing XTemplate instance to be used in place of the default template for rendering the component. - */ /** - * @cfg {String} itemCls - * The CSS class to apply to the containing element (defaults to "x-color-palette") + * @cfg {Boolean} titleCollapse + * true to allow expanding and collapsing the panel (when {@link #collapsible} = true) + * by clicking anywhere in the header bar, false) to allow it only by clicking to tool button + * (defaults to false)). If this panel is a child item of a border layout also see the + * {@link Ext.layout.BorderLayout.Region BorderLayout.Region} + * {@link Ext.layout.BorderLayout.Region#floatable floatable} config option. */ - itemCls : "x-color-palette", + /** - * @cfg {String} value - * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that - * the hex codes are case-sensitive. + * @cfg {Mixed} floating + *

            This property is used to configure the underlying {@link Ext.Layer}. Acceptable values for this + * configuration property are:

              + *
            • false : Default.
              Display the panel inline where it is + * rendered.
            • + *
            • true :
              Float the panel (absolute position it with automatic + * shimming and shadow).
                + *
                Setting floating to true will create an Ext.Layer for this panel and display the + * panel at negative offsets so that it is hidden.
                + *
                Since the panel will be absolute positioned, the position must be set explicitly + * after render (e.g., myPanel.setPosition(100,100);).
                + *
                Note: when floating a panel you should always assign a fixed width, + * otherwise it will be auto width and will expand to fill to the right edge of the viewport.
                + *
            • + *
            • {@link Ext.Layer object} :
              The specified object will be used + * as the configuration object for the {@link Ext.Layer} that will be created.
            • + *
            */ - value : null, - clickEvent:'click', - // private - ctype: "Ext.ColorPalette", - /** - * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the {@link #select} event + * @cfg {Boolean/String} shadow + * true (or a valid Ext.Shadow {@link Ext.Shadow#mode} value) to display a shadow behind the + * panel, false to display no shadow (defaults to 'sides'). Note that this option + * only applies when {@link #floating} = true. */ - allowReselect : false, - /** - *

            An array of 6-digit color hex code strings (without the # symbol). This array can contain any number - * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting - * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number - * of colors with the width setting until the box is symmetrical.

            - *

            You can override individual colors if needed:

            - *
            
            -var cp = new Ext.ColorPalette();
            -cp.colors[0] = "FF0000";  // change the first box to red
            -
            - -Or you can provide a custom array of your own for complete control: -
            
            -var cp = new Ext.ColorPalette();
            -cp.colors = ["000000", "993300", "333300"];
            -
            - * @type Array + * @cfg {Number} shadowOffset + * The number of pixels to offset the shadow if displayed (defaults to 4). Note that this + * option only applies when {@link #floating} = true. */ - colors : [ - "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333", - "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080", - "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696", - "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0", - "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF" - ], - - // private - onRender : function(container, position){ - var t = this.tpl || new Ext.XTemplate( - ' ' - ); - var el = document.createElement("div"); - el.id = this.getId(); - el.className = this.itemCls; - t.overwrite(el, this.colors); - container.dom.insertBefore(el, position); - this.el = Ext.get(el); - this.mon(this.el, this.clickEvent, this.handleClick, this, {delegate: 'a'}); - if(this.clickEvent != 'click'){ - this.mon(this.el, 'click', Ext.emptyFn, this, {delegate: 'a', preventDefault: true}); - } - }, - - // private - afterRender : function(){ - Ext.ColorPalette.superclass.afterRender.call(this); - if(this.value){ - var s = this.value; - this.value = null; - this.select(s); - } - }, - - // private - handleClick : function(e, t){ - e.preventDefault(); - if(!this.disabled){ - var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1]; - this.select(c.toUpperCase()); - } - }, - /** - * Selects the specified color in the palette (fires the {@link #select} event) - * @param {String} color A valid 6-digit color hex code (# will be stripped if included) + * @cfg {Boolean} shim + * false to disable the iframe shim in browsers which need one (defaults to true). + * Note that this option only applies when {@link #floating} = true. */ - select : function(color){ - color = color.replace("#", ""); - if(color != this.value || this.allowReselect){ - var el = this.el; - if(this.value){ - el.child("a.color-"+this.value).removeClass("x-color-palette-sel"); - } - el.child("a.color-"+color).addClass("x-color-palette-sel"); - this.value = color; - this.fireEvent("select", this, color); - } - } - /** - * @cfg {String} autoEl @hide + * @cfg {Object/Array} keys + * A {@link Ext.KeyMap} config object (in the format expected by {@link Ext.KeyMap#addBinding} + * used to assign custom key handling to this panel (defaults to null). */ + /** + * @cfg {Boolean/Object} draggable + *

            true to enable dragging of this Panel (defaults to false).

            + *

            For custom drag/drop implementations, an Ext.Panel.DD config could also be passed + * in this config instead of true. Ext.Panel.DD is an internal, undocumented class which + * moves a proxy Element around in place of the Panel's element, but provides no other behaviour + * during dragging or on drop. It is a subclass of {@link Ext.dd.DragSource}, so behaviour may be + * added by implementing the interface methods of {@link Ext.dd.DragDrop} e.g.: + *

            
            +new Ext.Panel({
            +    title: 'Drag me',
            +    x: 100,
            +    y: 100,
            +    renderTo: Ext.getBody(),
            +    floating: true,
            +    frame: true,
            +    width: 400,
            +    height: 200,
            +    draggable: {
            +//      Config option of Ext.Panel.DD class.
            +//      It's a floating Panel, so do not show a placeholder proxy in the original position.
            +        insertProxy: false,
            +
            +//      Called for each mousemove event while dragging the DD object.
            +        onDrag : function(e){
            +//          Record the x,y position of the drag proxy so that we can
            +//          position the Panel at end of drag.
            +            var pel = this.proxy.getEl();
            +            this.x = pel.getLeft(true);
            +            this.y = pel.getTop(true);
            +
            +//          Keep the Shadow aligned if there is one.
            +            var s = this.panel.getEl().shadow;
            +            if (s) {
            +                s.realign(this.x, this.y, pel.getWidth(), pel.getHeight());
            +            }
            +        },
            +
            +//      Called on the mouseup event.
            +        endDrag : function(e){
            +            this.panel.setPosition(this.x, this.y);
            +        }
            +    }
            +}).show();
            +
            + */ + /** + * @cfg {Boolean} disabled + * Render this panel disabled (default is false). An important note when using the disabled + * config on panels is that IE will often fail to initialize the disabled mask element correectly if + * the panel's layout has not yet completed by the time the Panel is disabled during the render process. + * If you experience this issue, you may need to instead use the {@link #afterlayout} event to initialize + * the disabled state: + *
            
            +new Ext.Panel({
            +    ...
            +    listeners: {
            +        'afterlayout': {
            +            fn: function(p){
            +                p.disable();
            +            },
            +            single: true // important, as many layouts can occur
            +        }
            +    }
             });
            -Ext.reg('colorpalette', Ext.ColorPalette);/**
            - * @class Ext.DatePicker
            - * @extends Ext.Component
            - * Simple date picker class.
            - * @constructor
            - * Create a new DatePicker
            - * @param {Object} config The config object
            - * @xtype datepicker
            - */
            -Ext.DatePicker = Ext.extend(Ext.BoxComponent, {
            -    /**
            -     * @cfg {String} todayText
            -     * The text to display on the button that selects the current date (defaults to 'Today')
            -     */
            -    todayText : 'Today',
            -    /**
            -     * @cfg {String} okText
            -     * The text to display on the ok button (defaults to ' OK ' to give the user extra clicking room)
            -     */
            -    okText : ' OK ',
            -    /**
            -     * @cfg {String} cancelText
            -     * The text to display on the cancel button (defaults to 'Cancel')
            -     */
            -    cancelText : 'Cancel',
            -    /**
            -     * @cfg {String} todayTip
            -     * The tooltip to display for the button that selects the current date (defaults to '{current date} (Spacebar)')
            -     */
            -    todayTip : '{0} (Spacebar)',
            -    /**
            -     * @cfg {String} minText
            -     * The error text to display if the minDate validation fails (defaults to 'This date is before the minimum date')
            -     */
            -    minText : 'This date is before the minimum date',
            -    /**
            -     * @cfg {String} maxText
            -     * The error text to display if the maxDate validation fails (defaults to 'This date is after the maximum date')
            -     */
            -    maxText : 'This date is after the maximum date',
            -    /**
            -     * @cfg {String} format
            -     * The default date format string which can be overriden for localization support.  The format must be
            -     * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
            -     */
            -    format : 'm/d/y',
            -    /**
            -     * @cfg {String} disabledDaysText
            -     * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
            -     */
            -    disabledDaysText : 'Disabled',
            -    /**
            -     * @cfg {String} disabledDatesText
            -     * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
            -     */
            -    disabledDatesText : 'Disabled',
            -    /**
            -     * @cfg {Array} monthNames
            -     * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
            -     */
            -    monthNames : Date.monthNames,
            -    /**
            -     * @cfg {Array} dayNames
            -     * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
            -     */
            -    dayNames : Date.dayNames,
            -    /**
            -     * @cfg {String} nextText
            -     * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
            -     */
            -    nextText : 'Next Month (Control+Right)',
            -    /**
            -     * @cfg {String} prevText
            -     * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
            -     */
            -    prevText : 'Previous Month (Control+Left)',
            -    /**
            -     * @cfg {String} monthYearText
            -     * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
            -     */
            -    monthYearText : 'Choose a month (Control+Up/Down to move years)',
            -    /**
            -     * @cfg {Number} startDay
            -     * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
            -     */
            -    startDay : 0,
            -    /**
            -     * @cfg {Boolean} showToday
            -     * False to hide the footer area containing the Today button and disable the keyboard handler for spacebar
            -     * that selects the current date (defaults to true).
            -     */
            -    showToday : true,
            -    /**
            -     * @cfg {Date} minDate
            -     * Minimum allowable date (JavaScript date object, defaults to null)
            -     */
            -    /**
            -     * @cfg {Date} maxDate
            -     * Maximum allowable date (JavaScript date object, defaults to null)
            -     */
            -    /**
            -     * @cfg {Array} disabledDays
            -     * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
            -     */
            -    /**
            -     * @cfg {RegExp} disabledDatesRE
            -     * JavaScript regular expression used to disable a pattern of dates (defaults to null).  The {@link #disabledDates}
            -     * config will generate this regex internally, but if you specify disabledDatesRE it will take precedence over the
            -     * disabledDates value.
            -     */
            -    /**
            -     * @cfg {Array} disabledDates
            -     * An array of 'dates' to disable, as strings. These strings will be used to build a dynamic regular
            -     * expression so they are very powerful. Some examples:
            -     * 
              - *
            • ['03/08/2003', '09/16/2003'] would disable those exact dates
            • - *
            • ['03/08', '09/16'] would disable those days for every year
            • - *
            • ['^03/08'] would only match the beginning (useful if you are using short years)
            • - *
            • ['03/../2006'] would disable every day in March 2006
            • - *
            • ['^03'] would disable every day in every March
            • - *
            - * Note that the format of the dates included in the array should exactly match the {@link #format} config. - * In order to support regular expressions, if you are using a date format that has '.' in it, you will have to - * escape the dot when restricting dates. For example: ['03\\.08\\.03']. - */ - - // private - initComponent : function(){ - Ext.DatePicker.superclass.initComponent.call(this); - - this.value = this.value ? - this.value.clearTime() : new Date().clearTime(); - - this.addEvents( - /** - * @event select - * Fires when a date is selected - * @param {DatePicker} this - * @param {Date} date The selected date - */ - 'select' - ); - - if(this.handler){ - this.on('select', this.handler, this.scope || this); - } - - this.initDisabledDays(); - }, - - // private - initDisabledDays : function(){ - if(!this.disabledDatesRE && this.disabledDates){ - var dd = this.disabledDates, - len = dd.length - 1, - re = '(?:'; - - Ext.each(dd, function(d, i){ - re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i]; - if(i != len){ - re += '|'; - } - }, this); - this.disabledDatesRE = new RegExp(re + ')'); - } - }, - - /** - * Replaces any existing disabled dates with new values and refreshes the DatePicker. - * @param {Array/RegExp} disabledDates An array of date strings (see the {@link #disabledDates} config - * for details on supported values), or a JavaScript regular expression used to disable a pattern of dates. - */ - setDisabledDates : function(dd){ - if(Ext.isArray(dd)){ - this.disabledDates = dd; - this.disabledDatesRE = null; - }else{ - this.disabledDatesRE = dd; - } - this.initDisabledDays(); - this.update(this.value, true); - }, - - /** - * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker. - * @param {Array} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config - * for details on supported values. - */ - setDisabledDays : function(dd){ - this.disabledDays = dd; - this.update(this.value, true); - }, - - /** - * Replaces any existing {@link #minDate} with the new value and refreshes the DatePicker. - * @param {Date} value The minimum date that can be selected - */ - setMinDate : function(dt){ - this.minDate = dt; - this.update(this.value, true); - }, - - /** - * Replaces any existing {@link #maxDate} with the new value and refreshes the DatePicker. - * @param {Date} value The maximum date that can be selected - */ - setMaxDate : function(dt){ - this.maxDate = dt; - this.update(this.value, true); - }, - - /** - * Sets the value of the date field - * @param {Date} value The date to set - */ - setValue : function(value){ - var old = this.value; - this.value = value.clearTime(true); - if(this.el){ - this.update(this.value); - } - }, - - /** - * Gets the current selected value of the date field - * @return {Date} The selected date - */ - getValue : function(){ - return this.value; - }, - - // private - focus : function(){ - if(this.el){ - this.update(this.activeDate); - } - }, - - // private - onEnable: function(initial){ - Ext.DatePicker.superclass.onEnable.call(this); - this.doDisabled(false); - this.update(initial ? this.value : this.activeDate); - if(Ext.isIE){ - this.el.repaint(); - } - - }, - - // private - onDisable: function(){ - Ext.DatePicker.superclass.onDisable.call(this); - this.doDisabled(true); - if(Ext.isIE && !Ext.isIE8){ - /* Really strange problem in IE6/7, when disabled, have to explicitly - * repaint each of the nodes to get them to display correctly, simply - * calling repaint on the main element doesn't appear to be enough. - */ - Ext.each([].concat(this.textNodes, this.el.query('th span')), function(el){ - Ext.fly(el).repaint(); - }); - } - }, - - // private - doDisabled: function(disabled){ - this.keyNav.setDisabled(disabled); - this.prevRepeater.setDisabled(disabled); - this.nextRepeater.setDisabled(disabled); - if(this.showToday){ - this.todayKeyListener.setDisabled(disabled); - this.todayBtn.setDisabled(disabled); - } - }, - - // private - onRender : function(container, position){ - var m = [ - '', - '', - '', - this.showToday ? '' : '', - '
              
            '], - dn = this.dayNames, - i; - for(i = 0; i < 7; i++){ - var d = this.startDay+i; - if(d > 6){ - d = d-7; - } - m.push(''); - } - m[m.length] = ''; - for(i = 0; i < 42; i++) { - if(i % 7 === 0 && i !== 0){ - m[m.length] = ''; - } - m[m.length] = ''; - } - m.push('
            ', dn[d].substr(0,1), '
            '); - - var el = document.createElement('div'); - el.className = 'x-date-picker'; - el.innerHTML = m.join(''); - - container.dom.insertBefore(el, position); - - this.el = Ext.get(el); - this.eventEl = Ext.get(el.firstChild); - - this.prevRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-left a'), { - handler: this.showPrevMonth, - scope: this, - preventDefault:true, - stopDefault:true - }); - - this.nextRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-right a'), { - handler: this.showNextMonth, - scope: this, - preventDefault:true, - stopDefault:true - }); - - this.monthPicker = this.el.down('div.x-date-mp'); - this.monthPicker.enableDisplayMode('block'); - - this.keyNav = new Ext.KeyNav(this.eventEl, { - 'left' : function(e){ - if(e.ctrlKey){ - this.showPrevMonth(); - }else{ - this.update(this.activeDate.add('d', -1)); - } - }, - - 'right' : function(e){ - if(e.ctrlKey){ - this.showNextMonth(); - }else{ - this.update(this.activeDate.add('d', 1)); - } - }, - - 'up' : function(e){ - if(e.ctrlKey){ - this.showNextYear(); - }else{ - this.update(this.activeDate.add('d', -7)); - } - }, - - 'down' : function(e){ - if(e.ctrlKey){ - this.showPrevYear(); - }else{ - this.update(this.activeDate.add('d', 7)); - } - }, - - 'pageUp' : function(e){ - this.showNextMonth(); - }, - - 'pageDown' : function(e){ - this.showPrevMonth(); - }, - - 'enter' : function(e){ - e.stopPropagation(); - return true; - }, - - scope : this - }); - - this.el.unselectable(); - - this.cells = this.el.select('table.x-date-inner tbody td'); - this.textNodes = this.el.query('table.x-date-inner tbody span'); - - this.mbtn = new Ext.Button({ - text: ' ', - tooltip: this.monthYearText, - renderTo: this.el.child('td.x-date-middle', true) - }); - this.mbtn.el.child('em').addClass('x-btn-arrow'); - - if(this.showToday){ - this.todayKeyListener = this.eventEl.addKeyListener(Ext.EventObject.SPACE, this.selectToday, this); - var today = (new Date()).dateFormat(this.format); - this.todayBtn = new Ext.Button({ - renderTo: this.el.child('td.x-date-bottom', true), - text: String.format(this.todayText, today), - tooltip: String.format(this.todayTip, today), - handler: this.selectToday, - scope: this - }); - } - this.mon(this.eventEl, 'mousewheel', this.handleMouseWheel, this); - this.mon(this.eventEl, 'click', this.handleDateClick, this, {delegate: 'a.x-date-date'}); - this.mon(this.mbtn, 'click', this.showMonthPicker, this); - this.onEnable(true); - }, - - // private - createMonthPicker : function(){ - if(!this.monthPicker.dom.firstChild){ - var buf = ['']; - for(var i = 0; i < 6; i++){ - buf.push( - '', - '', - i === 0 ? - '' : - '' - ); - } - buf.push( - '', - '
            ', Date.getShortMonthName(i), '', Date.getShortMonthName(i + 6), '
            ' - ); - this.monthPicker.update(buf.join('')); - - this.mon(this.monthPicker, 'click', this.onMonthClick, this); - this.mon(this.monthPicker, 'dblclick', this.onMonthDblClick, this); - - this.mpMonths = this.monthPicker.select('td.x-date-mp-month'); - this.mpYears = this.monthPicker.select('td.x-date-mp-year'); - - this.mpMonths.each(function(m, a, i){ - i += 1; - if((i%2) === 0){ - m.dom.xmonth = 5 + Math.round(i * 0.5); - }else{ - m.dom.xmonth = Math.round((i-1) * 0.5); - } - }); - } - }, - - // private - showMonthPicker : function(){ - if(!this.disabled){ - this.createMonthPicker(); - var size = this.el.getSize(); - this.monthPicker.setSize(size); - this.monthPicker.child('table').setSize(size); - - this.mpSelMonth = (this.activeDate || this.value).getMonth(); - this.updateMPMonth(this.mpSelMonth); - this.mpSelYear = (this.activeDate || this.value).getFullYear(); - this.updateMPYear(this.mpSelYear); - - this.monthPicker.slideIn('t', {duration:0.2}); - } - }, - - // private - updateMPYear : function(y){ - this.mpyear = y; - var ys = this.mpYears.elements; - for(var i = 1; i <= 10; i++){ - var td = ys[i-1], y2; - if((i%2) === 0){ - y2 = y + Math.round(i * 0.5); - td.firstChild.innerHTML = y2; - td.xyear = y2; - }else{ - y2 = y - (5-Math.round(i * 0.5)); - td.firstChild.innerHTML = y2; - td.xyear = y2; - } - this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel'); - } - }, - - // private - updateMPMonth : function(sm){ - this.mpMonths.each(function(m, a, i){ - m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel'); - }); - }, - - // private - selectMPMonth : function(m){ - - }, - - // private - onMonthClick : function(e, t){ - e.stopEvent(); - var el = new Ext.Element(t), pn; - if(el.is('button.x-date-mp-cancel')){ - this.hideMonthPicker(); - } - else if(el.is('button.x-date-mp-ok')){ - var d = new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()); - if(d.getMonth() != this.mpSelMonth){ - // 'fix' the JS rolling date conversion if needed - d = new Date(this.mpSelYear, this.mpSelMonth, 1).getLastDateOfMonth(); - } - this.update(d); - this.hideMonthPicker(); - } - else if((pn = el.up('td.x-date-mp-month', 2))){ - this.mpMonths.removeClass('x-date-mp-sel'); - pn.addClass('x-date-mp-sel'); - this.mpSelMonth = pn.dom.xmonth; - } - else if((pn = el.up('td.x-date-mp-year', 2))){ - this.mpYears.removeClass('x-date-mp-sel'); - pn.addClass('x-date-mp-sel'); - this.mpSelYear = pn.dom.xyear; - } - else if(el.is('a.x-date-mp-prev')){ - this.updateMPYear(this.mpyear-10); - } - else if(el.is('a.x-date-mp-next')){ - this.updateMPYear(this.mpyear+10); - } - }, - - // private - onMonthDblClick : function(e, t){ - e.stopEvent(); - var el = new Ext.Element(t), pn; - if((pn = el.up('td.x-date-mp-month', 2))){ - this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate())); - this.hideMonthPicker(); - } - else if((pn = el.up('td.x-date-mp-year', 2))){ - this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate())); - this.hideMonthPicker(); - } - }, - - // private - hideMonthPicker : function(disableAnim){ - if(this.monthPicker){ - if(disableAnim === true){ - this.monthPicker.hide(); - }else{ - this.monthPicker.slideOut('t', {duration:0.2}); - } - } - }, - - // private - showPrevMonth : function(e){ - this.update(this.activeDate.add('mo', -1)); - }, - - // private - showNextMonth : function(e){ - this.update(this.activeDate.add('mo', 1)); - }, - - // private - showPrevYear : function(){ - this.update(this.activeDate.add('y', -1)); - }, - - // private - showNextYear : function(){ - this.update(this.activeDate.add('y', 1)); - }, - - // private - handleMouseWheel : function(e){ - e.stopEvent(); - if(!this.disabled){ - var delta = e.getWheelDelta(); - if(delta > 0){ - this.showPrevMonth(); - } else if(delta < 0){ - this.showNextMonth(); - } - } - }, - - // private - handleDateClick : function(e, t){ - e.stopEvent(); - if(!this.disabled && t.dateValue && !Ext.fly(t.parentNode).hasClass('x-date-disabled')){ - this.setValue(new Date(t.dateValue)); - this.fireEvent('select', this, this.value); - } - }, - - // private - selectToday : function(){ - if(this.todayBtn && !this.todayBtn.disabled){ - this.setValue(new Date().clearTime()); - this.fireEvent('select', this, this.value); - } - }, - - // private - update : function(date, forceRefresh){ - var vd = this.activeDate, vis = this.isVisible(); - this.activeDate = date; - if(!forceRefresh && vd && this.el){ - var t = date.getTime(); - if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){ - this.cells.removeClass('x-date-selected'); - this.cells.each(function(c){ - if(c.dom.firstChild.dateValue == t){ - c.addClass('x-date-selected'); - if(vis){ - Ext.fly(c.dom.firstChild).focus(50); - } - return false; - } - }); - return; - } - } - var days = date.getDaysInMonth(); - var firstOfMonth = date.getFirstDateOfMonth(); - var startingPos = firstOfMonth.getDay()-this.startDay; - - if(startingPos <= this.startDay){ - startingPos += 7; - } - - var pm = date.add('mo', -1); - var prevStart = pm.getDaysInMonth()-startingPos; - - var cells = this.cells.elements; - var textEls = this.textNodes; - days += startingPos; - - // convert everything to numbers so it's fast - var day = 86400000; - var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime(); - var today = new Date().clearTime().getTime(); - var sel = date.clearTime().getTime(); - var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY; - var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY; - var ddMatch = this.disabledDatesRE; - var ddText = this.disabledDatesText; - var ddays = this.disabledDays ? this.disabledDays.join('') : false; - var ddaysText = this.disabledDaysText; - var format = this.format; - - if(this.showToday){ - var td = new Date().clearTime(); - var disable = (td < min || td > max || - (ddMatch && format && ddMatch.test(td.dateFormat(format))) || - (ddays && ddays.indexOf(td.getDay()) != -1)); - - if(!this.disabled){ - this.todayBtn.setDisabled(disable); - this.todayKeyListener[disable ? 'disable' : 'enable'](); - } - } - - var setCellClass = function(cal, cell){ - cell.title = ''; - var t = d.getTime(); - cell.firstChild.dateValue = t; - if(t == today){ - cell.className += ' x-date-today'; - cell.title = cal.todayText; - } - if(t == sel){ - cell.className += ' x-date-selected'; - if(vis){ - Ext.fly(cell.firstChild).focus(50); - } - } - // disabling - if(t < min) { - cell.className = ' x-date-disabled'; - cell.title = cal.minText; - return; - } - if(t > max) { - cell.className = ' x-date-disabled'; - cell.title = cal.maxText; - return; - } - if(ddays){ - if(ddays.indexOf(d.getDay()) != -1){ - cell.title = ddaysText; - cell.className = ' x-date-disabled'; - } - } - if(ddMatch && format){ - var fvalue = d.dateFormat(format); - if(ddMatch.test(fvalue)){ - cell.title = ddText.replace('%0', fvalue); - cell.className = ' x-date-disabled'; - } - } - }; - - var i = 0; - for(; i < startingPos; i++) { - textEls[i].innerHTML = (++prevStart); - d.setDate(d.getDate()+1); - cells[i].className = 'x-date-prevday'; - setCellClass(this, cells[i]); - } - for(; i < days; i++){ - var intDay = i - startingPos + 1; - textEls[i].innerHTML = (intDay); - d.setDate(d.getDate()+1); - cells[i].className = 'x-date-active'; - setCellClass(this, cells[i]); - } - var extraDays = 0; - for(; i < 42; i++) { - textEls[i].innerHTML = (++extraDays); - d.setDate(d.getDate()+1); - cells[i].className = 'x-date-nextday'; - setCellClass(this, cells[i]); - } - - this.mbtn.setText(this.monthNames[date.getMonth()] + ' ' + date.getFullYear()); - - if(!this.internalRender){ - var main = this.el.dom.firstChild; - var w = main.offsetWidth; - this.el.setWidth(w + this.el.getBorderWidth('lr')); - Ext.fly(main).setWidth(w); - this.internalRender = true; - // opera does not respect the auto grow header center column - // then, after it gets a width opera refuses to recalculate - // without a second pass - if(Ext.isOpera && !this.secondPass){ - main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + 'px'; - this.secondPass = true; - this.update.defer(10, this, [date]); - } - } - }, - - // private - beforeDestroy : function() { - if(this.rendered){ - this.keyNav.disable(); - this.keyNav = null; - Ext.destroy( - this.leftClickRpt, - this.rightClickRpt, - this.monthPicker, - this.eventEl, - this.mbtn, - this.todayBtn - ); - } - } - - /** - * @cfg {String} autoEl @hide - */ -}); - -Ext.reg('datepicker', Ext.DatePicker); +
            + */ + /** + * @cfg {Boolean} autoHeight + * true to use height:'auto', false to use fixed height (defaults to false). + * Note: Setting autoHeight: true means that the browser will manage the panel's height + * based on its contents, and that Ext will not manage it at all. If the panel is within a layout that + * manages dimensions (fit, border, etc.) then setting autoHeight: true + * can cause issues with scrolling and will not generally work as expected since the panel will take + * on the height of its contents rather than the height required by the Ext layout. + */ + + + /** + * @cfg {String} baseCls + * The base CSS class to apply to this panel's element (defaults to 'x-panel'). + *

            Another option available by default is to specify 'x-plain' which strips all styling + * except for required attributes for Ext layouts to function (e.g. overflow:hidden). + * See {@link #unstyled} also.

            + */ + baseCls : 'x-panel', + /** + * @cfg {String} collapsedCls + * A CSS class to add to the panel's element after it has been collapsed (defaults to + * 'x-panel-collapsed'). + */ + collapsedCls : 'x-panel-collapsed', + /** + * @cfg {Boolean} maskDisabled + * true to mask the panel when it is {@link #disabled}, false to not mask it (defaults + * to true). Either way, the panel will always tell its contained elements to disable themselves + * when it is disabled, but masking the panel can provide an additional visual cue that the panel is + * disabled. + */ + maskDisabled : true, + /** + * @cfg {Boolean} animCollapse + * true to animate the transition when the panel is collapsed, false to skip the + * animation (defaults to true if the {@link Ext.Fx} class is available, otherwise false). + */ + animCollapse : Ext.enableFx, + /** + * @cfg {Boolean} headerAsText + * true to display the panel {@link #title} in the {@link #header}, + * false to hide it (defaults to true). + */ + headerAsText : true, + /** + * @cfg {String} buttonAlign + * The alignment of any {@link #buttons} added to this panel. Valid values are 'right', + * 'left' and 'center' (defaults to 'right'). + */ + buttonAlign : 'right', + /** + * @cfg {Boolean} collapsed + * true to render the panel collapsed, false to render it expanded (defaults to + * false). + */ + collapsed : false, + /** + * @cfg {Boolean} collapseFirst + * true to make sure the collapse/expand toggle button always renders first (to the left of) + * any other tools in the panel's title bar, false to render it last (defaults to true). + */ + collapseFirst : true, + /** + * @cfg {Number} minButtonWidth + * Minimum width in pixels of all {@link #buttons} in this panel (defaults to 75) + */ + minButtonWidth : 75, + /** + * @cfg {Boolean} unstyled + * Overrides the {@link #baseCls} setting to {@link #baseCls} = 'x-plain' which renders + * the panel unstyled except for required attributes for Ext layouts to function (e.g. overflow:hidden). + */ + /** + * @cfg {String} elements + * A comma-delimited list of panel elements to initialize when the panel is rendered. Normally, this list will be + * generated automatically based on the items added to the panel at config time, but sometimes it might be useful to + * make sure a structural element is rendered even if not specified at config time (for example, you may want + * to add a button or toolbar dynamically after the panel has been rendered). Adding those elements to this + * list will allocate the required placeholders in the panel when it is rendered. Valid values are
              + *
            • header
            • + *
            • tbar (top bar)
            • + *
            • body
            • + *
            • bbar (bottom bar)
            • + *
            • footer
            • + *
            + * Defaults to 'body'. + */ + elements : 'body', + /** + * @cfg {Boolean} preventBodyReset + * Defaults to false. When set to true, an extra css class 'x-panel-normal' + * will be added to the panel's element, effectively applying css styles suggested by the W3C + * (see http://www.w3.org/TR/CSS21/sample.html) to the Panel's body element (not the header, + * footer, etc.). + */ + preventBodyReset : false, + + /** + * @cfg {Number/String} padding + * A shortcut for setting a padding style on the body element. The value can either be + * a number to be applied to all sides, or a normal css string describing padding. + * Defaults to undefined. + * + */ + padding: undefined, + + /** @cfg {String} resizeEvent + * The event to listen to for resizing in layouts. Defaults to 'bodyresize'. + */ + resizeEvent: 'bodyresize', + + // protected - these could be used to customize the behavior of the window, + // but changing them would not be useful without further mofifications and + // could lead to unexpected or undesirable results. + toolTarget : 'header', + collapseEl : 'bwrap', + slideAnchor : 't', + disabledClass : '', + + // private, notify box this class will handle heights + deferHeight : true, + // private + expandDefaults: { + duration : 0.25 + }, + // private + collapseDefaults : { + duration : 0.25 + }, + + // private + initComponent : function(){ + Ext.Panel.superclass.initComponent.call(this); + + this.addEvents( + /** + * @event bodyresize + * Fires after the Panel has been resized. + * @param {Ext.Panel} p the Panel which has been resized. + * @param {Number} width The Panel body's new width. + * @param {Number} height The Panel body's new height. + */ + 'bodyresize', + /** + * @event titlechange + * Fires after the Panel title has been {@link #title set} or {@link #setTitle changed}. + * @param {Ext.Panel} p the Panel which has had its title changed. + * @param {String} The new title. + */ + 'titlechange', + /** + * @event iconchange + * Fires after the Panel icon class has been {@link #iconCls set} or {@link #setIconClass changed}. + * @param {Ext.Panel} p the Panel which has had its {@link #iconCls icon class} changed. + * @param {String} The new icon class. + * @param {String} The old icon class. + */ + 'iconchange', + /** + * @event collapse + * Fires after the Panel has been collapsed. + * @param {Ext.Panel} p the Panel that has been collapsed. + */ + 'collapse', + /** + * @event expand + * Fires after the Panel has been expanded. + * @param {Ext.Panel} p The Panel that has been expanded. + */ + 'expand', + /** + * @event beforecollapse + * Fires before the Panel is collapsed. A handler can return false to cancel the collapse. + * @param {Ext.Panel} p the Panel being collapsed. + * @param {Boolean} animate True if the collapse is animated, else false. + */ + 'beforecollapse', + /** + * @event beforeexpand + * Fires before the Panel is expanded. A handler can return false to cancel the expand. + * @param {Ext.Panel} p The Panel being expanded. + * @param {Boolean} animate True if the expand is animated, else false. + */ + 'beforeexpand', + /** + * @event beforeclose + * Fires before the Panel is closed. Note that Panels do not directly support being closed, but some + * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel. This event only + * applies to such subclasses. + * A handler can return false to cancel the close. + * @param {Ext.Panel} p The Panel being closed. + */ + 'beforeclose', + /** + * @event close + * Fires after the Panel is closed. Note that Panels do not directly support being closed, but some + * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel. + * @param {Ext.Panel} p The Panel that has been closed. + */ + 'close', + /** + * @event activate + * Fires after the Panel has been visually activated. + * Note that Panels do not directly support being activated, but some Panel subclasses + * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the + * activate and deactivate events under the control of the TabPanel. + * @param {Ext.Panel} p The Panel that has been activated. + */ + 'activate', + /** + * @event deactivate + * Fires after the Panel has been visually deactivated. + * Note that Panels do not directly support being deactivated, but some Panel subclasses + * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the + * activate and deactivate events under the control of the TabPanel. + * @param {Ext.Panel} p The Panel that has been deactivated. + */ + 'deactivate' + ); + + if(this.unstyled){ + this.baseCls = 'x-plain'; + } + + + this.toolbars = []; + // shortcuts + if(this.tbar){ + this.elements += ',tbar'; + this.topToolbar = this.createToolbar(this.tbar); + delete this.tbar; + + } + if(this.bbar){ + this.elements += ',bbar'; + this.bottomToolbar = this.createToolbar(this.bbar); + delete this.bbar; + } + + if(this.header === true){ + this.elements += ',header'; + delete this.header; + }else if(this.headerCfg || (this.title && this.header !== false)){ + this.elements += ',header'; + } + + if(this.footerCfg || this.footer === true){ + this.elements += ',footer'; + delete this.footer; + } + + if(this.buttons){ + this.fbar = this.buttons; + delete this.buttons; + } + if(this.fbar){ + this.createFbar(this.fbar); + } + if(this.autoLoad){ + this.on('render', this.doAutoLoad, this, {delay:10}); + } + }, + + // private + createFbar : function(fbar){ + var min = this.minButtonWidth; + this.elements += ',footer'; + this.fbar = this.createToolbar(fbar, { + buttonAlign: this.buttonAlign, + toolbarCls: 'x-panel-fbar', + enableOverflow: false, + defaults: function(c){ + return { + minWidth: c.minWidth || min + }; + } + }); + //@compat addButton and buttons could possibly be removed + //@target 4.0 + /** + * This Panel's Array of buttons as created from the {@link #buttons} + * config property. Read only. + * @type Array + * @property buttons + */ + this.fbar.items.each(function(c){ + c.minWidth = c.minWidth || this.minButtonWidth; + }, this); + this.buttons = this.fbar.items.items; + }, + + // private + createToolbar: function(tb, options){ + var result; + // Convert array to proper toolbar config + if(Ext.isArray(tb)){ + tb = { + items: tb + }; + } + result = tb.events ? Ext.apply(tb, options) : this.createComponent(Ext.apply({}, tb, options), 'toolbar'); + this.toolbars.push(result); + return result; + }, + + // private + createElement : function(name, pnode){ + if(this[name]){ + pnode.appendChild(this[name].dom); + return; + } + + if(name === 'bwrap' || this.elements.indexOf(name) != -1){ + if(this[name+'Cfg']){ + this[name] = Ext.fly(pnode).createChild(this[name+'Cfg']); + }else{ + var el = document.createElement('div'); + el.className = this[name+'Cls']; + this[name] = Ext.get(pnode.appendChild(el)); + } + if(this[name+'CssClass']){ + this[name].addClass(this[name+'CssClass']); + } + if(this[name+'Style']){ + this[name].applyStyles(this[name+'Style']); + } + } + }, + + // private + onRender : function(ct, position){ + Ext.Panel.superclass.onRender.call(this, ct, position); + this.createClasses(); + + var el = this.el, + d = el.dom, + bw, + ts; + + + if(this.collapsible && !this.hideCollapseTool){ + this.tools = this.tools ? this.tools.slice(0) : []; + this.tools[this.collapseFirst?'unshift':'push']({ + id: 'toggle', + handler : this.toggleCollapse, + scope: this + }); + } + + if(this.tools){ + ts = this.tools; + this.elements += (this.header !== false) ? ',header' : ''; + } + this.tools = {}; + + el.addClass(this.baseCls); + if(d.firstChild){ // existing markup + this.header = el.down('.'+this.headerCls); + this.bwrap = el.down('.'+this.bwrapCls); + var cp = this.bwrap ? this.bwrap : el; + this.tbar = cp.down('.'+this.tbarCls); + this.body = cp.down('.'+this.bodyCls); + this.bbar = cp.down('.'+this.bbarCls); + this.footer = cp.down('.'+this.footerCls); + this.fromMarkup = true; + } + if (this.preventBodyReset === true) { + el.addClass('x-panel-reset'); + } + if(this.cls){ + el.addClass(this.cls); + } + + if(this.buttons){ + this.elements += ',footer'; + } + + // This block allows for maximum flexibility and performance when using existing markup + + // framing requires special markup + if(this.frame){ + el.insertHtml('afterBegin', String.format(Ext.Element.boxMarkup, this.baseCls)); + + this.createElement('header', d.firstChild.firstChild.firstChild); + this.createElement('bwrap', d); + + // append the mid and bottom frame to the bwrap + bw = this.bwrap.dom; + var ml = d.childNodes[1], bl = d.childNodes[2]; + bw.appendChild(ml); + bw.appendChild(bl); + + var mc = bw.firstChild.firstChild.firstChild; + this.createElement('tbar', mc); + this.createElement('body', mc); + this.createElement('bbar', mc); + this.createElement('footer', bw.lastChild.firstChild.firstChild); + + if(!this.footer){ + this.bwrap.dom.lastChild.className += ' x-panel-nofooter'; + } + /* + * Store a reference to this element so: + * a) We aren't looking it up all the time + * b) The last element is reported incorrectly when using a loadmask + */ + this.ft = Ext.get(this.bwrap.dom.lastChild); + this.mc = Ext.get(mc); + }else{ + this.createElement('header', d); + this.createElement('bwrap', d); + + // append the mid and bottom frame to the bwrap + bw = this.bwrap.dom; + this.createElement('tbar', bw); + this.createElement('body', bw); + this.createElement('bbar', bw); + this.createElement('footer', bw); + + if(!this.header){ + this.body.addClass(this.bodyCls + '-noheader'); + if(this.tbar){ + this.tbar.addClass(this.tbarCls + '-noheader'); + } + } + } + + if(Ext.isDefined(this.padding)){ + this.body.setStyle('padding', this.body.addUnits(this.padding)); + } + + if(this.border === false){ + this.el.addClass(this.baseCls + '-noborder'); + this.body.addClass(this.bodyCls + '-noborder'); + if(this.header){ + this.header.addClass(this.headerCls + '-noborder'); + } + if(this.footer){ + this.footer.addClass(this.footerCls + '-noborder'); + } + if(this.tbar){ + this.tbar.addClass(this.tbarCls + '-noborder'); + } + if(this.bbar){ + this.bbar.addClass(this.bbarCls + '-noborder'); + } + } + + if(this.bodyBorder === false){ + this.body.addClass(this.bodyCls + '-noborder'); + } + + this.bwrap.enableDisplayMode('block'); + + if(this.header){ + this.header.unselectable(); + + // for tools, we need to wrap any existing header markup + if(this.headerAsText){ + this.header.dom.innerHTML = + ''+this.header.dom.innerHTML+''; + + if(this.iconCls){ + this.setIconClass(this.iconCls); + } + } + } + + if(this.floating){ + this.makeFloating(this.floating); + } + + if(this.collapsible && this.titleCollapse && this.header){ + this.mon(this.header, 'click', this.toggleCollapse, this); + this.header.setStyle('cursor', 'pointer'); + } + if(ts){ + this.addTool.apply(this, ts); + } + + // Render Toolbars. + if(this.fbar){ + this.footer.addClass('x-panel-btns'); + this.fbar.ownerCt = this; + this.fbar.render(this.footer); + this.footer.createChild({cls:'x-clear'}); + } + if(this.tbar && this.topToolbar){ + this.topToolbar.ownerCt = this; + this.topToolbar.render(this.tbar); + } + if(this.bbar && this.bottomToolbar){ + this.bottomToolbar.ownerCt = this; + this.bottomToolbar.render(this.bbar); + } + }, + + /** + * Sets the CSS class that provides the icon image for this panel. This method will replace any existing + * icon class if one has already been set and fire the {@link #iconchange} event after completion. + * @param {String} cls The new CSS class name + */ + setIconClass : function(cls){ + var old = this.iconCls; + this.iconCls = cls; + if(this.rendered && this.header){ + if(this.frame){ + this.header.addClass('x-panel-icon'); + this.header.replaceClass(old, this.iconCls); + }else{ + var hd = this.header, + img = hd.child('img.x-panel-inline-icon'); + if(img){ + Ext.fly(img).replaceClass(old, this.iconCls); + }else{ + Ext.DomHelper.insertBefore(hd.dom.firstChild, { + tag:'img', src: Ext.BLANK_IMAGE_URL, cls:'x-panel-inline-icon '+this.iconCls + }); + } + } + } + this.fireEvent('iconchange', this, cls, old); + }, + + // private + makeFloating : function(cfg){ + this.floating = true; + this.el = new Ext.Layer(Ext.apply({}, cfg, { + shadow: Ext.isDefined(this.shadow) ? this.shadow : 'sides', + shadowOffset: this.shadowOffset, + constrain:false, + shim: this.shim === false ? false : undefined + }), this.el); + }, + + /** + * Returns the {@link Ext.Toolbar toolbar} from the top ({@link #tbar}) section of the panel. + * @return {Ext.Toolbar} The toolbar + */ + getTopToolbar : function(){ + return this.topToolbar; + }, + + /** + * Returns the {@link Ext.Toolbar toolbar} from the bottom ({@link #bbar}) section of the panel. + * @return {Ext.Toolbar} The toolbar + */ + getBottomToolbar : function(){ + return this.bottomToolbar; + }, + + /** + * Adds a button to this panel. Note that this method must be called prior to rendering. The preferred + * approach is to add buttons via the {@link #buttons} config. + * @param {String/Object} config A valid {@link Ext.Button} config. A string will become the text for a default + * button config, an object will be treated as a button config object. + * @param {Function} handler The function to be called on button {@link Ext.Button#click} + * @param {Object} scope The scope (this reference) in which the button handler function is executed. Defaults to the Button. + * @return {Ext.Button} The button that was added + */ + addButton : function(config, handler, scope){ + if(!this.fbar){ + this.createFbar([]); + } + if(handler){ + if(Ext.isString(config)){ + config = {text: config}; + } + config = Ext.apply({ + handler: handler, + scope: scope + }, config) + } + return this.fbar.add(config); + }, + + // private + addTool : function(){ + if(!this.rendered){ + if(!this.tools){ + this.tools = []; + } + Ext.each(arguments, function(arg){ + this.tools.push(arg) + }, this); + return; + } + // nowhere to render tools! + if(!this[this.toolTarget]){ + return; + } + if(!this.toolTemplate){ + // initialize the global tool template on first use + var tt = new Ext.Template( + '
             
            ' + ); + tt.disableFormats = true; + tt.compile(); + Ext.Panel.prototype.toolTemplate = tt; + } + for(var i = 0, a = arguments, len = a.length; i < len; i++) { + var tc = a[i]; + if(!this.tools[tc.id]){ + var overCls = 'x-tool-'+tc.id+'-over'; + var t = this.toolTemplate.insertFirst(this[this.toolTarget], tc, true); + this.tools[tc.id] = t; + t.enableDisplayMode('block'); + this.mon(t, 'click', this.createToolHandler(t, tc, overCls, this)); + if(tc.on){ + this.mon(t, tc.on); + } + if(tc.hidden){ + t.hide(); + } + if(tc.qtip){ + if(Ext.isObject(tc.qtip)){ + Ext.QuickTips.register(Ext.apply({ + target: t.id + }, tc.qtip)); + } else { + t.dom.qtip = tc.qtip; + } + } + t.addClassOnOver(overCls); + } + } + }, + + onLayout : function(shallow, force){ + Ext.Panel.superclass.onLayout.apply(this, arguments); + if(this.hasLayout && this.toolbars.length > 0){ + Ext.each(this.toolbars, function(tb){ + tb.doLayout(undefined, force); + }); + this.syncHeight(); + } + }, + + syncHeight : function(){ + var h = this.toolbarHeight, + bd = this.body, + lsh = this.lastSize.height, + sz; + + if(this.autoHeight || !Ext.isDefined(lsh) || lsh == 'auto'){ + return; + } + + + if(h != this.getToolbarHeight()){ + h = Math.max(0, this.adjustBodyHeight(lsh - this.getFrameHeight())); + bd.setHeight(h); + sz = bd.getSize(); + this.toolbarHeight = this.getToolbarHeight(); + this.onBodyResize(sz.width, sz.height); + } + }, + + // private + onShow : function(){ + if(this.floating){ + return this.el.show(); + } + Ext.Panel.superclass.onShow.call(this); + }, + + // private + onHide : function(){ + if(this.floating){ + return this.el.hide(); + } + Ext.Panel.superclass.onHide.call(this); + }, + + // private + createToolHandler : function(t, tc, overCls, panel){ + return function(e){ + t.removeClass(overCls); + if(tc.stopEvent !== false){ + e.stopEvent(); + } + if(tc.handler){ + tc.handler.call(tc.scope || t, e, t, panel, tc); + } + }; + }, + + // private + afterRender : function(){ + if(this.floating && !this.hidden){ + this.el.show(); + } + if(this.title){ + this.setTitle(this.title); + } + Ext.Panel.superclass.afterRender.call(this); // do sizing calcs last + if (this.collapsed) { + this.collapsed = false; + this.collapse(false); + } + this.initEvents(); + }, + + // private + getKeyMap : function(){ + if(!this.keyMap){ + this.keyMap = new Ext.KeyMap(this.el, this.keys); + } + return this.keyMap; + }, + + // private + initEvents : function(){ + if(this.keys){ + this.getKeyMap(); + } + if(this.draggable){ + this.initDraggable(); + } + if(this.toolbars.length > 0){ + Ext.each(this.toolbars, function(tb){ + tb.doLayout(); + tb.on({ + scope: this, + afterlayout: this.syncHeight, + remove: this.syncHeight + }); + }, this); + this.syncHeight(); + } + + }, + + // private + initDraggable : function(){ + /** + *

            If this Panel is configured {@link #draggable}, this property will contain + * an instance of {@link Ext.dd.DragSource} which handles dragging the Panel.

            + * The developer must provide implementations of the abstract methods of {@link Ext.dd.DragSource} + * in order to supply behaviour for each stage of the drag/drop process. See {@link #draggable}. + * @type Ext.dd.DragSource. + * @property dd + */ + this.dd = new Ext.Panel.DD(this, Ext.isBoolean(this.draggable) ? null : this.draggable); + }, + + // private + beforeEffect : function(anim){ + if(this.floating){ + this.el.beforeAction(); + } + if(anim !== false){ + this.el.addClass('x-panel-animated'); + } + }, + + // private + afterEffect : function(anim){ + this.syncShadow(); + if(anim !== false){ + this.el.removeClass('x-panel-animated'); + } + }, + + // private - wraps up an animation param with internal callbacks + createEffect : function(a, cb, scope){ + var o = { + scope:scope, + block:true + }; + if(a === true){ + o.callback = cb; + return o; + }else if(!a.callback){ + o.callback = cb; + }else { // wrap it up + o.callback = function(){ + cb.call(scope); + Ext.callback(a.callback, a.scope); + }; + } + return Ext.applyIf(o, a); + }, + + /** + * Collapses the panel body so that it becomes hidden. Fires the {@link #beforecollapse} event which will + * cancel the collapse action if it returns false. + * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the + * {@link #animCollapse} panel config) + * @return {Ext.Panel} this + */ + collapse : function(animate){ + if(this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforecollapse', this, animate) === false){ + return; + } + var doAnim = animate === true || (animate !== false && this.animCollapse); + this.beforeEffect(doAnim); + this.onCollapse(doAnim, animate); + return this; + }, + + // private + onCollapse : function(doAnim, animArg){ + if(doAnim){ + this[this.collapseEl].slideOut(this.slideAnchor, + Ext.apply(this.createEffect(animArg||true, this.afterCollapse, this), + this.collapseDefaults)); + }else{ + this[this.collapseEl].hide(); + this.afterCollapse(false); + } + }, + + // private + afterCollapse : function(anim){ + this.collapsed = true; + this.el.addClass(this.collapsedCls); + this.afterEffect(anim); + this.fireEvent('collapse', this); + }, + + /** + * Expands the panel body so that it becomes visible. Fires the {@link #beforeexpand} event which will + * cancel the expand action if it returns false. + * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the + * {@link #animCollapse} panel config) + * @return {Ext.Panel} this + */ + expand : function(animate){ + if(!this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforeexpand', this, animate) === false){ + return; + } + var doAnim = animate === true || (animate !== false && this.animCollapse); + this.el.removeClass(this.collapsedCls); + this.beforeEffect(doAnim); + this.onExpand(doAnim, animate); + return this; + }, + + // private + onExpand : function(doAnim, animArg){ + if(doAnim){ + this[this.collapseEl].slideIn(this.slideAnchor, + Ext.apply(this.createEffect(animArg||true, this.afterExpand, this), + this.expandDefaults)); + }else{ + this[this.collapseEl].show(); + this.afterExpand(false); + } + }, + + // private + afterExpand : function(anim){ + this.collapsed = false; + this.afterEffect(anim); + if (this.deferLayout) { + delete this.deferLayout; + this.doLayout(true); + } + this.fireEvent('expand', this); + }, + + /** + * Shortcut for performing an {@link #expand} or {@link #collapse} based on the current state of the panel. + * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the + * {@link #animCollapse} panel config) + * @return {Ext.Panel} this + */ + toggleCollapse : function(animate){ + this[this.collapsed ? 'expand' : 'collapse'](animate); + return this; + }, + + // private + onDisable : function(){ + if(this.rendered && this.maskDisabled){ + this.el.mask(); + } + Ext.Panel.superclass.onDisable.call(this); + }, + + // private + onEnable : function(){ + if(this.rendered && this.maskDisabled){ + this.el.unmask(); + } + Ext.Panel.superclass.onEnable.call(this); + }, + + // private + onResize : function(w, h){ + if(Ext.isDefined(w) || Ext.isDefined(h)){ + if(!this.collapsed){ + // First, set the the Panel's body width. + // If we have auto-widthed it, get the resulting full offset width so we can size the Toolbars to match + // The Toolbars must not buffer this resize operation because we need to know their heights. + + if(Ext.isNumber(w)){ + this.body.setWidth(w = this.adjustBodyWidth(w - this.getFrameWidth())); + } else if (w == 'auto') { + w = this.body.setWidth('auto').dom.offsetWidth; + } else { + w = this.body.dom.offsetWidth; + } + + if(this.tbar){ + this.tbar.setWidth(w); + if(this.topToolbar){ + this.topToolbar.setSize(w); + } + } + if(this.bbar){ + this.bbar.setWidth(w); + if(this.bottomToolbar){ + this.bottomToolbar.setSize(w); + // The bbar does not move on resize without this. + if (Ext.isIE) { + this.bbar.setStyle('position', 'static'); + this.bbar.setStyle('position', ''); + } + } + } + if(this.footer){ + this.footer.setWidth(w); + if(this.fbar){ + this.fbar.setSize(Ext.isIE ? (w - this.footer.getFrameWidth('lr')) : 'auto'); + } + } + + // At this point, the Toolbars must be layed out for getFrameHeight to find a result. + if(Ext.isNumber(h)){ + h = Math.max(0, this.adjustBodyHeight(h - this.getFrameHeight())); + this.body.setHeight(h); + }else if(h == 'auto'){ + this.body.setHeight(h); + } + + if(this.disabled && this.el._mask){ + this.el._mask.setSize(this.el.dom.clientWidth, this.el.getHeight()); + } + }else{ + // Adds an event to set the correct height afterExpand. This accounts for the deferHeight flag in panel + this.queuedBodySize = {width: w, height: h}; + if(!this.queuedExpand && this.allowQueuedExpand !== false){ + this.queuedExpand = true; + this.on('expand', function(){ + delete this.queuedExpand; + this.onResize(this.queuedBodySize.width, this.queuedBodySize.height); + }, this, {single:true}); + } + } + this.onBodyResize(w, h); + } + this.syncShadow(); + Ext.Panel.superclass.onResize.call(this); + }, + + // private + onBodyResize: function(w, h){ + this.fireEvent('bodyresize', this, w, h); + }, + + // private + getToolbarHeight: function(){ + var h = 0; + if(this.rendered){ + Ext.each(this.toolbars, function(tb){ + h += tb.getHeight(); + }, this); + } + return h; + }, + + // private + adjustBodyHeight : function(h){ + return h; + }, + + // private + adjustBodyWidth : function(w){ + return w; + }, + + // private + onPosition : function(){ + this.syncShadow(); + }, + + /** + * Returns the width in pixels of the framing elements of this panel (not including the body width). To + * retrieve the body width see {@link #getInnerWidth}. + * @return {Number} The frame width + */ + getFrameWidth : function(){ + var w = this.el.getFrameWidth('lr') + this.bwrap.getFrameWidth('lr'); + + if(this.frame){ + var l = this.bwrap.dom.firstChild; + w += (Ext.fly(l).getFrameWidth('l') + Ext.fly(l.firstChild).getFrameWidth('r')); + w += this.mc.getFrameWidth('lr'); + } + return w; + }, + + /** + * Returns the height in pixels of the framing elements of this panel (including any top and bottom bars and + * header and footer elements, but not including the body height). To retrieve the body height see {@link #getInnerHeight}. + * @return {Number} The frame height + */ + getFrameHeight : function(){ + var h = this.el.getFrameWidth('tb') + this.bwrap.getFrameWidth('tb'); + h += (this.tbar ? this.tbar.getHeight() : 0) + + (this.bbar ? this.bbar.getHeight() : 0); + + if(this.frame){ + h += this.el.dom.firstChild.offsetHeight + this.ft.dom.offsetHeight + this.mc.getFrameWidth('tb'); + }else{ + h += (this.header ? this.header.getHeight() : 0) + + (this.footer ? this.footer.getHeight() : 0); + } + return h; + }, + + /** + * Returns the width in pixels of the body element (not including the width of any framing elements). + * For the frame width see {@link #getFrameWidth}. + * @return {Number} The body width + */ + getInnerWidth : function(){ + return this.getSize().width - this.getFrameWidth(); + }, + + /** + * Returns the height in pixels of the body element (not including the height of any framing elements). + * For the frame height see {@link #getFrameHeight}. + * @return {Number} The body height + */ + getInnerHeight : function(){ + return this.getSize().height - this.getFrameHeight(); + }, + + // private + syncShadow : function(){ + if(this.floating){ + this.el.sync(true); + } + }, + + // private + getLayoutTarget : function(){ + return this.body; + }, + + // private + getContentTarget : function(){ + return this.body; + }, + + /** + *

            Sets the title text for the panel and optionally the {@link #iconCls icon class}.

            + *

            In order to be able to set the title, a header element must have been created + * for the Panel. This is triggered either by configuring the Panel with a non-blank {@link #title}, + * or configuring it with {@link #header}: true.

            + * @param {String} title The title text to set + * @param {String} iconCls (optional) {@link #iconCls iconCls} A user-defined CSS class that provides the icon image for this panel + */ + setTitle : function(title, iconCls){ + this.title = title; + if(this.header && this.headerAsText){ + this.header.child('span').update(title); + } + if(iconCls){ + this.setIconClass(iconCls); + } + this.fireEvent('titlechange', this, title); + return this; + }, + + /** + * Get the {@link Ext.Updater} for this panel. Enables you to perform Ajax updates of this panel's body. + * @return {Ext.Updater} The Updater + */ + getUpdater : function(){ + return this.body.getUpdater(); + }, + + /** + * Loads this content panel immediately with content returned from an XHR call. + * @param {Object/String/Function} config A config object containing any of the following options: +
            
            +panel.load({
            +    url: 'your-url.php',
            +    params: {param1: 'foo', param2: 'bar'}, // or a URL encoded string
            +    callback: yourFunction,
            +    scope: yourObject, // optional scope for the callback
            +    discardUrl: false,
            +    nocache: false,
            +    text: 'Loading...',
            +    timeout: 30,
            +    scripts: false
            +});
            +
            + * The only required property is url. The optional properties nocache, text and scripts + * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their + * associated property on this panel Updater instance. + * @return {Ext.Panel} this + */ + load : function(){ + var um = this.body.getUpdater(); + um.update.apply(um, arguments); + return this; + }, + + // private + beforeDestroy : function(){ + Ext.Panel.superclass.beforeDestroy.call(this); + if(this.header){ + this.header.removeAllListeners(); + } + if(this.tools){ + for(var k in this.tools){ + Ext.destroy(this.tools[k]); + } + } + if(this.toolbars.length > 0){ + Ext.each(this.toolbars, function(tb){ + tb.un('afterlayout', this.syncHeight, this); + tb.un('remove', this.syncHeight, this); + }, this); + } + if(Ext.isArray(this.buttons)){ + while(this.buttons.length) { + Ext.destroy(this.buttons[0]); + } + } + if(this.rendered){ + Ext.destroy( + this.ft, + this.header, + this.footer, + this.toolbars, + this.tbar, + this.bbar, + this.body, + this.mc, + this.bwrap + ); + if (this.fbar) { + Ext.destroy( + this.fbar, + this.fbar.el + ); + } + }else{ + Ext.destroy( + this.topToolbar, + this.bottomToolbar + ); + } + }, + + // private + createClasses : function(){ + this.headerCls = this.baseCls + '-header'; + this.headerTextCls = this.baseCls + '-header-text'; + this.bwrapCls = this.baseCls + '-bwrap'; + this.tbarCls = this.baseCls + '-tbar'; + this.bodyCls = this.baseCls + '-body'; + this.bbarCls = this.baseCls + '-bbar'; + this.footerCls = this.baseCls + '-footer'; + }, + + // private + createGhost : function(cls, useShim, appendTo){ + var el = document.createElement('div'); + el.className = 'x-panel-ghost ' + (cls ? cls : ''); + if(this.header){ + el.appendChild(this.el.dom.firstChild.cloneNode(true)); + } + Ext.fly(el.appendChild(document.createElement('ul'))).setHeight(this.bwrap.getHeight()); + el.style.width = this.el.dom.offsetWidth + 'px';; + if(!appendTo){ + this.container.dom.appendChild(el); + }else{ + Ext.getDom(appendTo).appendChild(el); + } + if(useShim !== false && this.el.useShim !== false){ + var layer = new Ext.Layer({shadow:false, useDisplay:true, constrain:false}, el); + layer.show(); + return layer; + }else{ + return new Ext.Element(el); + } + }, + + // private + doAutoLoad : function(){ + var u = this.body.getUpdater(); + if(this.renderer){ + u.setRenderer(this.renderer); + } + u.update(Ext.isObject(this.autoLoad) ? this.autoLoad : {url: this.autoLoad}); + }, + + /** + * Retrieve a tool by id. + * @param {String} id + * @return {Object} tool + */ + getTool : function(id) { + return this.tools[id]; + } + +/** + * @cfg {String} autoEl @hide + */ +}); +Ext.reg('panel', Ext.Panel); +/** + * @class Ext.Editor + * @extends Ext.Component + * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic. + * @constructor + * Create a new Editor + * @param {Object} config The config object + * @xtype editor + */ +Ext.Editor = function(field, config){ + if(field.field){ + this.field = Ext.create(field.field, 'textfield'); + config = Ext.apply({}, field); // copy so we don't disturb original config + delete config.field; + }else{ + this.field = field; + } + Ext.Editor.superclass.constructor.call(this, config); +}; + +Ext.extend(Ext.Editor, Ext.Component, { + /** + * @cfg {Ext.form.Field} field + * The Field object (or descendant) or config object for field + */ + /** + * @cfg {Boolean} allowBlur + * True to {@link #completeEdit complete the editing process} if in edit mode when the + * field is blurred. Defaults to false. + */ + /** + * @cfg {Boolean/String} autoSize + * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only, + * or "height" to adopt the height only, "none" to always use the field dimensions. (defaults to false) + */ + /** + * @cfg {Boolean} revertInvalid + * True to automatically revert the field value and cancel the edit when the user completes an edit and the field + * validation fails (defaults to true) + */ + /** + * @cfg {Boolean} ignoreNoChange + * True to skip the edit completion process (no save, no events fired) if the user completes an edit and + * the value has not changed (defaults to false). Applies only to string values - edits for other data types + * will never be ignored. + */ + /** + * @cfg {Boolean} hideEl + * False to keep the bound element visible while the editor is displayed (defaults to true) + */ + /** + * @cfg {Mixed} value + * The data value of the underlying field (defaults to "") + */ + value : "", + /** + * @cfg {String} alignment + * The position to align to (see {@link Ext.Element#alignTo} for more details, defaults to "c-c?"). + */ + alignment: "c-c?", + /** + * @cfg {Array} offsets + * The offsets to use when aligning (see {@link Ext.Element#alignTo} for more details. Defaults to [0, 0]. + */ + offsets: [0, 0], + /** + * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop" + * for bottom-right shadow (defaults to "frame") + */ + shadow : "frame", + /** + * @cfg {Boolean} constrain True to constrain the editor to the viewport + */ + constrain : false, + /** + * @cfg {Boolean} swallowKeys Handle the keydown/keypress events so they don't propagate (defaults to true) + */ + swallowKeys : true, + /** + * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed. Defaults to true. + */ + completeOnEnter : true, + /** + * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed. Defaults to true. + */ + cancelOnEsc : true, + /** + * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false) + */ + updateEl : false, + + initComponent : function(){ + Ext.Editor.superclass.initComponent.call(this); + this.addEvents( + /** + * @event beforestartedit + * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning + * false from the handler of this event. + * @param {Editor} this + * @param {Ext.Element} boundEl The underlying element bound to this editor + * @param {Mixed} value The field value being set + */ + "beforestartedit", + /** + * @event startedit + * Fires when this editor is displayed + * @param {Ext.Element} boundEl The underlying element bound to this editor + * @param {Mixed} value The starting field value + */ + "startedit", + /** + * @event beforecomplete + * Fires after a change has been made to the field, but before the change is reflected in the underlying + * field. Saving the change to the field can be canceled by returning false from the handler of this event. + * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this + * event will not fire since no edit actually occurred. + * @param {Editor} this + * @param {Mixed} value The current field value + * @param {Mixed} startValue The original field value + */ + "beforecomplete", + /** + * @event complete + * Fires after editing is complete and any changed value has been written to the underlying field. + * @param {Editor} this + * @param {Mixed} value The current field value + * @param {Mixed} startValue The original field value + */ + "complete", + /** + * @event canceledit + * Fires after editing has been canceled and the editor's value has been reset. + * @param {Editor} this + * @param {Mixed} value The user-entered field value that was discarded + * @param {Mixed} startValue The original field value that was set back into the editor after cancel + */ + "canceledit", + /** + * @event specialkey + * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check + * {@link Ext.EventObject#getKey} to determine which key was pressed. + * @param {Ext.form.Field} this + * @param {Ext.EventObject} e The event object + */ + "specialkey" + ); + }, + + // private + onRender : function(ct, position){ + this.el = new Ext.Layer({ + shadow: this.shadow, + cls: "x-editor", + parentEl : ct, + shim : this.shim, + shadowOffset: this.shadowOffset || 4, + id: this.id, + constrain: this.constrain + }); + if(this.zIndex){ + this.el.setZIndex(this.zIndex); + } + this.el.setStyle("overflow", Ext.isGecko ? "auto" : "hidden"); + if(this.field.msgTarget != 'title'){ + this.field.msgTarget = 'qtip'; + } + this.field.inEditor = true; + this.mon(this.field, { + scope: this, + blur: this.onBlur, + specialkey: this.onSpecialKey + }); + if(this.field.grow){ + this.mon(this.field, "autosize", this.el.sync, this.el, {delay:1}); + } + this.field.render(this.el).show(); + this.field.getEl().dom.name = ''; + if(this.swallowKeys){ + this.field.el.swallowEvent([ + 'keypress', // *** Opera + 'keydown' // *** all other browsers + ]); + } + }, + + // private + onSpecialKey : function(field, e){ + var key = e.getKey(), + complete = this.completeOnEnter && key == e.ENTER, + cancel = this.cancelOnEsc && key == e.ESC; + if(complete || cancel){ + e.stopEvent(); + if(complete){ + this.completeEdit(); + }else{ + this.cancelEdit(); + } + if(field.triggerBlur){ + field.triggerBlur(); + } + } + this.fireEvent('specialkey', field, e); + }, + + /** + * Starts the editing process and shows the editor. + * @param {Mixed} el The element to edit + * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults + * to the innerHTML of el. + */ + startEdit : function(el, value){ + if(this.editing){ + this.completeEdit(); + } + this.boundEl = Ext.get(el); + var v = value !== undefined ? value : this.boundEl.dom.innerHTML; + if(!this.rendered){ + this.render(this.parentEl || document.body); + } + if(this.fireEvent("beforestartedit", this, this.boundEl, v) !== false){ + this.startValue = v; + this.field.reset(); + this.field.setValue(v); + this.realign(true); + this.editing = true; + this.show(); + } + }, + + // private + doAutoSize : function(){ + if(this.autoSize){ + var sz = this.boundEl.getSize(), + fs = this.field.getSize(); + + switch(this.autoSize){ + case "width": + this.setSize(sz.width, fs.height); + break; + case "height": + this.setSize(fs.width, sz.height); + break; + case "none": + this.setSize(fs.width, fs.height); + break; + default: + this.setSize(sz.width, sz.height); + } + } + }, + + /** + * Sets the height and width of this editor. + * @param {Number} width The new width + * @param {Number} height The new height + */ + setSize : function(w, h){ + delete this.field.lastSize; + this.field.setSize(w, h); + if(this.el){ + if(Ext.isGecko2 || Ext.isOpera){ + // prevent layer scrollbars + this.el.setSize(w, h); + } + this.el.sync(); + } + }, + + /** + * Realigns the editor to the bound field based on the current alignment config value. + * @param {Boolean} autoSize (optional) True to size the field to the dimensions of the bound element. + */ + realign : function(autoSize){ + if(autoSize === true){ + this.doAutoSize(); + } + this.el.alignTo(this.boundEl, this.alignment, this.offsets); + }, + + /** + * Ends the editing process, persists the changed value to the underlying field, and hides the editor. + * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false) + */ + completeEdit : function(remainVisible){ + if(!this.editing){ + return; + } + var v = this.getValue(); + if(!this.field.isValid()){ + if(this.revertInvalid !== false){ + this.cancelEdit(remainVisible); + } + return; + } + if(String(v) === String(this.startValue) && this.ignoreNoChange){ + this.hideEdit(remainVisible); + return; + } + if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){ + v = this.getValue(); + if(this.updateEl && this.boundEl){ + this.boundEl.update(v); + } + this.hideEdit(remainVisible); + this.fireEvent("complete", this, v, this.startValue); + } + }, + + // private + onShow : function(){ + this.el.show(); + if(this.hideEl !== false){ + this.boundEl.hide(); + } + this.field.show().focus(false, true); + this.fireEvent("startedit", this.boundEl, this.startValue); + }, + + /** + * Cancels the editing process and hides the editor without persisting any changes. The field value will be + * reverted to the original starting value. + * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after + * cancel (defaults to false) + */ + cancelEdit : function(remainVisible){ + if(this.editing){ + var v = this.getValue(); + this.setValue(this.startValue); + this.hideEdit(remainVisible); + this.fireEvent("canceledit", this, v, this.startValue); + } + }, + + // private + hideEdit: function(remainVisible){ + if(remainVisible !== true){ + this.editing = false; + this.hide(); + } + }, + + // private + onBlur : function(){ + // selectSameEditor flag allows the same editor to be started without onBlur firing on itself + if(this.allowBlur !== true && this.editing && this.selectSameEditor !== true){ + this.completeEdit(); + } + }, + + // private + onHide : function(){ + if(this.editing){ + this.completeEdit(); + return; + } + this.field.blur(); + if(this.field.collapse){ + this.field.collapse(); + } + this.el.hide(); + if(this.hideEl !== false){ + this.boundEl.show(); + } + }, + + /** + * Sets the data value of the editor + * @param {Mixed} value Any valid value supported by the underlying field + */ + setValue : function(v){ + this.field.setValue(v); + }, + + /** + * Gets the data value of the editor + * @return {Mixed} The data value + */ + getValue : function(){ + return this.field.getValue(); + }, + + beforeDestroy : function(){ + Ext.destroyMembers(this, 'field'); + + delete this.parentEl; + delete this.boundEl; + } +}); +Ext.reg('editor', Ext.Editor); +/** + * @class Ext.ColorPalette + * @extends Ext.Component + * Simple color palette class for choosing colors. The palette can be rendered to any container.
            + * Here's an example of typical usage: + *
            
            +var cp = new Ext.ColorPalette({value:'993300'});  // initial selected color
            +cp.render('my-div');
            +
            +cp.on('select', function(palette, selColor){
            +    // do something with selColor
            +});
            +
            + * @constructor + * Create a new ColorPalette + * @param {Object} config The config object + * @xtype colorpalette + */ +Ext.ColorPalette = Ext.extend(Ext.Component, { + /** + * @cfg {String} tpl An existing XTemplate instance to be used in place of the default template for rendering the component. + */ + /** + * @cfg {String} itemCls + * The CSS class to apply to the containing element (defaults to 'x-color-palette') + */ + itemCls : 'x-color-palette', + /** + * @cfg {String} value + * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that + * the hex codes are case-sensitive. + */ + value : null, + /** + * @cfg {String} clickEvent + * The DOM event that will cause a color to be selected. This can be any valid event name (dblclick, contextmenu). + * Defaults to 'click'. + */ + clickEvent :'click', + // private + ctype : 'Ext.ColorPalette', + + /** + * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the {@link #select} event + */ + allowReselect : false, + + /** + *

            An array of 6-digit color hex code strings (without the # symbol). This array can contain any number + * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting + * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number + * of colors with the width setting until the box is symmetrical.

            + *

            You can override individual colors if needed:

            + *
            
            +var cp = new Ext.ColorPalette();
            +cp.colors[0] = 'FF0000';  // change the first box to red
            +
            + +Or you can provide a custom array of your own for complete control: +
            
            +var cp = new Ext.ColorPalette();
            +cp.colors = ['000000', '993300', '333300'];
            +
            + * @type Array + */ + colors : [ + '000000', '993300', '333300', '003300', '003366', '000080', '333399', '333333', + '800000', 'FF6600', '808000', '008000', '008080', '0000FF', '666699', '808080', + 'FF0000', 'FF9900', '99CC00', '339966', '33CCCC', '3366FF', '800080', '969696', + 'FF00FF', 'FFCC00', 'FFFF00', '00FF00', '00FFFF', '00CCFF', '993366', 'C0C0C0', + 'FF99CC', 'FFCC99', 'FFFF99', 'CCFFCC', 'CCFFFF', '99CCFF', 'CC99FF', 'FFFFFF' + ], + + /** + * @cfg {Function} handler + * Optional. A function that will handle the select event of this palette. + * The handler is passed the following parameters:
              + *
            • palette : ColorPalette
              The {@link #palette Ext.ColorPalette}.
            • + *
            • color : String
              The 6-digit color hex code (without the # symbol).
            • + *
            + */ + /** + * @cfg {Object} scope + * The scope (this reference) in which the {@link #handler} + * function will be called. Defaults to this ColorPalette instance. + */ + + // private + initComponent : function(){ + Ext.ColorPalette.superclass.initComponent.call(this); + this.addEvents( + /** + * @event select + * Fires when a color is selected + * @param {ColorPalette} this + * @param {String} color The 6-digit color hex code (without the # symbol) + */ + 'select' + ); + + if(this.handler){ + this.on('select', this.handler, this.scope, true); + } + }, + + // private + onRender : function(container, position){ + this.autoEl = { + tag: 'div', + cls: this.itemCls + }; + Ext.ColorPalette.superclass.onRender.call(this, container, position); + var t = this.tpl || new Ext.XTemplate( + ' ' + ); + t.overwrite(this.el, this.colors); + this.mon(this.el, this.clickEvent, this.handleClick, this, {delegate: 'a'}); + if(this.clickEvent != 'click'){ + this.mon(this.el, 'click', Ext.emptyFn, this, {delegate: 'a', preventDefault: true}); + } + }, + + // private + afterRender : function(){ + Ext.ColorPalette.superclass.afterRender.call(this); + if(this.value){ + var s = this.value; + this.value = null; + this.select(s); + } + }, + + // private + handleClick : function(e, t){ + e.preventDefault(); + if(!this.disabled){ + var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1]; + this.select(c.toUpperCase()); + } + }, + + /** + * Selects the specified color in the palette (fires the {@link #select} event) + * @param {String} color A valid 6-digit color hex code (# will be stripped if included) + */ + select : function(color){ + color = color.replace('#', ''); + if(color != this.value || this.allowReselect){ + var el = this.el; + if(this.value){ + el.child('a.color-'+this.value).removeClass('x-color-palette-sel'); + } + el.child('a.color-'+color).addClass('x-color-palette-sel'); + this.value = color; + this.fireEvent('select', this, color); + } + } + + /** + * @cfg {String} autoEl @hide + */ +}); +Ext.reg('colorpalette', Ext.ColorPalette); +/** + * @class Ext.DatePicker + * @extends Ext.Component + *

            A popup date picker. This class is used by the {@link Ext.form.DateField DateField} class + * to allow browsing and selection of valid dates.

            + *

            All the string values documented below may be overridden by including an Ext locale file in + * your page.

            + * @constructor + * Create a new DatePicker + * @param {Object} config The config object + * @xtype datepicker + */ +Ext.DatePicker = Ext.extend(Ext.BoxComponent, { + /** + * @cfg {String} todayText + * The text to display on the button that selects the current date (defaults to 'Today') + */ + todayText : 'Today', + /** + * @cfg {String} okText + * The text to display on the ok button (defaults to ' OK ' to give the user extra clicking room) + */ + okText : ' OK ', + /** + * @cfg {String} cancelText + * The text to display on the cancel button (defaults to 'Cancel') + */ + cancelText : 'Cancel', + /** + * @cfg {Function} handler + * Optional. A function that will handle the select event of this picker. + * The handler is passed the following parameters:
              + *
            • picker : DatePicker
              This DatePicker.
            • + *
            • date : Date
              The selected date.
            • + *
            + */ + /** + * @cfg {Object} scope + * The scope (this reference) in which the {@link #handler} + * function will be called. Defaults to this DatePicker instance. + */ + /** + * @cfg {String} todayTip + * A string used to format the message for displaying in a tooltip over the button that + * selects the current date. Defaults to '{0} (Spacebar)' where + * the {0} token is replaced by today's date. + */ + todayTip : '{0} (Spacebar)', + /** + * @cfg {String} minText + * The error text to display if the minDate validation fails (defaults to 'This date is before the minimum date') + */ + minText : 'This date is before the minimum date', + /** + * @cfg {String} maxText + * The error text to display if the maxDate validation fails (defaults to 'This date is after the maximum date') + */ + maxText : 'This date is after the maximum date', + /** + * @cfg {String} format + * The default date format string which can be overriden for localization support. The format must be + * valid according to {@link Date#parseDate} (defaults to 'm/d/y'). + */ + format : 'm/d/y', + /** + * @cfg {String} disabledDaysText + * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled') + */ + disabledDaysText : 'Disabled', + /** + * @cfg {String} disabledDatesText + * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled') + */ + disabledDatesText : 'Disabled', + /** + * @cfg {Array} monthNames + * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames) + */ + monthNames : Date.monthNames, + /** + * @cfg {Array} dayNames + * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames) + */ + dayNames : Date.dayNames, + /** + * @cfg {String} nextText + * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)') + */ + nextText : 'Next Month (Control+Right)', + /** + * @cfg {String} prevText + * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)') + */ + prevText : 'Previous Month (Control+Left)', + /** + * @cfg {String} monthYearText + * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)') + */ + monthYearText : 'Choose a month (Control+Up/Down to move years)', + /** + * @cfg {Number} startDay + * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday) + */ + startDay : 0, + /** + * @cfg {Boolean} showToday + * False to hide the footer area containing the Today button and disable the keyboard handler for spacebar + * that selects the current date (defaults to true). + */ + showToday : true, + /** + * @cfg {Date} minDate + * Minimum allowable date (JavaScript date object, defaults to null) + */ + /** + * @cfg {Date} maxDate + * Maximum allowable date (JavaScript date object, defaults to null) + */ + /** + * @cfg {Array} disabledDays + * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null). + */ + /** + * @cfg {RegExp} disabledDatesRE + * JavaScript regular expression used to disable a pattern of dates (defaults to null). The {@link #disabledDates} + * config will generate this regex internally, but if you specify disabledDatesRE it will take precedence over the + * disabledDates value. + */ + /** + * @cfg {Array} disabledDates + * An array of 'dates' to disable, as strings. These strings will be used to build a dynamic regular + * expression so they are very powerful. Some examples: + *
              + *
            • ['03/08/2003', '09/16/2003'] would disable those exact dates
            • + *
            • ['03/08', '09/16'] would disable those days for every year
            • + *
            • ['^03/08'] would only match the beginning (useful if you are using short years)
            • + *
            • ['03/../2006'] would disable every day in March 2006
            • + *
            • ['^03'] would disable every day in every March
            • + *
            + * Note that the format of the dates included in the array should exactly match the {@link #format} config. + * In order to support regular expressions, if you are using a date format that has '.' in it, you will have to + * escape the dot when restricting dates. For example: ['03\\.08\\.03']. + */ + + // private + // Set by other components to stop the picker focus being updated when the value changes. + focusOnSelect: true, + + // private + initComponent : function(){ + Ext.DatePicker.superclass.initComponent.call(this); + + this.value = this.value ? + this.value.clearTime(true) : new Date().clearTime(); + + this.addEvents( + /** + * @event select + * Fires when a date is selected + * @param {DatePicker} this DatePicker + * @param {Date} date The selected date + */ + 'select' + ); + + if(this.handler){ + this.on('select', this.handler, this.scope || this); + } + + this.initDisabledDays(); + }, + + // private + initDisabledDays : function(){ + if(!this.disabledDatesRE && this.disabledDates){ + var dd = this.disabledDates, + len = dd.length - 1, + re = '(?:'; + + Ext.each(dd, function(d, i){ + re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i]; + if(i != len){ + re += '|'; + } + }, this); + this.disabledDatesRE = new RegExp(re + ')'); + } + }, + + /** + * Replaces any existing disabled dates with new values and refreshes the DatePicker. + * @param {Array/RegExp} disabledDates An array of date strings (see the {@link #disabledDates} config + * for details on supported values), or a JavaScript regular expression used to disable a pattern of dates. + */ + setDisabledDates : function(dd){ + if(Ext.isArray(dd)){ + this.disabledDates = dd; + this.disabledDatesRE = null; + }else{ + this.disabledDatesRE = dd; + } + this.initDisabledDays(); + this.update(this.value, true); + }, + + /** + * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker. + * @param {Array} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config + * for details on supported values. + */ + setDisabledDays : function(dd){ + this.disabledDays = dd; + this.update(this.value, true); + }, + + /** + * Replaces any existing {@link #minDate} with the new value and refreshes the DatePicker. + * @param {Date} value The minimum date that can be selected + */ + setMinDate : function(dt){ + this.minDate = dt; + this.update(this.value, true); + }, + + /** + * Replaces any existing {@link #maxDate} with the new value and refreshes the DatePicker. + * @param {Date} value The maximum date that can be selected + */ + setMaxDate : function(dt){ + this.maxDate = dt; + this.update(this.value, true); + }, + + /** + * Sets the value of the date field + * @param {Date} value The date to set + */ + setValue : function(value){ + this.value = value.clearTime(true); + this.update(this.value); + }, + + /** + * Gets the current selected value of the date field + * @return {Date} The selected date + */ + getValue : function(){ + return this.value; + }, + + // private + focus : function(){ + this.update(this.activeDate); + }, + + // private + onEnable: function(initial){ + Ext.DatePicker.superclass.onEnable.call(this); + this.doDisabled(false); + this.update(initial ? this.value : this.activeDate); + if(Ext.isIE){ + this.el.repaint(); + } + + }, + + // private + onDisable : function(){ + Ext.DatePicker.superclass.onDisable.call(this); + this.doDisabled(true); + if(Ext.isIE && !Ext.isIE8){ + /* Really strange problem in IE6/7, when disabled, have to explicitly + * repaint each of the nodes to get them to display correctly, simply + * calling repaint on the main element doesn't appear to be enough. + */ + Ext.each([].concat(this.textNodes, this.el.query('th span')), function(el){ + Ext.fly(el).repaint(); + }); + } + }, + + // private + doDisabled : function(disabled){ + this.keyNav.setDisabled(disabled); + this.prevRepeater.setDisabled(disabled); + this.nextRepeater.setDisabled(disabled); + if(this.showToday){ + this.todayKeyListener.setDisabled(disabled); + this.todayBtn.setDisabled(disabled); + } + }, + + // private + onRender : function(container, position){ + var m = [ + '', + '', + '', + this.showToday ? '' : '', + '
              
            '], + dn = this.dayNames, + i; + for(i = 0; i < 7; i++){ + var d = this.startDay+i; + if(d > 6){ + d = d-7; + } + m.push(''); + } + m[m.length] = ''; + for(i = 0; i < 42; i++) { + if(i % 7 === 0 && i !== 0){ + m[m.length] = ''; + } + m[m.length] = ''; + } + m.push('
            ', dn[d].substr(0,1), '
            '); + + var el = document.createElement('div'); + el.className = 'x-date-picker'; + el.innerHTML = m.join(''); + + container.dom.insertBefore(el, position); + + this.el = Ext.get(el); + this.eventEl = Ext.get(el.firstChild); + + this.prevRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-left a'), { + handler: this.showPrevMonth, + scope: this, + preventDefault:true, + stopDefault:true + }); + + this.nextRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-right a'), { + handler: this.showNextMonth, + scope: this, + preventDefault:true, + stopDefault:true + }); + + this.monthPicker = this.el.down('div.x-date-mp'); + this.monthPicker.enableDisplayMode('block'); + + this.keyNav = new Ext.KeyNav(this.eventEl, { + 'left' : function(e){ + if(e.ctrlKey){ + this.showPrevMonth(); + }else{ + this.update(this.activeDate.add('d', -1)); + } + }, + + 'right' : function(e){ + if(e.ctrlKey){ + this.showNextMonth(); + }else{ + this.update(this.activeDate.add('d', 1)); + } + }, + + 'up' : function(e){ + if(e.ctrlKey){ + this.showNextYear(); + }else{ + this.update(this.activeDate.add('d', -7)); + } + }, + + 'down' : function(e){ + if(e.ctrlKey){ + this.showPrevYear(); + }else{ + this.update(this.activeDate.add('d', 7)); + } + }, + + 'pageUp' : function(e){ + this.showNextMonth(); + }, + + 'pageDown' : function(e){ + this.showPrevMonth(); + }, + + 'enter' : function(e){ + e.stopPropagation(); + return true; + }, + + scope : this + }); + + this.el.unselectable(); + + this.cells = this.el.select('table.x-date-inner tbody td'); + this.textNodes = this.el.query('table.x-date-inner tbody span'); + + this.mbtn = new Ext.Button({ + text: ' ', + tooltip: this.monthYearText, + renderTo: this.el.child('td.x-date-middle', true) + }); + this.mbtn.el.child('em').addClass('x-btn-arrow'); + + if(this.showToday){ + this.todayKeyListener = this.eventEl.addKeyListener(Ext.EventObject.SPACE, this.selectToday, this); + var today = (new Date()).dateFormat(this.format); + this.todayBtn = new Ext.Button({ + renderTo: this.el.child('td.x-date-bottom', true), + text: String.format(this.todayText, today), + tooltip: String.format(this.todayTip, today), + handler: this.selectToday, + scope: this + }); + } + this.mon(this.eventEl, 'mousewheel', this.handleMouseWheel, this); + this.mon(this.eventEl, 'click', this.handleDateClick, this, {delegate: 'a.x-date-date'}); + this.mon(this.mbtn, 'click', this.showMonthPicker, this); + this.onEnable(true); + }, + + // private + createMonthPicker : function(){ + if(!this.monthPicker.dom.firstChild){ + var buf = ['']; + for(var i = 0; i < 6; i++){ + buf.push( + '', + '', + i === 0 ? + '' : + '' + ); + } + buf.push( + '', + '
            ', Date.getShortMonthName(i), '', Date.getShortMonthName(i + 6), '
            ' + ); + this.monthPicker.update(buf.join('')); + + this.mon(this.monthPicker, 'click', this.onMonthClick, this); + this.mon(this.monthPicker, 'dblclick', this.onMonthDblClick, this); + + this.mpMonths = this.monthPicker.select('td.x-date-mp-month'); + this.mpYears = this.monthPicker.select('td.x-date-mp-year'); + + this.mpMonths.each(function(m, a, i){ + i += 1; + if((i%2) === 0){ + m.dom.xmonth = 5 + Math.round(i * 0.5); + }else{ + m.dom.xmonth = Math.round((i-1) * 0.5); + } + }); + } + }, + + // private + showMonthPicker : function(){ + if(!this.disabled){ + this.createMonthPicker(); + var size = this.el.getSize(); + this.monthPicker.setSize(size); + this.monthPicker.child('table').setSize(size); + + this.mpSelMonth = (this.activeDate || this.value).getMonth(); + this.updateMPMonth(this.mpSelMonth); + this.mpSelYear = (this.activeDate || this.value).getFullYear(); + this.updateMPYear(this.mpSelYear); + + this.monthPicker.slideIn('t', {duration:0.2}); + } + }, + + // private + updateMPYear : function(y){ + this.mpyear = y; + var ys = this.mpYears.elements; + for(var i = 1; i <= 10; i++){ + var td = ys[i-1], y2; + if((i%2) === 0){ + y2 = y + Math.round(i * 0.5); + td.firstChild.innerHTML = y2; + td.xyear = y2; + }else{ + y2 = y - (5-Math.round(i * 0.5)); + td.firstChild.innerHTML = y2; + td.xyear = y2; + } + this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel'); + } + }, + + // private + updateMPMonth : function(sm){ + this.mpMonths.each(function(m, a, i){ + m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel'); + }); + }, + + // private + selectMPMonth : function(m){ + + }, + + // private + onMonthClick : function(e, t){ + e.stopEvent(); + var el = new Ext.Element(t), pn; + if(el.is('button.x-date-mp-cancel')){ + this.hideMonthPicker(); + } + else if(el.is('button.x-date-mp-ok')){ + var d = new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()); + if(d.getMonth() != this.mpSelMonth){ + // 'fix' the JS rolling date conversion if needed + d = new Date(this.mpSelYear, this.mpSelMonth, 1).getLastDateOfMonth(); + } + this.update(d); + this.hideMonthPicker(); + } + else if((pn = el.up('td.x-date-mp-month', 2))){ + this.mpMonths.removeClass('x-date-mp-sel'); + pn.addClass('x-date-mp-sel'); + this.mpSelMonth = pn.dom.xmonth; + } + else if((pn = el.up('td.x-date-mp-year', 2))){ + this.mpYears.removeClass('x-date-mp-sel'); + pn.addClass('x-date-mp-sel'); + this.mpSelYear = pn.dom.xyear; + } + else if(el.is('a.x-date-mp-prev')){ + this.updateMPYear(this.mpyear-10); + } + else if(el.is('a.x-date-mp-next')){ + this.updateMPYear(this.mpyear+10); + } + }, + + // private + onMonthDblClick : function(e, t){ + e.stopEvent(); + var el = new Ext.Element(t), pn; + if((pn = el.up('td.x-date-mp-month', 2))){ + this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate())); + this.hideMonthPicker(); + } + else if((pn = el.up('td.x-date-mp-year', 2))){ + this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate())); + this.hideMonthPicker(); + } + }, + + // private + hideMonthPicker : function(disableAnim){ + if(this.monthPicker){ + if(disableAnim === true){ + this.monthPicker.hide(); + }else{ + this.monthPicker.slideOut('t', {duration:0.2}); + } + } + }, + + // private + showPrevMonth : function(e){ + this.update(this.activeDate.add('mo', -1)); + }, + + // private + showNextMonth : function(e){ + this.update(this.activeDate.add('mo', 1)); + }, + + // private + showPrevYear : function(){ + this.update(this.activeDate.add('y', -1)); + }, + + // private + showNextYear : function(){ + this.update(this.activeDate.add('y', 1)); + }, + + // private + handleMouseWheel : function(e){ + e.stopEvent(); + if(!this.disabled){ + var delta = e.getWheelDelta(); + if(delta > 0){ + this.showPrevMonth(); + } else if(delta < 0){ + this.showNextMonth(); + } + } + }, + + // private + handleDateClick : function(e, t){ + e.stopEvent(); + if(!this.disabled && t.dateValue && !Ext.fly(t.parentNode).hasClass('x-date-disabled')){ + this.cancelFocus = this.focusOnSelect === false; + this.setValue(new Date(t.dateValue)); + delete this.cancelFocus; + this.fireEvent('select', this, this.value); + } + }, + + // private + selectToday : function(){ + if(this.todayBtn && !this.todayBtn.disabled){ + this.setValue(new Date().clearTime()); + this.fireEvent('select', this, this.value); + } + }, + + // private + update : function(date, forceRefresh){ + if(this.rendered){ + var vd = this.activeDate, vis = this.isVisible(); + this.activeDate = date; + if(!forceRefresh && vd && this.el){ + var t = date.getTime(); + if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){ + this.cells.removeClass('x-date-selected'); + this.cells.each(function(c){ + if(c.dom.firstChild.dateValue == t){ + c.addClass('x-date-selected'); + if(vis && !this.cancelFocus){ + Ext.fly(c.dom.firstChild).focus(50); + } + return false; + } + }, this); + return; + } + } + var days = date.getDaysInMonth(), + firstOfMonth = date.getFirstDateOfMonth(), + startingPos = firstOfMonth.getDay()-this.startDay; + + if(startingPos < 0){ + startingPos += 7; + } + days += startingPos; + + var pm = date.add('mo', -1), + prevStart = pm.getDaysInMonth()-startingPos, + cells = this.cells.elements, + textEls = this.textNodes, + // convert everything to numbers so it's fast + day = 86400000, + d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime(), + today = new Date().clearTime().getTime(), + sel = date.clearTime(true).getTime(), + min = this.minDate ? this.minDate.clearTime(true) : Number.NEGATIVE_INFINITY, + max = this.maxDate ? this.maxDate.clearTime(true) : Number.POSITIVE_INFINITY, + ddMatch = this.disabledDatesRE, + ddText = this.disabledDatesText, + ddays = this.disabledDays ? this.disabledDays.join('') : false, + ddaysText = this.disabledDaysText, + format = this.format; + + if(this.showToday){ + var td = new Date().clearTime(), + disable = (td < min || td > max || + (ddMatch && format && ddMatch.test(td.dateFormat(format))) || + (ddays && ddays.indexOf(td.getDay()) != -1)); + + if(!this.disabled){ + this.todayBtn.setDisabled(disable); + this.todayKeyListener[disable ? 'disable' : 'enable'](); + } + } + + var setCellClass = function(cal, cell){ + cell.title = ''; + var t = d.getTime(); + cell.firstChild.dateValue = t; + if(t == today){ + cell.className += ' x-date-today'; + cell.title = cal.todayText; + } + if(t == sel){ + cell.className += ' x-date-selected'; + if(vis){ + Ext.fly(cell.firstChild).focus(50); + } + } + // disabling + if(t < min) { + cell.className = ' x-date-disabled'; + cell.title = cal.minText; + return; + } + if(t > max) { + cell.className = ' x-date-disabled'; + cell.title = cal.maxText; + return; + } + if(ddays){ + if(ddays.indexOf(d.getDay()) != -1){ + cell.title = ddaysText; + cell.className = ' x-date-disabled'; + } + } + if(ddMatch && format){ + var fvalue = d.dateFormat(format); + if(ddMatch.test(fvalue)){ + cell.title = ddText.replace('%0', fvalue); + cell.className = ' x-date-disabled'; + } + } + }; + + var i = 0; + for(; i < startingPos; i++) { + textEls[i].innerHTML = (++prevStart); + d.setDate(d.getDate()+1); + cells[i].className = 'x-date-prevday'; + setCellClass(this, cells[i]); + } + for(; i < days; i++){ + var intDay = i - startingPos + 1; + textEls[i].innerHTML = (intDay); + d.setDate(d.getDate()+1); + cells[i].className = 'x-date-active'; + setCellClass(this, cells[i]); + } + var extraDays = 0; + for(; i < 42; i++) { + textEls[i].innerHTML = (++extraDays); + d.setDate(d.getDate()+1); + cells[i].className = 'x-date-nextday'; + setCellClass(this, cells[i]); + } + + this.mbtn.setText(this.monthNames[date.getMonth()] + ' ' + date.getFullYear()); + + if(!this.internalRender){ + var main = this.el.dom.firstChild, + w = main.offsetWidth; + this.el.setWidth(w + this.el.getBorderWidth('lr')); + Ext.fly(main).setWidth(w); + this.internalRender = true; + // opera does not respect the auto grow header center column + // then, after it gets a width opera refuses to recalculate + // without a second pass + if(Ext.isOpera && !this.secondPass){ + main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + 'px'; + this.secondPass = true; + this.update.defer(10, this, [date]); + } + } + } + }, + + // private + beforeDestroy : function() { + if(this.rendered){ + Ext.destroy( + this.keyNav, + this.monthPicker, + this.eventEl, + this.mbtn, + this.nextRepeater, + this.prevRepeater, + this.cells.el, + this.todayBtn + ); + delete this.textNodes; + delete this.cells.elements; + } + } + + /** + * @cfg {String} autoEl @hide + */ +}); + +Ext.reg('datepicker', Ext.DatePicker); /** * @class Ext.LoadMask * A simple utility class for generically masking elements while loading data. If the {@link #store} @@ -10488,16 +11707,22 @@ Ext.LoadMask = function(el, config){ this.el = Ext.get(el); Ext.apply(this, config); if(this.store){ - this.store.on('beforeload', this.onBeforeLoad, this); - this.store.on('load', this.onLoad, this); - this.store.on('exception', this.onLoad, this); + this.store.on({ + scope: this, + beforeload: this.onBeforeLoad, + load: this.onLoad, + exception: this.onLoad + }); this.removeMask = Ext.value(this.removeMask, false); }else{ var um = this.el.getUpdater(); um.showLoadIndicator = false; // disable the default indicator - um.on('beforeupdate', this.onBeforeLoad, this); - um.on('update', this.onLoad, this); - um.on('failure', this.onLoad, this); + um.on({ + scope: this, + beforeupdate: this.onBeforeLoad, + update: this.onLoad, + failure: this.onLoad + }); this.removeMask = Ext.value(this.removeMask, true); } }; @@ -10601,20 +11826,20 @@ new Ext.Slider({
    */ Ext.Slider = Ext.extend(Ext.BoxComponent, { - /** - * @cfg {Number} value The value to initialize the slider with. Defaults to minValue. - */ - /** - * @cfg {Boolean} vertical Orient the Slider vertically rather than horizontally, defaults to false. - */ + /** + * @cfg {Number} value The value to initialize the slider with. Defaults to minValue. + */ + /** + * @cfg {Boolean} vertical Orient the Slider vertically rather than horizontally, defaults to false. + */ vertical: false, - /** - * @cfg {Number} minValue The minimum value for the Slider. Defaults to 0. - */ + /** + * @cfg {Number} minValue The minimum value for the Slider. Defaults to 0. + */ minValue: 0, - /** - * @cfg {Number} maxValue The maximum value for the Slider. Defaults to 100. - */ + /** + * @cfg {Number} maxValue The maximum value for the Slider. Defaults to 100. + */ maxValue: 100, /** * @cfg {Number/Boolean} decimalPrecision. @@ -10622,23 +11847,23 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, { *

    To disable rounding, configure as false.

    */ decimalPrecision: 0, - /** - * @cfg {Number} keyIncrement How many units to change the Slider when adjusting with keyboard navigation. Defaults to 1. If the increment config is larger, it will be used instead. - */ + /** + * @cfg {Number} keyIncrement How many units to change the Slider when adjusting with keyboard navigation. Defaults to 1. If the increment config is larger, it will be used instead. + */ keyIncrement: 1, - /** - * @cfg {Number} increment How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'. - */ + /** + * @cfg {Number} increment How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'. + */ increment: 0, - // private + // private clickRange: [5,15], - /** - * @cfg {Boolean} clickToChange Determines whether or not clicking on the Slider axis will change the slider. Defaults to true - */ + /** + * @cfg {Boolean} clickToChange Determines whether or not clicking on the Slider axis will change the slider. Defaults to true + */ clickToChange : true, - /** - * @cfg {Boolean} animate Turn on or off animation. Defaults to true - */ + /** + * @cfg {Boolean} animate Turn on or off animation. Defaults to true + */ animate: true, /** @@ -10659,54 +11884,54 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, { * @event beforechange * Fires before the slider value is changed. By returning false from an event handler, * you can cancel the event and prevent the slider from changing. - * @param {Ext.Slider} slider The slider - * @param {Number} newValue The new value which the slider is being changed to. - * @param {Number} oldValue The old value which the slider was previously. + * @param {Ext.Slider} slider The slider + * @param {Number} newValue The new value which the slider is being changed to. + * @param {Number} oldValue The old value which the slider was previously. + */ + 'beforechange', + /** + * @event change + * Fires when the slider value is changed. + * @param {Ext.Slider} slider The slider + * @param {Number} newValue The new value which the slider has been changed to. + */ + 'change', + /** + * @event changecomplete + * Fires when the slider value is changed by the user and any drag operations have completed. + * @param {Ext.Slider} slider The slider + * @param {Number} newValue The new value which the slider has been changed to. */ - 'beforechange', - /** - * @event change - * Fires when the slider value is changed. - * @param {Ext.Slider} slider The slider - * @param {Number} newValue The new value which the slider has been changed to. - */ - 'change', - /** - * @event changecomplete - * Fires when the slider value is changed by the user and any drag operations have completed. - * @param {Ext.Slider} slider The slider - * @param {Number} newValue The new value which the slider has been changed to. - */ - 'changecomplete', - /** - * @event dragstart + 'changecomplete', + /** + * @event dragstart * Fires after a drag operation has started. - * @param {Ext.Slider} slider The slider - * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker - */ - 'dragstart', - /** - * @event drag + * @param {Ext.Slider} slider The slider + * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker + */ + 'dragstart', + /** + * @event drag * Fires continuously during the drag operation while the mouse is moving. - * @param {Ext.Slider} slider The slider - * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker - */ - 'drag', - /** - * @event dragend + * @param {Ext.Slider} slider The slider + * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker + */ + 'drag', + /** + * @event dragend * Fires after the drag operation has completed. - * @param {Ext.Slider} slider The slider - * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker - */ - 'dragend' - ); + * @param {Ext.Slider} slider The slider + * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker + */ + 'dragend' + ); if(this.vertical){ Ext.apply(this, Ext.Slider.Vertical); } }, - // private override + // private override onRender : function(){ this.autoEl = { cls: 'x-slider ' + (this.vertical ? 'x-slider-vert' : 'x-slider-horz'), @@ -10721,7 +11946,7 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, { this.initEvents(); }, - // private override + // private override initEvents : function(){ this.thumb.addClassOnOver('x-slider-thumb-over'); this.mon(this.el, { @@ -10741,12 +11966,13 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, { autoStart: 300 }); this.tracker.initEl(this.thumb); - this.on('beforedestroy', this.tracker.destroy, this.tracker); }, - // private override + // private override onMouseDown : function(e){ - if(this.disabled) {return;} + if(this.disabled){ + return; + } if(this.clickToChange && e.target != this.thumb.dom){ var local = this.innerEl.translatePoints(e.getXY()); this.onClickChange(local); @@ -10754,14 +11980,14 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, { this.focus(); }, - // private + // private onClickChange : function(local){ if(local.top > this.clickRange[0] && local.top < this.clickRange[1]){ this.setValue(Ext.util.Format.round(this.reverseValue(local.left), this.decimalPrecision), undefined, true); } }, - // private + // private onKeyDown : function(e){ if(this.disabled){e.preventDefault();return;} var k = e.getKey(); @@ -10789,13 +12015,14 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, { } }, - // private + // private doSnap : function(value){ - if(!this.increment || this.increment == 1 || !value) { + if(!(this.increment && value)){ return value; } - var newValue = value, inc = this.increment; - var m = value % inc; + var newValue = value, + inc = this.increment, + m = value % inc; if(m != 0){ newValue -= m; if(m * 2 > inc){ @@ -10807,7 +12034,7 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, { return newValue.constrain(this.minValue, this.maxValue); }, - // private + // private afterRender : function(){ Ext.Slider.superclass.afterRender.apply(this, arguments); if(this.value !== undefined){ @@ -10821,27 +12048,53 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, { } }, - // private + // private getRatio : function(){ - var w = this.innerEl.getWidth(); - var v = this.maxValue - this.minValue; + var w = this.innerEl.getWidth(), + v = this.maxValue - this.minValue; return v == 0 ? w : (w/v); }, - // private + // private normalizeValue : function(v){ v = this.doSnap(v); v = Ext.util.Format.round(v, this.decimalPrecision); v = v.constrain(this.minValue, this.maxValue); return v; }, + + /** + * Sets the minimum value for the slider instance. If the current value is less than the + * minimum value, the current value will be changed. + * @param {Number} val The new minimum value + */ + setMinValue : function(val){ + this.minValue = val; + this.syncThumb(); + if(this.value < val){ + this.setValue(val); + } + }, + + /** + * Sets the maximum value for the slider instance. If the current value is more than the + * maximum value, the current value will be changed. + * @param {Number} val The new maximum value + */ + setMaxValue : function(val){ + this.maxValue = val; + this.syncThumb(); + if(this.value > val){ + this.setValue(val); + } + }, - /** - * Programmatically sets the value of the Slider. Ensures that the value is constrained within - * the minValue and maxValue. - * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue) - * @param {Boolean} animate Turn on or off animation, defaults to true - */ + /** + * Programmatically sets the value of the Slider. Ensures that the value is constrained within + * the minValue and maxValue. + * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue) + * @param {Boolean} animate Turn on or off animation, defaults to true + */ setValue : function(v, animate, changeComplete){ v = this.normalizeValue(v); if(v !== this.value && this.fireEvent('beforechange', this, v, this.value) !== false){ @@ -10854,18 +12107,18 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, { } }, - // private + // private translateValue : function(v){ var ratio = this.getRatio(); - return (v * ratio)-(this.minValue * ratio)-this.halfThumb; + return (v * ratio) - (this.minValue * ratio) - this.halfThumb; }, - reverseValue : function(pos){ + reverseValue : function(pos){ var ratio = this.getRatio(); - return (pos+this.halfThumb+(this.minValue * ratio))/ratio; + return (pos + (this.minValue * ratio)) / ratio; }, - // private + // private moveThumb: function(v, animate){ if(!animate || this.animate === false){ this.thumb.setLeft(v); @@ -10874,17 +12127,17 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, { } }, - // private + // private focus : function(){ this.focusEl.focus(10); }, - // private + // private onBeforeDragStart : function(e){ return !this.disabled; }, - // private + // private onDragStart: function(e){ this.thumb.addClass('x-slider-thumb-drag'); this.dragging = true; @@ -10892,14 +12145,14 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, { this.fireEvent('dragstart', this, e); }, - // private + // private onDrag: function(e){ var pos = this.innerEl.translatePoints(this.tracker.getXY()); this.setValue(Ext.util.Format.round(this.reverseValue(pos.left), this.decimalPrecision), false); this.fireEvent('drag', this, e); }, - // private + // private onDragEnd: function(e){ this.thumb.removeClass('x-slider-thumb-drag'); this.dragging = false; @@ -10909,12 +12162,13 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, { } }, - // private + // private onResize : function(w, h){ this.innerEl.setWidth(w - (this.el.getPadding('l') + this.endEl.getPadding('r'))); this.syncThumb(); + Ext.Slider.superclass.onResize.apply(this, arguments); }, - + //private onDisable: function(){ Ext.Slider.superclass.onDisable.call(this); @@ -10926,26 +12180,26 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, { this.thumb.hide(); this.innerEl.addClass(this.disabledClass).dom.disabled = true; if (!this.thumbHolder){ - this.thumbHolder = this.endEl.createChild({cls: 'x-slider-thumb ' + this.disabledClass}); + this.thumbHolder = this.endEl.createChild({cls: 'x-slider-thumb ' + this.disabledClass}); } this.thumbHolder.show().setXY(xy); } }, - + //private onEnable: function(){ Ext.Slider.superclass.onEnable.call(this); this.thumb.removeClass(this.disabledClass); if(Ext.isIE){ this.innerEl.removeClass(this.disabledClass).dom.disabled = false; - if (this.thumbHolder){ + if(this.thumbHolder){ this.thumbHolder.hide(); } this.thumb.show(); this.syncThumb(); } }, - + /** * Synchronizes the thumb position to the proper proportion of the total component width based * on the current slider {@link #value}. This will be called automatically when the Slider @@ -10958,12 +12212,18 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, { } }, - /** - * Returns the current value of the slider - * @return {Number} The current value of the slider - */ + /** + * Returns the current value of the slider + * @return {Number} The current value of the slider + */ getValue : function(){ return this.value; + }, + + // private + beforeDestroy : function(){ + Ext.destroyMembers(this, 'endEl', 'innerEl', 'thumb', 'halfThumb', 'focusEl', 'tracker', 'thumbHolder'); + Ext.Slider.superclass.beforeDestroy.call(this); } }); Ext.reg('slider', Ext.Slider); @@ -10976,8 +12236,8 @@ Ext.Slider.Vertical = { }, getRatio : function(){ - var h = this.innerEl.getHeight(); - var v = this.maxValue - this.minValue; + var h = this.innerEl.getHeight(), + v = this.maxValue - this.minValue; return h/v; }, @@ -10990,15 +12250,15 @@ Ext.Slider.Vertical = { }, onDrag: function(e){ - var pos = this.innerEl.translatePoints(this.tracker.getXY()); - var bottom = this.innerEl.getHeight()-pos.top; + var pos = this.innerEl.translatePoints(this.tracker.getXY()), + bottom = this.innerEl.getHeight()-pos.top; this.setValue(this.minValue + Ext.util.Format.round(bottom/this.getRatio(), this.decimalPrecision), false); this.fireEvent('drag', this, e); }, onClickChange : function(local){ if(local.left > this.clickRange[0] && local.left < this.clickRange[1]){ - var bottom = this.innerEl.getHeight()-local.top; + var bottom = this.innerEl.getHeight() - local.top; this.setValue(this.minValue + Ext.util.Format.round(bottom/this.getRatio(), this.decimalPrecision), undefined, true); } } @@ -11118,7 +12378,7 @@ Ext.ProgressBar = Ext.extend(Ext.BoxComponent, { if(text){ this.updateText(text); } - if(this.rendered){ + if(this.rendered && !this.isDestroyed){ var w = Math.floor(value*this.el.dom.firstChild.offsetWidth); this.progressBar.setWidth(w, animate === true || (animate !== false && this.animate)); if(this.textTopEl){ @@ -11195,6 +12455,7 @@ myAction.on('complete', function(){ this.waitTimer = Ext.TaskMgr.start({ run: function(i){ var inc = o.increment || 10; + i -= 1; this.updateProgress(((((i+inc)%inc)+1)*(100/inc))*0.01, null, o.animate); }, interval: o.interval || 1000, @@ -11273,15 +12534,31 @@ myAction.on('complete', function(){ if(this.textTopEl){ this.textTopEl.addClass('x-hidden'); } + this.clearTimer(); + if(hide === true){ + this.hide(); + } + return this; + }, + + // private + clearTimer : function(){ if(this.waitTimer){ this.waitTimer.onStop = null; //prevent recursion Ext.TaskMgr.stop(this.waitTimer); this.waitTimer = null; } - if(hide === true){ - this.hide(); + }, + + onDestroy: function(){ + this.clearTimer(); + if(this.rendered){ + if(this.textEl.isComposite){ + this.textEl.clear(); + } + Ext.destroyMembers(this, 'textEl', 'progressBar', 'textTopEl'); } - return this; + Ext.ProgressBar.superclass.onDestroy.call(this); } }); Ext.reg('progress', Ext.ProgressBar); \ No newline at end of file