/*! * Ext JS Library 3.0.0 * Copyright(c) 2006-2009 Ext JS, LLC * licensing@extjs.com * http://www.extjs.com/license */ /** * @class Ext.ComponentMgr *

Provides a registry of all Components (instances of {@link Ext.Component} or any subclass * thereof) on a page so that they can be easily accessed by {@link Ext.Component component} * {@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 * 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 * 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}.

* @singleton */ Ext.ComponentMgr = function(){ var all = new Ext.util.MixedCollection(); var types = {}; var ptypes = {}; return { /** * Registers a component. * @param {Ext.Component} c The component */ register : function(c){ all.add(c); }, /** * Unregisters a component. * @param {Ext.Component} c The component */ unregister : function(c){ all.remove(c); }, /** * 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 * Class was found. */ get : function(id){ return all.get(id); }, /** * Registers a function that will be called when a specified component is added to ComponentMgr * @param {String} id The component {@link Ext.Component#id id} * @param {Function} fn The callback function * @param {Object} scope The scope of the callback */ onAvailable : function(id, fn, scope){ all.on("add", function(index, o){ if(o.id == id){ fn.call(scope || o, o); all.un("add", fn, scope); } }); }, /** * The MixedCollection used internally for the component cache. An example usage may be subscribing to * events on the MixedCollection to monitor addition or removal. Read-only. * @type {MixedCollection} */ all : all, /** * Checks if a Component type is registered. * @param {Ext.Component} xtype The mnemonic string by which the Component class may be looked up * @return {Boolean} Whether the type is registered. */ isRegistered : function(xtype){ return types[xtype] !== undefined; }, /** *

Registers a new Component constructor, keyed by a new * {@link Ext.Component#xtype}.

*

Use this method (or its alias {@link Ext#reg Ext.reg}) to register new * subclasses of {@link Ext.Component} so that lazy instantiation may be used when specifying * child Components. * see {@link Ext.Container#items}

* @param {String} xtype The mnemonic string by which the Component class may be looked up. * @param {Constructor} cls The new Component class. */ registerType : function(xtype, cls){ types[xtype] = cls; cls.xtype = xtype; }, /** * 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. */ create : function(config, defaultType){ return config.render ? config : new types[config.xtype || defaultType](config); }, /** *

Registers a new Plugin constructor, keyed by a new * {@link Ext.Component#ptype}.

*

Use this method (or its alias {@link Ext#preg Ext.preg}) to register new * plugins for {@link Ext.Component}s so that lazy instantiation may be used when specifying * Plugins.

* @param {String} ptype The mnemonic string by which the Plugin class may be looked up. * @param {Constructor} cls The new Plugin class. */ registerPlugin : function(ptype, cls){ ptypes[ptype] = cls; cls.ptype = ptype; }, /** * Creates a new Plugin from the specified config object using the * 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). * @return {Ext.Component} The newly instantiated Plugin. */ createPlugin : function(config, defaultType){ return new ptypes[config.ptype || defaultType](config); } }; }(); /** * Shorthand for {@link Ext.ComponentMgr#registerType} * @param {String} xtype The {@link Ext.component#xtype mnemonic string} by which the Component class * may be looked up. * @param {Constructor} cls The new Component class. * @member Ext * @method reg */ Ext.reg = Ext.ComponentMgr.registerType; // this will be called a lot internally, shorthand to keep the bytes down /** * Shorthand for {@link Ext.ComponentMgr#registerPlugin} * @param {String} ptype The {@link Ext.component#ptype mnemonic string} by which the Plugin class * may be looked up. * @param {Constructor} cls The new Plugin class. * @member Ext * @method preg */ Ext.preg = Ext.ComponentMgr.registerPlugin; 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 * Ext component lifecycle of creation, rendering and destruction which is provided by the {@link Ext.Container Container} class. * Components may be added to a Container through the {@link Ext.Container#items items} config option at the time the Container is created, * or they may be added dynamically via the {@link Ext.Container#add add} method.

*

The Component base class has built-in support for basic hide/show and enable/disable behavior.

*

All Components are registered with the {@link Ext.ComponentMgr} on construction so that they can be referenced at any time via * {@link Ext#getCmp}, passing the {@link #id}.

*

All user-developed visual widgets that are required to participate in automated lifecycle and size management should subclass Component (or * {@link Ext.BoxComponent} if managed box model handling is required, ie height and width management).

*

See the Creating new UI controls tutorial for details on how * and to either extend or augment ExtJs base classes to create custom Components.

*

Every component has a specific xtype, which is its Ext-specific type name, along with methods for checking the * xtype like {@link #getXType} and {@link #isXType}. This is the list of all valid xtypes:

*
xtype            Class
-------------    ------------------
box              {@link Ext.BoxComponent}
button           {@link Ext.Button}
buttongroup      {@link Ext.ButtonGroup}
colorpalette     {@link Ext.ColorPalette}
component        {@link Ext.Component}
container        {@link Ext.Container}
cycle            {@link Ext.CycleButton}
dataview         {@link Ext.DataView}
datepicker       {@link Ext.DatePicker}
editor           {@link Ext.Editor}
editorgrid       {@link Ext.grid.EditorGridPanel}
flash            {@link Ext.FlashComponent}
grid             {@link Ext.grid.GridPanel}
listview         {@link Ext.ListView}
panel            {@link Ext.Panel}
progress         {@link Ext.ProgressBar}
propertygrid     {@link Ext.grid.PropertyGrid}
slider           {@link Ext.Slider}
spacer           {@link Ext.Spacer}
splitbutton      {@link Ext.SplitButton}
tabpanel         {@link Ext.TabPanel}
treepanel        {@link Ext.tree.TreePanel}
viewport         {@link Ext.ViewPort}
window           {@link Ext.Window}

Toolbar components
---------------------------------------
paging           {@link Ext.PagingToolbar}
toolbar          {@link Ext.Toolbar}
tbbutton         {@link Ext.Toolbar.Button}        (deprecated; use button)
tbfill           {@link Ext.Toolbar.Fill}
tbitem           {@link Ext.Toolbar.Item}
tbseparator      {@link Ext.Toolbar.Separator}
tbspacer         {@link Ext.Toolbar.Spacer}
tbsplit          {@link Ext.Toolbar.SplitButton}   (deprecated; use splitbutton)
tbtext           {@link Ext.Toolbar.TextItem}

Menu components
---------------------------------------
menu             {@link Ext.menu.Menu}
colormenu        {@link Ext.menu.ColorMenu}
datemenu         {@link Ext.menu.DateMenu}
menubaseitem     {@link Ext.menu.BaseItem}
menucheckitem    {@link Ext.menu.CheckItem}
menuitem         {@link Ext.menu.Item}
menuseparator    {@link Ext.menu.Separator}
menutextitem     {@link Ext.menu.TextItem}

Form components
---------------------------------------
form             {@link Ext.FormPanel}
checkbox         {@link Ext.form.Checkbox}
checkboxgroup    {@link Ext.form.CheckboxGroup}
combo            {@link Ext.form.ComboBox}
datefield        {@link Ext.form.DateField}
displayfield     {@link Ext.form.DisplayField}
field            {@link Ext.form.Field}
fieldset         {@link Ext.form.FieldSet}
hidden           {@link Ext.form.Hidden}
htmleditor       {@link Ext.form.HtmlEditor}
label            {@link Ext.form.Label}
numberfield      {@link Ext.form.NumberField}
radio            {@link Ext.form.Radio}
radiogroup       {@link Ext.form.RadioGroup}
textarea         {@link Ext.form.TextArea}
textfield        {@link Ext.form.TextField}
timefield        {@link Ext.form.TimeField}
trigger          {@link Ext.form.TriggerField}

Chart components
---------------------------------------
chart            {@link Ext.chart.Chart}
barchart         {@link Ext.chart.BarChart}
cartesianchart   {@link Ext.chart.CartesianChart}
columnchart      {@link Ext.chart.ColumnChart}
linechart        {@link Ext.chart.LineChart}
piechart         {@link Ext.chart.PieChart}

Store xtypes
---------------------------------------
arraystore       {@link Ext.data.ArrayStore}
directstore      {@link Ext.data.DirectStore}
groupingstore    {@link Ext.data.GroupingStore}
jsonstore        {@link Ext.data.JsonStore}
simplestore      {@link Ext.data.SimpleStore}      (deprecated; use arraystore)
store            {@link Ext.data.Store}
xmlstore         {@link Ext.data.XmlStore}
* @constructor * @param {Ext.Element/String/Object} config The configuration options may be specified as either: *
*/ Ext.Component = function(config){ config = config || {}; if(config.initialConfig){ if(config.isAction){ // actions this.baseAction = config; } config = config.initialConfig; // component cloning / action set up }else if(config.tagName || config.dom || Ext.isString(config)){ // element object config = {applyTo: config, id: config.id || config}; } /** * This Component's initial configuration specification. Read-only. * @type Object * @property initialConfig */ this.initialConfig = config; Ext.apply(this, config); this.addEvents( /** * @event disable * Fires after the component is disabled. * @param {Ext.Component} this */ 'disable', /** * @event enable * Fires after the component is enabled. * @param {Ext.Component} this */ 'enable', /** * @event beforeshow * Fires before the component is shown by calling the {@link #show} method. * Return false from an event handler to stop the show. * @param {Ext.Component} this */ 'beforeshow', /** * @event show * Fires after the component is shown when calling the {@link #show} method. * @param {Ext.Component} this */ 'show', /** * @event beforehide * Fires before the component is hidden by calling the {@link #hide} method. * Return false from an event handler to stop the hide. * @param {Ext.Component} this */ 'beforehide', /** * @event hide * Fires after the component is hidden. * Fires after the component is hidden when calling the {@link #hide} method. * @param {Ext.Component} this */ 'hide', /** * @event beforerender * Fires before the component is {@link #rendered}. Return false from an * event handler to stop the {@link #render}. * @param {Ext.Component} this */ 'beforerender', /** * @event render * Fires after the component markup is {@link #rendered}. * @param {Ext.Component} this */ 'render', /** * @event afterrender *

Fires after the component rendering is finished.

*

The afterrender event is fired after this Component has been {@link #rendered}, been postprocesed * by any afterRender method defined for the Component, and, if {@link #stateful}, after state * has been restored.

* @param {Ext.Component} this */ 'afterrender', /** * @event beforedestroy * Fires before the component is {@link #destroy}ed. Return false from an event handler to stop the {@link #destroy}. * @param {Ext.Component} this */ 'beforedestroy', /** * @event destroy * Fires after the component is {@link #destroy}ed. * @param {Ext.Component} this */ 'destroy', /** * @event beforestaterestore * Fires before the state of the component is restored. Return false from an event handler to stop the restore. * @param {Ext.Component} this * @param {Object} state The hash of state values returned from the StateProvider. If this * event is not vetoed, then the state object is passed to applyState. By default, * that simply copies property values into this Component. The method maybe overriden to * provide custom state restoration. */ 'beforestaterestore', /** * @event staterestore * Fires after the state of the component is restored. * @param {Ext.Component} this * @param {Object} state The hash of state values returned from the StateProvider. This is passed * to applyState. By default, that simply copies property values into this * Component. The method maybe overriden to provide custom state restoration. */ 'staterestore', /** * @event beforestatesave * Fires before the state of the component is saved to the configured state provider. Return false to stop the save. * @param {Ext.Component} this * @param {Object} state The hash of state values. This is determined by calling * getState() on the Component. This method must be provided by the * developer to return whetever representation of state is required, by default, Ext.Component * has a null implementation. */ 'beforestatesave', /** * @event statesave * Fires after the state of the component is saved to the configured state provider. * @param {Ext.Component} this * @param {Object} state The hash of state values. This is determined by calling * getState() on the Component. This method must be provided by the * developer to return whetever representation of state is required, by default, Ext.Component * has a null implementation. */ 'statesave' ); this.getId(); Ext.ComponentMgr.register(this); Ext.Component.superclass.constructor.call(this); if(this.baseAction){ this.baseAction.addComponent(this); } this.initComponent(); if(this.plugins){ if(Ext.isArray(this.plugins)){ for(var i = 0, len = this.plugins.length; i < len; i++){ this.plugins[i] = this.initPlugin(this.plugins[i]); } }else{ this.plugins = this.initPlugin(this.plugins); } } if(this.stateful !== false){ this.initState(config); } if(this.applyTo){ this.applyToMarkup(this.applyTo); delete this.applyTo; }else if(this.renderTo){ this.render(this.renderTo); delete this.renderTo; } }; // private Ext.Component.AUTO_ID = 1000; Ext.extend(Ext.Component, Ext.util.Observable, { // 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 * has been configured to use the {@link Ext.layout.FormLayout FormLayout} layout manager (e.g. * {@link Ext.form.FormPanel} or specifying layout:'form').


*

Also see {@link #hideLabel} and * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.

* Example use:

new Ext.FormPanel({
    height: 100,
    renderTo: Ext.getBody(),
    items: [{
        xtype: 'textfield',
        fieldLabel: 'Name'
    }]
});
*/ /** * @cfg {String} labelStyle

A CSS style specification string to apply directly to this field's * label. Defaults to the container's labelStyle value if set (e.g., * {@link Ext.layout.FormLayout#labelStyle} , or '').

*

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


*

Also see {@link #hideLabel} and * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.

* Example use:

new Ext.FormPanel({
    height: 100,
    renderTo: Ext.getBody(),
    items: [{
        xtype: 'textfield',
        fieldLabel: 'Name',
        labelStyle: 'font-weight:bold;'
    }]
});
*/ /** * @cfg {String} labelSeparator

The separator to display after the text of each * {@link #fieldLabel}. This property may be configured at various levels. * The order of precedence is: *

* To display no separator for this field's label specify empty string ''.

*

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


*

Also see {@link #hideLabel} and * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.

* Example use:

new Ext.FormPanel({
    height: 100,
    renderTo: Ext.getBody(),
    layoutConfig: {
        labelSeparator: '~'   // layout config has lowest priority (defaults to ':')
    },
    {@link Ext.layout.FormLayout#labelSeparator labelSeparator}: '>>',     // config at container level
    items: [{
        xtype: 'textfield',
        fieldLabel: 'Field 1',
        labelSeparator: '...' // field/component level config supersedes others
    },{
        xtype: 'textfield',
        fieldLabel: 'Field 2' // labelSeparator will be '='
    }]
});
*/ /** * @cfg {Boolean} hideLabel

true to completely hide the label element * ({@link #fieldLabel label} and {@link #labelSeparator separator}). Defaults to false. * By default, even if you do not specify a {@link #fieldLabel} the space will still be * reserved so that the field will line up with other fields that do have labels. * Setting this to true will cause the field to not reserve that space.

*

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


* Example use:

new Ext.FormPanel({
    height: 100,
    renderTo: Ext.getBody(),
    items: [{
        xtype: 'textfield'
        hideLabel: true
    }]
});
*/ /** * @cfg {String} clearCls

The CSS class used to to apply to the special clearing div rendered * directly after each form field wrapper to provide field clearing (defaults to * 'x-form-clear-left').

*

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') and either a * {@link #fieldLabel} is specified or isFormField=true is specified.


*

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 * 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').

*

Since it is applied to the item wrapper (see * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}), it allows * you to write standard CSS rules that can apply to the field, the label (if specified), or * 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:
<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'
	}]
});
*/ // 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.

*/ /** * @cfg {String} id *

The unique id of this component (defaults to an {@link #getId auto-assigned id}). * You should assign an id if you need to be able to access the component later and you do * not have an object reference available (e.g., using {@link Ext}.{@link Ext#getCmp getCmp}).

*

Note that this id will also be used as the element id for the containing HTML element * that is rendered to the page for this component. This allows you to write id-based CSS * rules to style the specific instance of this component uniquely, and also to select * sub-elements using this component's id as the parent.

*

Note: to avoid complications imposed by a unique id also see * {@link #itemId} and {@link #ref}.

*

Note: to access the container of an item see {@link #ownerCt}.

*/ /** * @cfg {String} itemId *

An itemId can be used as an alternative way to get a reference to a component * when no object reference is available. Instead of using an {@link #id} with * {@link Ext}.{@link Ext#getCmp getCmp}, use itemId with * {@link Ext.Container}.{@link Ext.Container#getComponent getComponent} which will retrieve * itemId's or {@link #id}'s. Since itemId's are an index to the * container's internal MixedCollection, the itemId is scoped locally to the container -- * avoiding potential conflicts with {@link Ext.ComponentMgr} which requires a unique * {@link #id}.

*

var c = new Ext.Panel({ //
    {@link Ext.BoxComponent#height height}: 300,
    {@link #renderTo}: document.body,
    {@link Ext.Container#layout layout}: 'auto',
    {@link Ext.Container#items items}: [
        {
            itemId: 'p1',
            {@link Ext.Panel#title title}: 'Panel 1',
            {@link Ext.BoxComponent#height height}: 150
        },
        {
            itemId: 'p2',
            {@link Ext.Panel#title title}: 'Panel 2',
            {@link Ext.BoxComponent#height height}: 150
        }
    ]
})
p1 = c.{@link Ext.Container#getComponent getComponent}('p1'); // not the same as {@link Ext#getCmp Ext.getCmp()}
p2 = p1.{@link #ownerCt}.{@link Ext.Container#getComponent getComponent}('p2'); // reference via a sibling
     * 
*

Also see {@link #id} and {@link #ref}.

*

Note: to access the container of an item see {@link #ownerCt}.

*/ /** * @cfg {String} xtype * The registered xtype to create. This config option is not used when passing * a config object into a constructor. This config option is used only when * lazy instantiation is being used, and a child item of a Container is being * specified not as a fully instantiated Component, but as a Component config * object. The xtype will be looked up at render time up to determine what * type of child Component to create.

* The predefined xtypes are listed {@link Ext.Component here}. *

* If you subclass Components to create your own Components, you may register * them using {@link Ext.ComponentMgr#registerType} in order to be able to * take advantage of lazy instantiation and rendering. */ /** * @cfg {String} ptype * The registered ptype to create. This config option is not used when passing * a config object into a constructor. This config option is used only when * lazy instantiation is being used, and a Plugin is being * specified not as a fully instantiated Component, but as a Component config * object. The ptype will be looked up at render time up to determine what * type of Plugin to create.

* If you create your own Plugins, you may register them using * {@link Ext.ComponentMgr#registerPlugin} in order to be able to * take advantage of lazy instantiation and rendering. */ /** * @cfg {String} cls * An optional extra CSS class that will be added to this component's Element (defaults to ''). This can be * useful for adding customized styles to the component or any of its children using standard CSS rules. */ /** * @cfg {String} overCls * An optional extra CSS class that will be added to this component's Element when the mouse moves * over the Element, and removed when the mouse moves out. (defaults to ''). This can be * useful for adding customized 'active' or 'hover' styles to the component or any of its children using standard CSS rules. */ /** * @cfg {String} style * A custom style specification to be applied to this component's Element. Should be a valid argument to * {@link Ext.Element#applyStyles}. *

new Ext.Panel({
    title: 'Some Title',
    renderTo: Ext.getBody(),
    width: 400, height: 300,
    layout: 'form',
    items: [{
        xtype: 'textarea',
        style: {
            width: '95%',
            marginBottom: '10px'
        }
    },
        new Ext.Button({
            text: 'Send',
            minWidth: '100',
            style: {
                marginBottom: '10px'
            }
        })
    ]
});
     * 
*/ /** * @cfg {String} ctCls *

An optional extra CSS class that will be added to this component's container. This can be useful for * adding customized styles to the container or any of its children using standard CSS rules. See * {@link Ext.layout.ContainerLayout}.{@link Ext.layout.ContainerLayout#extraCls extraCls} also.

*

Note: ctCls defaults to '' except for the following class * which assigns a value by default: *

* To configure the above Class with an extra CSS class append to the default. For example, * for BoxLayout (Hbox and Vbox):

     * ctCls: 'x-box-layout-ct custom-class'
     * 
*

*/ /** * @cfg {Boolean} disabled * Render this component disabled (default is false). */ disabled : false, /** * @cfg {Boolean} hidden * Render this component hidden (default is false). If true, the * {@link #hide} method will be called internally. */ hidden : false, /** * @cfg {Object/Array} plugins * An object or array of objects that will provide custom functionality for this component. The only * requirement for a valid plugin is that it contain an init method that accepts a reference of type Ext.Component. * When a component is created, if any plugins are available, the component will call the init method on each * plugin, passing a reference to itself. Each plugin can then call methods or respond to events on the * component as needed to provide its functionality. */ /** * @cfg {Mixed} applyTo *

Specify the id of the element, a DOM element or an existing Element corresponding to a DIV * that is already present in the document that specifies some structural markup for this * component.

*/ /** * @cfg {Mixed} renderTo *

Specify the id of the element, a DOM element or an existing Element that this component * will be rendered into.

*

See {@link #render} also.

*/ /** * @cfg {Boolean} stateful *

A flag which causes the Component to attempt to restore the state of * internal properties from a saved state on startup. The component must have * either a {@link #stateId} or {@link #id} assigned * for state to be managed. Auto-generated ids are not guaranteed to be stable * across page loads and cannot be relied upon to save and restore the same * state for a component.

*

For state saving to work, the state manager's provider must have been * set to an implementation of {@link Ext.state.Provider} which overrides the * {@link Ext.state.Provider#set set} and {@link Ext.state.Provider#get get} * methods to save and recall name/value pairs. A built-in implementation, * {@link Ext.state.CookieProvider} is available.

*

To set the state provider for the current page:

*

Ext.state.Manager.setProvider(new Ext.state.CookieProvider({
    expires: new Date(new Date().getTime()+(1000*60*60*24*7)), //7 days from now
}));
     * 
*

A stateful Component attempts to save state when one of the events * listed in the {@link #stateEvents} configuration fires.

*

To save state, a stateful Component first serializes its state by * calling getState. By default, this function does * nothing. The developer must provide an implementation which returns an * object hash which represents the Component's restorable state.

*

The value yielded by getState is passed to {@link Ext.state.Manager#set} * which uses the configured {@link Ext.state.Provider} to save the object * keyed by the Component's {@link stateId}, or, if that is not * specified, its {@link #id}.

*

During construction, a stateful Component attempts to restore * its state by calling {@link Ext.state.Manager#get} passing the * {@link #stateId}, or, if that is not specified, the * {@link #id}.

*

The resulting object is passed to applyState. * The default implementation of applyState simply copies * properties into the object, but a developer may override this to support * more behaviour.

*

You can perform extra processing on state save and restore by attaching * handlers to the {@link #beforestaterestore}, {@link #staterestore}, * {@link #beforestatesave} and {@link #statesave} events.

*/ /** * @cfg {String} stateId * The unique id for this component to use for state management purposes * (defaults to the component id if one was set, otherwise null if the * component is using a generated id). *

See {@link #stateful} for an explanation of saving and * restoring Component state.

*/ /** * @cfg {Array} stateEvents *

An array of events that, when fired, should trigger this component to * save its state (defaults to none). stateEvents may be any type * of event supported by this component, including browser or custom events * (e.g., ['click', 'customerchange']).

*

See {@link #stateful} for an explanation of saving and * restoring Component state.

*/ /** * @cfg {Mixed} autoEl *

A tag name or {@link Ext.DomHelper DomHelper} spec used to create the {@link #getEl Element} which will * encapsulate this Component.

*

You do not normally need to specify this. For the base classes {@link Ext.Component}, {@link Ext.BoxComponent}, * and {@link Ext.Container}, this defaults to 'div'. The more complex Ext classes use a more complex * DOM structure created by their own onRender methods.

*

This is intended to allow the developer to create application-specific utility Components encapsulated by * different DOM elements. Example usage:


{
    xtype: 'box',
    autoEl: {
        tag: 'img',
        src: 'http://www.example.com/example.jpg'
    }
}, {
    xtype: 'box',
    autoEl: {
        tag: 'blockquote',
        html: 'autoEl is cool!'
    }
}, {
    xtype: 'container',
    autoEl: 'ul',
    cls: 'ux-unordered-list',
    items: {
        xtype: 'box',
        autoEl: 'li',
        html: 'First list item'
    }
}
*/ autoEl : 'div', /** * @cfg {String} disabledClass * CSS class added to the component when it is disabled (defaults to 'x-item-disabled'). */ disabledClass : 'x-item-disabled', /** * @cfg {Boolean} allowDomMove * Whether the component can move the Dom node when rendering (defaults to true). */ allowDomMove : true, /** * @cfg {Boolean} autoShow * True if the component should check for hidden classes (e.g. 'x-hidden' or 'x-hide-display') and remove * them on render (defaults to false). */ autoShow : false, /** * @cfg {String} hideMode *

How this component should be hidden. Supported values are 'visibility' * (css visibility), 'offsets' (negative offset position) and 'display' * (css display).

*

Note: the default of 'display' is generally preferred * since items are automatically laid out when they are first shown (no sizing * is done while hidden).

*/ hideMode : 'display', /** * @cfg {Boolean} hideParent * True to hide and show the component's container when hide/show is called on the component, false to hide * and show the component itself (defaults to false). For example, this can be used as a shortcut for a hide * button on a window by setting hide:true on the button when adding it to its parent container. */ hideParent : false, /** *

The {@link Ext.Element} which encapsulates this Component. Read-only.

*

This will usually be a <DIV> element created by the class's onRender method, but * that may be overridden using the {@link #autoEl} config.

*

Note: this element will not be available until this Component has been rendered.


*

To add listeners for DOM events to this Component (as opposed to listeners * for this Component's own Observable events), see the {@link Ext.util.Observable#listeners listeners} * config for a suggestion, or use a render listener directly:


new Ext.Panel({
    title: 'The Clickable Panel',
    listeners: {
        render: function(p) {
            // Append the Panel to the click handler's argument list.
            p.getEl().on('click', handlePanelClick.createDelegate(null, [p], true));
        },
        single: true  // Remove the listener after first invocation
    }
});
*

See also {@link #getEl getEl}

* @type Ext.Element * @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}.

* @type Ext.Container * @property ownerCt */ /** * True if this component is hidden. Read-only. * @type Boolean * @property */ /** * True if this component is disabled. Read-only. * @type Boolean * @property */ /** * True if this component has been rendered. Read-only. * @type Boolean * @property */ rendered : false, // private ctype : 'Ext.Component', // private actionMode : 'el', // private getActionEl : function(){ return this[this.actionMode]; }, initPlugin : function(p){ if(p.ptype && !Ext.isFunction(p.init)){ p = Ext.ComponentMgr.createPlugin(p); }else if(Ext.isString(p)){ p = Ext.ComponentMgr.createPlugin({ ptype: p }); } p.init(this); return p; }, /* // protected * Function to be implemented by Component subclasses to be part of standard component initialization flow (it is empty by default). *

// Traditional constructor:
Ext.Foo = function(config){
    // call superclass constructor:
    Ext.Foo.superclass.constructor.call(this, config);

    this.addEvents({
        // add events
    });
};
Ext.extend(Ext.Foo, Ext.Bar, {
   // class body
}

// initComponent replaces the constructor:
Ext.Foo = Ext.extend(Ext.Bar, {
    initComponent : function(){
        // call superclass initComponent
        Ext.Container.superclass.initComponent.call(this);

        this.addEvents({
            // add events
        });
    }
}
*/ initComponent : Ext.emptyFn, /** *

Render this Component into the passed HTML element.

*

If you are using a {@link Ext.Container Container} object to house this Component, then * do not use the render method.

*

A Container's child Components are rendered by that Container's * {@link Ext.Container#layout layout} manager when the Container is first rendered.

*

Certain layout managers allow dynamic addition of child components. Those that do * include {@link Ext.layout.CardLayout}, {@link Ext.layout.AnchorLayout}, * {@link Ext.layout.FormLayout}, {@link Ext.layout.TableLayout}.

*

If the Container is already rendered when a new child Component is added, you may need to call * the Container's {@link Ext.Container#doLayout 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 once.

*

When creating complex UIs, it is important to remember that sizing and positioning * of child items is the responsibility of the Container's {@link Ext.Container#layout layout} manager. * If you expect child items to be sized in response to user interactions, you must * configure the Container with a layout manager which creates and manages the type of layout you * have in mind.

*

Omitting the Container's {@link Ext.Container#layout layout} config means that a basic * layout manager is used which does nothing but render child components sequentially into the * Container. No sizing or positioning will be performed in this situation.

* @param {Element/HTMLElement/String} container (optional) The element this Component should be * rendered into. If it is being created from existing markup, this should be omitted. * @param {String/Number} position (optional) The element ID or DOM node index within the container before * which this component will be inserted (defaults to appending to the end of the container) */ render : function(container, position){ if(!this.rendered && this.fireEvent('beforerender', this) !== false){ if(!container && this.el){ this.el = Ext.get(this.el); container = this.el.dom.parentNode; this.allowDomMove = false; } this.container = Ext.get(container); if(this.ctCls){ this.container.addClass(this.ctCls); } this.rendered = true; if(position !== undefined){ if(Ext.isNumber(position)){ position = this.container.dom.childNodes[position]; }else{ position = Ext.getDom(position); } } this.onRender(this.container, position || null); if(this.autoShow){ this.el.removeClass(['x-hidden','x-hide-' + this.hideMode]); } if(this.cls){ this.el.addClass(this.cls); delete this.cls; } if(this.style){ this.el.applyStyles(this.style); delete this.style; } if(this.overCls){ this.el.addClassOnOver(this.overCls); } this.fireEvent('render', this); this.afterRender(this.container); if(this.hidden){ // call this so we don't fire initial hide events. this.doHide(); } if(this.disabled){ // pass silent so the event doesn't fire the first time. this.disable(true); } if(this.stateful !== false){ this.initStateEvents(); } this.initRef(); this.fireEvent('afterrender', this); } return this; }, 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.

*

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({
    title: 'My EditorGridPanel',
    store: myStore,
    colModel: myColModel,
    tbar: [{
        text: 'Save',
        handler: saveChanges,
        disabled: true,
        ref: '../saveButton'
    }],
    listeners: {
        afteredit: function() {
//          The button reference is in the GridPanel
            myGrid.saveButton.enable();
        }
    }
});
*

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}.

*/ 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++; } t[levels[--i]] = this; } }, // private initState : function(config){ 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.fireEvent('staterestore', this, state); } } } } }, // private getStateId : function(){ return this.stateId || ((this.id.indexOf('ext-comp-') == 0 || this.id.indexOf('ext-gen') == 0) ? null : this.id); }, // private initStateEvents : function(){ if(this.stateEvents){ for(var i = 0, e; e = this.stateEvents[i]; i++){ this.on(e, this.saveState, this, {delay:100}); } } }, // private applyState : function(state, config){ if(state){ Ext.apply(this, state); } }, // private getState : function(){ return null; }, // private saveState : function(){ if(Ext.state.Manager && this.stateful !== false){ var id = this.getStateId(); if(id){ var state = this.getState(); if(this.fireEvent('beforestatesave', this, state) !== false){ Ext.state.Manager.set(id, state); this.fireEvent('statesave', this, state); } } } }, /** * Apply this component to existing markup that is valid. With this function, no call to render() is required. * @param {String/HTMLElement} el */ applyToMarkup : function(el){ this.allowDomMove = false; this.el = Ext.get(el); this.render(this.el.dom.parentNode); }, /** * Adds a CSS class to the component's underlying element. * @param {string} cls The CSS class name to add * @return {Ext.Component} this */ addClass : function(cls){ if(this.el){ this.el.addClass(cls); }else{ this.cls = this.cls ? this.cls + ' ' + cls : cls; } return this; }, /** * Removes a CSS class from the component's underlying element. * @param {string} cls The CSS class name to remove * @return {Ext.Component} this */ removeClass : function(cls){ if(this.el){ this.el.removeClass(cls); }else if(this.cls){ this.cls = this.cls.split(' ').remove(cls).join(' '); } return this; }, // private // default function is not really useful onRender : function(ct, position){ if(!this.el && this.autoEl){ if(Ext.isString(this.autoEl)){ this.el = document.createElement(this.autoEl); }else{ var div = document.createElement('div'); Ext.DomHelper.overwrite(div, this.autoEl); this.el = div.firstChild; } if (!this.el.id) { this.el.id = this.getId(); } } if(this.el){ this.el = Ext.get(this.el); if(this.allowDomMove !== false){ ct.dom.insertBefore(this.el.dom, position); } } }, // private getAutoCreate : function(){ var cfg = Ext.isObject(this.autoCreate) ? this.autoCreate : Ext.apply({}, this.defaultAutoCreate); if(this.id && !cfg.id){ cfg.id = this.id; } return cfg; }, // private afterRender : Ext.emptyFn, /** * Destroys this component by purging any event listeners, removing the component's element from the DOM, * removing the component from its {@link Ext.Container} (if applicable) and unregistering it from * {@link Ext.ComponentMgr}. Destruction is generally handled automatically by the framework and this method * should usually not need to be called directly. * */ 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(); } } this.onDestroy(); Ext.ComponentMgr.unregister(this); this.fireEvent('destroy', this); this.purgeListeners(); } }, // private beforeDestroy : Ext.emptyFn, // private onDestroy : Ext.emptyFn, /** *

Returns the {@link Ext.Element} which encapsulates this Component.

*

This will usually be a <DIV> element created by the class's onRender method, but * that may be overridden using the {@link #autoEl} config.

*

Note: this element will not be available until this Component has been rendered.


*

To add listeners for DOM events to this Component (as opposed to listeners * for this Component's own Observable events), see the {@link #listeners} config for a suggestion, * or use a render listener directly:


new Ext.Panel({
    title: 'The Clickable Panel',
    listeners: {
        render: function(p) {
            // Append the Panel to the click handler's argument list.
            p.getEl().on('click', handlePanelClick.createDelegate(null, [p], true));
        },
        single: true  // Remove the listener after first invocation
    }
});
* @return {Ext.Element} The Element which encapsulates this Component. */ getEl : function(){ return this.el; }, /** * Returns the id of this component or automatically generates and * returns an id if an id is not defined yet:

     * 'ext-comp-' + (++Ext.Component.AUTO_ID)
     * 
* @return {String} id */ getId : function(){ return this.id || (this.id = 'ext-comp-' + (++Ext.Component.AUTO_ID)); }, /** * Returns the {@link #itemId} of this component. If an * {@link #itemId} was not assigned through configuration the * id is returned using {@link #getId}. * @return {String} */ getItemId : function(){ return this.itemId || this.getId(); }, /** * Try to focus this component. * @param {Boolean} selectText (optional) If applicable, true to also select the text in this component * @param {Boolean/Number} delay (optional) Delay the focus this number of milliseconds (true for 10 milliseconds) * @return {Ext.Component} this */ focus : function(selectText, delay){ if(delay){ this.focus.defer(Ext.isNumber(delay) ? delay : 10, this, [selectText, false]); return; } if(this.rendered){ this.el.focus(); if(selectText === true){ this.el.dom.select(); } } return this; }, // private blur : function(){ if(this.rendered){ this.el.blur(); } return this; }, /** * Disable this component and fire the 'disable' event. * @return {Ext.Component} this */ disable : function(/* private */ silent){ if(this.rendered){ this.onDisable(); } this.disabled = true; if(silent !== true){ this.fireEvent('disable', this); } return this; }, // private onDisable : function(){ this.getActionEl().addClass(this.disabledClass); this.el.dom.disabled = true; }, /** * Enable this component and fire the 'enable' event. * @return {Ext.Component} this */ enable : function(){ if(this.rendered){ this.onEnable(); } this.disabled = false; this.fireEvent('enable', this); return this; }, // private onEnable : function(){ this.getActionEl().removeClass(this.disabledClass); this.el.dom.disabled = false; }, /** * Convenience function for setting disabled/enabled by boolean. * @param {Boolean} disabled * @return {Ext.Component} this */ setDisabled : function(disabled){ return this[disabled ? 'disable' : 'enable'](); }, /** * Show this component. Listen to the '{@link #beforeshow}' event and return * false to cancel showing the component. Fires the '{@link #show}' * event after showing the component. * @return {Ext.Component} this */ show : function(){ if(this.fireEvent('beforeshow', this) !== false){ this.hidden = false; if(this.autoRender){ this.render(Ext.isBoolean(this.autoRender) ? Ext.getBody() : this.autoRender); } if(this.rendered){ this.onShow(); } this.fireEvent('show', this); } return this; }, // private onShow : function(){ this.getVisibiltyEl().removeClass('x-hide-' + this.hideMode); }, /** * Hide this component. Listen to the '{@link #beforehide}' event and return * false to cancel hiding the component. Fires the '{@link #hide}' * event after hiding the component. Note this method is called internally if * the component is configured to be {@link #hidden}. * @return {Ext.Component} this */ hide : function(){ if(this.fireEvent('beforehide', this) !== false){ this.doHide(); this.fireEvent('hide', this); } return this; }, // private doHide: function(){ this.hidden = true; if(this.rendered){ this.onHide(); } }, // private onHide : function(){ this.getVisibiltyEl().addClass('x-hide-' + this.hideMode); }, // private getVisibiltyEl : function(){ return this.hideParent ? this.container : this.getActionEl(); }, /** * Convenience function to hide or show this component by boolean. * @param {Boolean} visible True to show, false to hide * @return {Ext.Component} this */ setVisible : function(visible){ return this[visible ? 'show' : 'hide'](); }, /** * Returns true if this component is visible. * @return {Boolean} True if this component is visible, false otherwise. */ isVisible : function(){ return this.rendered && this.getVisibiltyEl().isVisible(); }, /** * Clone the current component using the original config values passed into this instance by default. * @param {Object} overrides A new config containing any properties to override in the cloned version. * An id property can be passed on this object, otherwise one will be generated to avoid duplicates. * @return {Ext.Component} clone The cloned copy of this component */ cloneConfig : function(overrides){ overrides = overrides || {}; var id = overrides.id || Ext.id(); var cfg = Ext.applyIf(overrides, this.initialConfig); cfg.id = id; // prevent dup id return new this.constructor(cfg); }, /** * Gets the xtype for this component as registered with {@link Ext.ComponentMgr}. For a list of all * available xtypes, see the {@link Ext.Component} header. Example usage: *

var t = new Ext.form.TextField();
alert(t.getXType());  // alerts 'textfield'
* @return {String} The xtype */ getXType : function(){ return this.constructor.xtype; }, /** *

Tests whether or not this Component is of a specific xtype. This can test whether this Component is descended * from the xtype (default) or whether it is directly of the xtype specified (shallow = true).

*

If using your own subclasses, be aware that a Component must register its own xtype * to participate in determination of inherited xtypes.

*

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

*

Example usage:

*

var t = new Ext.form.TextField();
var isText = t.isXType('textfield');        // true
var isBoxSubclass = t.isXType('box');       // true, descended from BoxComponent
var isBoxInstance = t.isXType('box', true); // false, not a direct BoxComponent instance
* @param {String} xtype The xtype to check for this Component * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is * the default), or true to check whether this Component is directly of the specified xtype. * @return {Boolean} True if this component descends from the specified xtype, false otherwise. */ isXType : function(xtype, shallow){ //assume a string by default if (Ext.isFunction(xtype)){ xtype = xtype.xtype; //handle being passed the class, e.g. Ext.Component }else if (Ext.isObject(xtype)){ xtype = xtype.constructor.xtype; //handle being passed an instance } return !shallow ? ('/' + this.getXTypes() + '/').indexOf('/' + xtype + '/') != -1 : this.constructor.xtype == xtype; }, /** *

Returns this Component's xtype hierarchy as a slash-delimited string. For a list of all * available xtypes, see the {@link Ext.Component} header.

*

If using your own subclasses, be aware that a Component must register its own xtype * to participate in determination of inherited xtypes.

*

Example usage:

*

var t = new Ext.form.TextField();
alert(t.getXTypes());  // alerts 'component/box/field/textfield'
* @return {String} The xtype hierarchy string */ getXTypes : function(){ var tc = this.constructor; if(!tc.xtypes){ var c = [], sc = this; while(sc && sc.constructor.xtype){ c.unshift(sc.constructor.xtype); sc = sc.constructor.superclass; } tc.xtypeChain = c; tc.xtypes = c.join('/'); } return tc.xtypes; }, /** * Find a container above this component at any level by a custom function. If the passed function returns * true, the container will be returned. * @param {Function} fn The custom function to call with the arguments (container, this component). * @return {Ext.Container} The first Container for which the custom function returns true */ findParentBy : function(fn) { for (var p = this.ownerCt; (p != null) && !fn(p, this); p = p.ownerCt); return p || null; }, /** * Find a container above this component at any level by xtype or class * @param {String/Class} xtype The xtype string for a component, or the class of the component directly * @return {Ext.Container} The first Container which matches the given xtype or class */ findParentByType : function(xtype) { return Ext.isFunction(xtype) ? this.findParentBy(function(p){ return p.constructor === xtype; }) : this.findParentBy(function(p){ return p.constructor.xtype === xtype; }); }, getDomPositionEl : function(){ return this.getPositionEl ? this.getPositionEl() : this.getEl(); }, // private purgeListeners : function(){ Ext.Component.superclass.purgeListeners.call(this); if(this.mons){ this.on('beforedestroy', this.clearMons, this, {single: true}); } }, // private clearMons : function(){ Ext.each(this.mons, function(m){ m.item.un(m.ename, m.fn, m.scope); }, this); this.mons = []; }, // internal function for auto removal of assigned event handlers on destruction mon : function(item, ename, fn, scope, opt){ if(!this.mons){ this.mons = []; this.on('beforedestroy', this.clearMons, this, {single: true}); } if(Ext.isObject(ename)){ var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/; var o = ename; for(var e in o){ if(propRe.test(e)){ continue; } 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); }else{ // individual options 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 mun : function(item, ename, fn, scope){ var found, mon; 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){ this.mons.splice(i, 1); item.un(ename, fn, scope); found = true; break; } } return found; }, /** * Returns the next component in the owning container * @return Ext.Component */ nextSibling : function(){ if(this.ownerCt){ var index = this.ownerCt.items.indexOf(this); if(index != -1 && index+1 < this.ownerCt.items.getCount()){ return this.ownerCt.items.itemAt(index+1); } } return null; }, /** * Returns the previous component in the owning container * @return Ext.Component */ previousSibling : function(){ if(this.ownerCt){ var index = this.ownerCt.items.indexOf(this); if(index > 0){ return this.ownerCt.items.itemAt(index-1); } } return null; }, /** * Provides the link for Observable's fireEvent method to bubble up the ownership hierarchy. * @return {Ext.Container} the Container which owns this Component. */ getBubbleTarget : function(){ return this.ownerCt; } }); 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 * updates across any components that support the Action interface (primarily {@link Ext.Toolbar}, {@link Ext.Button} * and {@link Ext.menu.Menu} components).

*

Aside from supporting the config object interface, any component that needs to use Actions must also support * the following method list, as these will be called as needed by the Action class: setText(string), setIconCls(string), * setDisabled(boolean), setVisible(boolean) and setHandler(function).

* Example usage:
*

// Define the shared action.  Each component below will have the same
// display text and icon, and will display the same message on click.
var action = new Ext.Action({
    {@link #text}: 'Do something',
    {@link #handler}: function(){
        Ext.Msg.alert('Click', 'You did something.');
    },
    {@link #iconCls}: 'do-something',
    {@link #itemId}: 'myAction'
});

var panel = new Ext.Panel({
    title: 'Actions',
    width: 500,
    height: 300,
    tbar: [
        // Add the action directly to a toolbar as a menu button
        action,
        {
            text: 'Action Menu',
            // Add the action to a menu as a text item
            menu: [action]
        }
    ],
    items: [
        // Add the action to the panel body as a standard button
        new Ext.Button(action)
    ],
    renderTo: Ext.getBody()
});

// Change the text for all components using the action
action.setText('Something else');

// Reference an action through a container using the itemId
var btn = panel.getComponent('myAction');
var aRef = btn.baseAction;
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 = { /** * @cfg {String} text The text to set for all components using this action (defaults to ''). */ /** * @cfg {String} iconCls * The CSS class selector that specifies a background image to be used as the header icon for * all components using this action (defaults to ''). *

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


// specify the property in the config for the class:
     ...
     iconCls: 'do-something'

// css class that specifies background image to be used as the icon image:
.do-something { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
*/ /** * @cfg {Boolean} disabled True to disable all components using this action, false to enable them (defaults to false). */ /** * @cfg {Boolean} hidden True to hide all components using this action, false to show them (defaults to false). */ /** * @cfg {Function} handler The function that will be invoked by each component tied to this action * when the component's primary event is triggered (defaults to undefined). */ /** * @cfg {String} itemId * See {@link Ext.Component}.{@link Ext.Component#itemId itemId}. */ /** * @cfg {Object} scope The scope in which the {@link #handler} function will execute. */ // private isAction : true, /** * Sets the text to be displayed by all components using this action. * @param {String} text The text to display */ setText : function(text){ this.initialConfig.text = text; this.callEach('setText', [text]); }, /** * Gets the text currently displayed by all components using this action. */ getText : function(){ return this.initialConfig.text; }, /** * Sets the icon CSS class for all components using this action. The class should supply * a background image that will be used as the icon image. * @param {String} cls The CSS class supplying the icon image */ setIconClass : function(cls){ this.initialConfig.iconCls = cls; this.callEach('setIconClass', [cls]); }, /** * Gets the icon CSS class currently used by all components using this action. */ getIconClass : function(){ return this.initialConfig.iconCls; }, /** * Sets the disabled state of all components using this action. Shortcut method * for {@link #enable} and {@link #disable}. * @param {Boolean} disabled True to disable the component, false to enable it */ setDisabled : function(v){ this.initialConfig.disabled = v; this.callEach('setDisabled', [v]); }, /** * Enables all components using this action. */ enable : function(){ this.setDisabled(false); }, /** * Disables all components using this action. */ disable : function(){ this.setDisabled(true); }, /** * Returns true if the components using this action are currently disabled, else returns false. */ isDisabled : function(){ return this.initialConfig.disabled; }, /** * Sets the hidden state of all components using this action. Shortcut method * for {@link #hide} and {@link #show}. * @param {Boolean} hidden True to hide the component, false to show it */ setHidden : function(v){ this.initialConfig.hidden = v; this.callEach('setVisible', [!v]); }, /** * Shows all components using this action. */ show : function(){ this.setHidden(false); }, /** * Hides all components using this action. */ hide : function(){ this.setHidden(true); }, /** * Returns true if the components using this action are currently hidden, else returns false. */ isHidden : function(){ return this.initialConfig.hidden; }, /** * 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 */ setHandler : function(fn, scope){ this.initialConfig.handler = fn; this.initialConfig.scope = scope; this.callEach('setHandler', [fn, scope]); }, /** * 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 */ each : function(fn, scope){ Ext.each(this.items, fn, scope); }, // private callEach : function(fnName, args){ var cs = this.items; for(var i = 0, len = cs.length; i < len; i++){ cs[i][fnName].apply(cs[i], args); } }, // private addComponent : function(comp){ this.items.push(comp); comp.on('destroy', this.removeComponent, this); }, // private removeComponent : function(comp){ this.items.remove(comp); }, /** * Executes this action manually using the handler function specified in the original config object * or the handler function set with {@link #setHandler}. Any arguments passed to this * function will be passed on to the handler function. * @param {Mixed} arg1 (optional) Variable number of arguments passed to the handler function * @param {Mixed} arg2 (optional) * @param {Mixed} etc... (optional) */ execute : function(){ this.initialConfig.handler.apply(this.initialConfig.scope || window, arguments); } }; /** * @class Ext.Layer * @extends Ext.Element * An extended {@link Ext.Element} object that supports a shadow and shim, constrain to viewport and * automatic maintaining of shadow/shim positions. * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true) * @cfg {String/Boolean} shadow True to automatically create an {@link Ext.Shadow}, or a string indicating the * shadow's display {@link Ext.Shadow#mode}. False to disable the shadow. (defaults to false) * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: 'div', cls: 'x-layer'}). * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true) * @cfg {String} cls CSS class to add to the element * @cfg {Number} zindex Starting z-index (defaults to 11000) * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 4) * @cfg {Boolean} useDisplay * Defaults to use css offsets to hide the Layer. Specify true * to use css style 'display:none;' to hide the Layer. * @constructor * @param {Object} config An object with config options. * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it. */ (function(){ Ext.Layer = function(config, existingEl){ config = config || {}; var dh = Ext.DomHelper; var cp = config.parentEl, pel = cp ? Ext.getDom(cp) : document.body; if(existingEl){ this.dom = Ext.getDom(existingEl); } if(!this.dom){ var o = config.dh || {tag: 'div', cls: 'x-layer'}; this.dom = dh.append(pel, o); } if(config.cls){ this.addClass(config.cls); } this.constrain = config.constrain !== false; this.setVisibilityMode(Ext.Element.VISIBILITY); if(config.id){ this.id = this.dom.id = config.id; }else{ this.id = Ext.id(this.dom); } this.zindex = config.zindex || this.getZIndex(); this.position('absolute', this.zindex); if(config.shadow){ this.shadowOffset = config.shadowOffset || 4; this.shadow = new Ext.Shadow({ offset : this.shadowOffset, mode : config.shadow }); }else{ this.shadowOffset = 0; } this.useShim = config.shim !== false && Ext.useShims; this.useDisplay = config.useDisplay; this.hide(); }; var supr = Ext.Element.prototype; // shims are shared among layer to keep from having 100 iframes var shims = []; Ext.extend(Ext.Layer, Ext.Element, { getZIndex : function(){ return this.zindex || parseInt((this.getShim() || this).getStyle('z-index'), 10) || 11000; }, getShim : function(){ if(!this.useShim){ return null; } if(this.shim){ return this.shim; } var shim = shims.shift(); if(!shim){ shim = this.createShim(); shim.enableDisplayMode('block'); shim.dom.style.display = 'none'; shim.dom.style.visibility = 'visible'; } var pn = this.dom.parentNode; if(shim.dom.parentNode != pn){ pn.insertBefore(shim.dom, this.dom); } shim.setStyle('z-index', this.getZIndex()-2); this.shim = shim; return shim; }, hideShim : function(){ if(this.shim){ this.shim.setDisplayed(false); shims.push(this.shim); delete this.shim; } }, disableShadow : function(){ if(this.shadow){ this.shadowDisabled = true; this.shadow.hide(); this.lastShadowOffset = this.shadowOffset; this.shadowOffset = 0; } }, enableShadow : function(show){ if(this.shadow){ this.shadowDisabled = false; this.shadowOffset = this.lastShadowOffset; delete this.lastShadowOffset; if(show){ this.sync(true); } } }, // private // this code can execute repeatedly in milliseconds (i.e. during a drag) so // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls) sync : function(doShow){ var sw = this.shadow; if(!this.updating && this.isVisible() && (sw || this.useShim)){ var sh = this.getShim(); var w = this.getWidth(), h = this.getHeight(); var l = this.getLeft(true), t = this.getTop(true); if(sw && !this.shadowDisabled){ if(doShow && !sw.isVisible()){ sw.show(this); }else{ sw.realign(l, t, w, h); } if(sh){ if(doShow){ sh.show(); } // fit the shim behind the shadow, so it is shimmed too var a = sw.adjusts, s = sh.dom.style; s.left = (Math.min(l, l+a.l))+'px'; s.top = (Math.min(t, t+a.t))+'px'; s.width = (w+a.w)+'px'; s.height = (h+a.h)+'px'; } }else if(sh){ if(doShow){ sh.show(); } sh.setSize(w, h); sh.setLeftTop(l, t); } } }, // private destroy : function(){ this.hideShim(); if(this.shadow){ this.shadow.hide(); } this.removeAllListeners(); Ext.removeNode(this.dom); Ext.Element.uncache(this.id); }, remove : function(){ this.destroy(); }, // private beginUpdate : function(){ this.updating = true; }, // private endUpdate : function(){ this.updating = false; this.sync(true); }, // private hideUnders : function(negOffset){ if(this.shadow){ this.shadow.hide(); } this.hideShim(); }, // private constrainXY : function(){ if(this.constrain){ var vw = Ext.lib.Dom.getViewWidth(), vh = Ext.lib.Dom.getViewHeight(); var s = Ext.getDoc().getScroll(); var xy = this.getXY(); var x = xy[0], y = xy[1]; var so = this.shadowOffset; var w = this.dom.offsetWidth+so, h = this.dom.offsetHeight+so; // only move it if it needs it var moved = false; // first validate right/bottom if((x + w) > vw+s.left){ x = vw - w - so; moved = true; } if((y + h) > vh+s.top){ y = vh - h - so; moved = true; } // then make sure top/left isn't negative if(x < s.left){ x = s.left; moved = true; } if(y < s.top){ y = s.top; moved = true; } if(moved){ if(this.avoidY){ var ay = this.avoidY; if(y <= ay && (y+h) >= ay){ y = ay-h-5; } } xy = [x, y]; this.storeXY(xy); supr.setXY.call(this, xy); this.sync(); } } return this; }, isVisible : function(){ return this.visible; }, // private showAction : function(){ this.visible = true; // track visibility to prevent getStyle calls if(this.useDisplay === true){ this.setDisplayed(''); }else if(this.lastXY){ supr.setXY.call(this, this.lastXY); }else if(this.lastLT){ supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]); } }, // private hideAction : function(){ this.visible = false; if(this.useDisplay === true){ this.setDisplayed(false); }else{ this.setLeftTop(-10000,-10000); } }, // overridden Element method setVisible : function(v, a, d, c, e){ if(v){ this.showAction(); } if(a && v){ var cb = function(){ this.sync(true); if(c){ c(); } }.createDelegate(this); supr.setVisible.call(this, true, true, d, cb, e); }else{ if(!v){ this.hideUnders(true); } var cb = c; if(a){ cb = function(){ this.hideAction(); if(c){ c(); } }.createDelegate(this); } supr.setVisible.call(this, v, a, d, cb, e); if(v){ this.sync(true); }else if(!a){ this.hideAction(); } } return this; }, storeXY : function(xy){ delete this.lastLT; this.lastXY = xy; }, storeLeftTop : function(left, top){ delete this.lastXY; this.lastLT = [left, top]; }, // private beforeFx : function(){ this.beforeAction(); return Ext.Layer.superclass.beforeFx.apply(this, arguments); }, // private afterFx : function(){ Ext.Layer.superclass.afterFx.apply(this, arguments); this.sync(this.isVisible()); }, // private beforeAction : function(){ if(!this.updating && this.shadow){ this.shadow.hide(); } }, // overridden Element method setLeft : function(left){ this.storeLeftTop(left, this.getTop(true)); supr.setLeft.apply(this, arguments); this.sync(); return this; }, setTop : function(top){ this.storeLeftTop(this.getLeft(true), top); supr.setTop.apply(this, arguments); this.sync(); return this; }, setLeftTop : function(left, top){ this.storeLeftTop(left, top); supr.setLeftTop.apply(this, arguments); this.sync(); return this; }, setXY : function(xy, a, d, c, e){ this.fixDisplay(); this.beforeAction(); this.storeXY(xy); var cb = this.createCB(c); supr.setXY.call(this, xy, a, d, cb, e); if(!a){ cb(); } return this; }, // private createCB : function(c){ var el = this; return function(){ el.constrainXY(); el.sync(true); if(c){ c(); } }; }, // overridden Element method setX : function(x, a, d, c, e){ this.setXY([x, this.getY()], a, d, c, e); return this; }, // overridden Element method setY : function(y, a, d, c, e){ this.setXY([this.getX(), y], a, d, c, e); return this; }, // overridden Element method setSize : function(w, h, a, d, c, e){ this.beforeAction(); var cb = this.createCB(c); supr.setSize.call(this, w, h, a, d, cb, e); if(!a){ cb(); } return this; }, // overridden Element method setWidth : function(w, a, d, c, e){ this.beforeAction(); var cb = this.createCB(c); supr.setWidth.call(this, w, a, d, cb, e); if(!a){ cb(); } return this; }, // overridden Element method setHeight : function(h, a, d, c, e){ this.beforeAction(); var cb = this.createCB(c); supr.setHeight.call(this, h, a, d, cb, e); if(!a){ cb(); } return this; }, // overridden Element method setBounds : function(x, y, w, h, a, d, c, e){ this.beforeAction(); var cb = this.createCB(c); if(!a){ this.storeXY([x, y]); supr.setXY.call(this, [x, y]); supr.setSize.call(this, w, h, a, d, cb, e); cb(); }else{ supr.setBounds.call(this, x, y, w, h, a, d, cb, e); } return this; }, /** * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index). * @param {Number} zindex The new z-index to set * @return {this} The Layer */ setZIndex : function(zindex){ this.zindex = zindex; this.setStyle('z-index', zindex + 2); if(this.shadow){ this.shadow.setZIndex(zindex + 1); } if(this.shim){ this.shim.setStyle('z-index', zindex); } 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 * functionality that can also provide the same shadow effect, see the {@link Ext.Layer} class. * @constructor * Create a new Shadow * @param {Object} config The config object */ Ext.Shadow = function(config){ Ext.apply(this, config); if(typeof this.mode != "string"){ this.mode = this.defaultMode; } var o = this.offset, a = {h: 0}; var rad = Math.floor(this.offset/2); switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows case "drop": a.w = 0; a.l = a.t = o; a.t -= 1; if(Ext.isIE){ a.l -= this.offset + rad; a.t -= this.offset + rad; a.w -= rad; a.h -= rad; a.t += 1; } break; case "sides": a.w = (o*2); a.l = -o; a.t = o-1; if(Ext.isIE){ a.l -= (this.offset - rad); a.t -= this.offset + rad; a.l += 1; a.w -= (this.offset - rad)*2; a.w -= rad + 1; a.h -= 1; } break; case "frame": a.w = a.h = (o*2); a.l = a.t = -o; a.t += 1; a.h -= 2; if(Ext.isIE){ a.l -= (this.offset - rad); a.t -= (this.offset - rad); a.l += 1; a.w -= (this.offset + rad + 1); a.h -= (this.offset + rad); a.h += 1; } break; }; this.adjusts = a; }; Ext.Shadow.prototype = { /** * @cfg {String} mode * The shadow display mode. Supports the following options:
*/ /** * @cfg {String} offset * The number of pixels to offset the shadow from the element (defaults to 4) */ offset: 4, // private defaultMode: "drop", /** * Displays the shadow under the target element * @param {Mixed} targetEl The id or element under which the shadow should display */ show : function(target){ target = Ext.get(target); if(!this.el){ this.el = Ext.Shadow.Pool.pull(); if(this.el.dom.nextSibling != target.dom){ this.el.insertBefore(target); } } this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1); if(Ext.isIE){ this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")"; } this.realign( target.getLeft(true), target.getTop(true), target.getWidth(), target.getHeight() ); this.el.dom.style.display = "block"; }, /** * Returns true if the shadow is visible, else false */ isVisible : function(){ return this.el ? true : false; }, /** * Direct alignment when values are already available. Show must be called at least once before * calling this method to ensure it is initialized. * @param {Number} left The target element left position * @param {Number} top The target element top position * @param {Number} width The target element width * @param {Number} height The target element height */ realign : function(l, t, w, h){ if(!this.el){ return; } var a = this.adjusts, d = this.el.dom, s = d.style; var iea = 0; s.left = (l+a.l)+"px"; s.top = (t+a.t)+"px"; var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px"; if(s.width != sws || s.height != shs){ s.width = sws; s.height = shs; if(!Ext.isIE){ var cn = d.childNodes; var sww = Math.max(0, (sw-12))+"px"; cn[0].childNodes[1].style.width = sww; cn[1].childNodes[1].style.width = sww; cn[2].childNodes[1].style.width = sww; cn[1].style.height = Math.max(0, (sh-12))+"px"; } } }, /** * Hides this shadow */ hide : function(){ if(this.el){ this.el.dom.style.display = "none"; Ext.Shadow.Pool.push(this.el); delete this.el; } }, /** * Adjust the z-index of this shadow * @param {Number} zindex The new z-index */ setZIndex : function(z){ this.zIndex = z; if(this.el){ this.el.setStyle("z-index", z); } } }; // Private utility class that manages the internal Shadow cache Ext.Shadow.Pool = function(){ var p = []; var markup = Ext.isIE ? '
' : '
'; return { pull : function(){ var sh = p.shift(); if(!sh){ sh = Ext.get(Ext.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup)); sh.autoBoxAdjust = false; } return sh; }, push : function(sh){ p.push(sh); } }; }();/** * @class Ext.BoxComponent * @extends Ext.Component *

Base class for any {@link Ext.Component Component} that is to be sized as a box, using width and height.

*

BoxComponent provides automatic box model adjustments for sizing and positioning and will work correctly * within the Component rendering model.

*

A BoxComponent may be created as a custom Component which encapsulates any HTML element, either a pre-existing * element, or one that is created to your specifications at render time. Usually, to participate in layouts, * a Component will need to be a BoxComponent in order to have its width and height managed.

*

To use a pre-existing element as a BoxComponent, configure it so that you preset the el property to the * element to reference:


var pageHeader = new Ext.BoxComponent({
    el: 'my-header-div'
});
* This may then be {@link Ext.Container#add added} to a {@link Ext.Container Container} as a child item.

*

To create a BoxComponent based around a HTML element to be created at render time, use the * {@link Ext.Component#autoEl autoEl} config option which takes the form of a * {@link Ext.DomHelper DomHelper} specification:


var myImage = new Ext.BoxComponent({
    autoEl: {
        tag: 'img',
        src: '/images/my-image.jpg'
    }
});

* @constructor * @param {Ext.Element/String/Object} config The configuration options. * @xtype box */ Ext.BoxComponent = Ext.extend(Ext.Component, { // 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 * by a Container which has been configured to use the {@link Ext.layout.BorderLayout BorderLayout} * layout manager (e.g. specifying layout:'border').


*

See {@link Ext.layout.BorderLayout} also.

*/ // margins config is used when a BoxComponent is rendered by BorderLayout or BoxLayout. /** * @cfg {Object} margins

Note: this config is only used when this BoxComponent is rendered * by a Container which has been configured to use the {@link Ext.layout.BorderLayout BorderLayout} * or one of the two {@link Ext.layout.BoxLayout BoxLayout} subclasses.

*

An object containing margins to apply to this BoxComponent in the * format:


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

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

*

*

Defaults to:


     * {top:0, right:0, bottom:0, left:0}
     * 
*/ /** * @cfg {Number} x * The local x (left) coordinate for this component if contained within a positioning container. */ /** * @cfg {Number} y * The local y (top) coordinate for this component if contained within a positioning container. */ /** * @cfg {Number} pageX * The page level x coordinate for this component if contained within a positioning container. */ /** * @cfg {Number} pageY * The page level y coordinate for this component if contained within a positioning container. */ /** * @cfg {Number} height * The height 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} width * 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 {Boolean} autoHeight *

True to use height:'auto', false to use fixed height (or allow it to be managed by its parent * Container's {@link Ext.Container#layout layout manager}. Defaults to false.

*

Note: Although many components inherit this config option, not all will * function as expected with a height of 'auto'. Setting autoHeight:true means that the * browser will manage height based on the element's contents, and that Ext will not manage it at all.

*

If the browser is managing the height, be aware that resizes performed by the browser in response * to changes within the structure of the Component cannot be detected. Therefore changes to the height might * result in elements needing to be synchronized with the new height. Example:


var w = new Ext.Window({
    title: 'Window',
    width: 600,
    autoHeight: true,
    items: {
        title: 'Collapse Me',
        height: 400,
        collapsible: true,
        border: false,
        listeners: {
            beforecollapse: function() {
                w.el.shadow.hide();
            },
            beforeexpand: function() {
                w.el.shadow.hide();
            },
            collapse: function() {
                w.syncShadow();
            },
            expand: function() {
                w.syncShadow();
            }
        }
    }
}).show();
*/ /** * @cfg {Boolean} autoWidth *

True to use width:'auto', false to use fixed width (or allow it to be managed by its parent * Container's {@link Ext.Container#layout layout manager}. Defaults to false.

*

Note: Although many components inherit this config option, not all will * function as expected with a width of 'auto'. Setting autoWidth:true means that the * browser will manage width based on the element's contents, and that Ext will not manage it at all.

*

If the browser is managing the width, be aware that resizes performed by the browser in response * to changes within the structure of the Component cannot be detected. Therefore changes to the width might * result in elements needing to be synchronized with the new width. For example, where the target element is:


<div id='grid-container' style='margin-left:25%;width:50%'></div>
* A Panel rendered into that target element must listen for browser window resize in order to relay its * child items when the browser changes its width:

var myPanel = new Ext.Panel({
    renderTo: 'grid-container',
    monitorResize: true, // relay on browser resize
    title: 'Panel',
    height: 400,
    autoWidth: true,
    layout: 'hbox',
    layoutConfig: {
        align: 'stretch'
    },
    defaults: {
        flex: 1
    },
    items: [{
        title: 'Box 1',
    }, {
        title: 'Box 2'
    }, {
        title: 'Box 3'
    }],
});
*/ /* // private internal config * {Boolean} deferHeight * True to defer height calculations to an external component, false to allow this component to set its own * height (defaults to false). */ // private initComponent : function(){ Ext.BoxComponent.superclass.initComponent.call(this); this.addEvents( /** * @event resize * Fires after the component is resized. * @param {Ext.Component} this * @param {Number} adjWidth The box-adjusted width that was set * @param {Number} adjHeight The box-adjusted height that was set * @param {Number} rawWidth The width that was originally specified * @param {Number} rawHeight The height that was originally specified */ 'resize', /** * @event move * Fires after the component is moved. * @param {Ext.Component} this * @param {Number} x The new x position * @param {Number} y The new y position */ 'move' ); }, // private, set in afterRender to signify that the component has been rendered boxReady : false, // private, used to defer height settings to subclasses deferHeight: false, /** * Sets the width and height of this BoxComponent. This method fires the {@link #resize} event. This method can accept * either width and height as separate arguments, or you can pass a size object like {width:10, height:20}. * @param {Mixed} width The new width to set. This may be one of:
* @param {Mixed} height The new height to set (not required if a size object is passed as the first arg). * This may be one of:
* @return {Ext.BoxComponent} this */ setSize : function(w, h){ // support for standard size objects if(typeof w == 'object'){ h = w.height; w = w.width; } // not rendered if(!this.boxReady){ this.width = w; this.height = h; return this; } // prevent recalcs when not needed if(this.cacheSizes !== false && this.lastSize && this.lastSize.width == w && this.lastSize.height == h){ return this; } this.lastSize = {width: w, height: h}; var adj = this.adjustSize(w, h); var aw = adj.width, ah = adj.height; if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters var rz = this.getResizeEl(); if(!this.deferHeight && aw !== undefined && ah !== undefined){ rz.setSize(aw, ah); }else if(!this.deferHeight && ah !== undefined){ rz.setHeight(ah); }else if(aw !== undefined){ rz.setWidth(aw); } this.onResize(aw, ah, w, h); this.fireEvent('resize', this, aw, ah, w, h); } return this; }, /** * Sets the width of the component. This method fires the {@link #resize} event. * @param {Number} width The new width to setThis may be one of:
* @return {Ext.BoxComponent} this */ setWidth : function(width){ return this.setSize(width); }, /** * Sets the height of the component. This method fires the {@link #resize} event. * @param {Number} height The new height to set. This may be one of:
* @return {Ext.BoxComponent} this */ setHeight : function(height){ return this.setSize(undefined, height); }, /** * Gets the current size of the component's underlying element. * @return {Object} An object containing the element's size {width: (element width), height: (element height)} */ getSize : function(){ return this.getResizeEl().getSize(); }, /** * Gets the current width of the component's underlying element. * @return {Number} */ getWidth : function(){ return this.getResizeEl().getWidth(); }, /** * Gets the current height of the component's underlying element. * @return {Number} */ getHeight : function(){ return this.getResizeEl().getHeight(); }, /** * Gets the current size of the component's underlying element, including space taken by its margins. * @return {Object} An object containing the element's size {width: (element width + left/right margins), height: (element height + top/bottom margins)} */ getOuterSize : function(){ var el = this.getResizeEl(); return {width: el.getWidth() + el.getMargins('lr'), height: el.getHeight() + el.getMargins('tb')}; }, /** * Gets the current XY position of the component's underlying element. * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false) * @return {Array} The XY position of the element (e.g., [100, 200]) */ getPosition : function(local){ var el = this.getPositionEl(); if(local === true){ return [el.getLeft(true), el.getTop(true)]; } return this.xy || el.getXY(); }, /** * Gets the current box measurements of the component's underlying element. * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false) * @return {Object} box An object in the format {x, y, width, height} */ getBox : function(local){ var pos = this.getPosition(local); var s = this.getSize(); s.x = pos[0]; s.y = pos[1]; return s; }, /** * Sets the current box measurements of the component's underlying element. * @param {Object} box An object in the format {x, y, width, height} * @return {Ext.BoxComponent} this */ updateBox : function(box){ this.setSize(box.width, box.height); this.setPagePosition(box.x, box.y); return this; }, /** *

Returns the outermost Element of this Component which defines the Components overall size.

*

Usually this will return the same Element as {@link #getEl}, * but in some cases, a Component may have some more wrapping Elements around its main * active Element.

*

An example is a ComboBox. It is encased in a wrapping Element which * 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. */ getResizeEl : function(){ return this.resizeEl || this.el; }, // protected getPositionEl : function(){ return this.positionEl || this.el; }, /** * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}. * This method fires the {@link #move} event. * @param {Number} left The new left * @param {Number} top The new top * @return {Ext.BoxComponent} this */ setPosition : function(x, y){ if(x && typeof x[1] == 'number'){ y = x[1]; x = x[0]; } this.x = x; this.y = y; if(!this.boxReady){ return this; } var adj = this.adjustPosition(x, y); var ax = adj.x, ay = adj.y; var el = this.getPositionEl(); if(ax !== undefined || ay !== undefined){ if(ax !== undefined && ay !== undefined){ el.setLeftTop(ax, ay); }else if(ax !== undefined){ el.setLeft(ax); }else if(ay !== undefined){ el.setTop(ay); } this.onPosition(ax, ay); this.fireEvent('move', this, ax, ay); } return this; }, /** * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}. * This method fires the {@link #move} event. * @param {Number} x The new x position * @param {Number} y The new y position * @return {Ext.BoxComponent} this */ setPagePosition : function(x, y){ if(x && typeof x[1] == 'number'){ y = x[1]; x = x[0]; } this.pageX = x; this.pageY = y; if(!this.boxReady){ return; } if(x === undefined || y === undefined){ // cannot translate undefined points return; } var p = this.getPositionEl().translatePoints(x, y); this.setPosition(p.left, p.top); return this; }, // private onRender : function(ct, position){ Ext.BoxComponent.superclass.onRender.call(this, ct, position); 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; this.setSize(this.width, this.height); if(this.x || this.y){ this.setPosition(this.x, this.y); }else if(this.pageX || this.pageY){ this.setPagePosition(this.pageX, this.pageY); } }, /** * Force the component's size to recalculate based on the underlying element's current height and width. * @return {Ext.BoxComponent} this */ syncSize : function(){ delete this.lastSize; this.setSize(this.autoWidth ? undefined : this.getResizeEl().getWidth(), this.autoHeight ? undefined : this.getResizeEl().getHeight()); return this; }, /* // protected * Called after the component is resized, this method is empty by default but can be implemented by any * subclass that needs to perform custom logic after a resize occurs. * @param {Number} adjWidth The box-adjusted width that was set * @param {Number} adjHeight The box-adjusted height that was set * @param {Number} rawWidth The width that was originally specified * @param {Number} rawHeight The height that was originally specified */ onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){ }, /* // protected * Called after the component is moved, this method is empty by default but can be implemented by any * subclass that needs to perform custom logic after a move occurs. * @param {Number} x The new x position * @param {Number} y The new y position */ onPosition : function(x, y){ }, // private adjustSize : function(w, h){ if(this.autoWidth){ w = 'auto'; } if(this.autoHeight){ h = 'auto'; } return {width : w, height: h}; }, // private adjustPosition : function(x, y){ return {x : x, y: y}; } }); Ext.reg('box', Ext.BoxComponent); /** * @class Ext.Spacer * @extends Ext.BoxComponent *

Used to provide a sizable space in a layout.

* @constructor * @param {Object} config */ Ext.Spacer = Ext.extend(Ext.BoxComponent, { autoEl:'div' }); Ext.reg('spacer', Ext.Spacer);/** * @class Ext.SplitBar * @extends Ext.util.Observable * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized). *

* Usage: *

var split = new Ext.SplitBar("elementToDrag", "elementToSize",
                   Ext.SplitBar.HORIZONTAL, Ext.SplitBar.LEFT);
split.setAdapter(new Ext.SplitBar.AbsoluteLayoutAdapter("container"));
split.minSize = 100;
split.maxSize = 600;
split.animate = true;
split.on('moved', splitterMoved);
* @constructor * Create a new SplitBar * @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 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"; /** @private */ this.resizingEl = Ext.get(resizingElement, true); /** * @private * The orientation of the split. Either Ext.SplitBar.HORIZONTAL or Ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL) * Note: If this is changed after creating the SplitBar, the placement property must be manually updated * @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 * @property tickSize */ /** * The minimum size of the resizing element. (Defaults to 0) * @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); }else{ this.proxy = Ext.get(existingProxy).dom; } /** @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); this.el.addClass("x-splitbar-h"); }else{ /** @private */ 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 * Fires when the splitter is moved (alias for {@link #moved}) * @param {Ext.SplitBar} this * @param {Number} newSize the new width or height */ "resize", /** * @event moved * Fires when the splitter is moved * @param {Ext.SplitBar} this * @param {Number} newSize the new width or height */ "moved", /** * @event beforeresize * Fires before the splitter is dragged * @param {Ext.SplitBar} this */ "beforeresize", "beforeapply" ); Ext.SplitBar.superclass.constructor.call(this); }; Ext.extend(Ext.SplitBar, Ext.util.Observable, { onStartProxyDrag : function(x, y){ this.fireEvent("beforeresize", this); this.overlay = Ext.DomHelper.append(document.body, {cls: "x-drag-overlay", html: " "}, true); this.overlay.unselectable(); this.overlay.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true)); this.overlay.show(); Ext.get(this.proxy).setDisplayed("block"); var size = this.adapter.getElementSize(this); this.activeMinSize = this.getMinimumSize(); this.activeMaxSize = this.getMaximumSize(); var c1 = size - this.activeMinSize; var c2 = Math.max(this.activeMaxSize - size, 0); if(this.orientation == Ext.SplitBar.HORIZONTAL){ this.dd.resetConstraints(); this.dd.setXConstraint( this.placement == Ext.SplitBar.LEFT ? c1 : c2, this.placement == Ext.SplitBar.LEFT ? c2 : c1, this.tickSize ); this.dd.setYConstraint(0, 0); }else{ this.dd.resetConstraints(); this.dd.setXConstraint(0, 0); this.dd.setYConstraint( this.placement == Ext.SplitBar.TOP ? c1 : c2, this.placement == Ext.SplitBar.TOP ? c2 : c1, this.tickSize ); } this.dragSpecs.startSize = size; 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){ Ext.get(this.proxy).setDisplayed(false); var endPoint = Ext.lib.Event.getXY(e); if(this.overlay){ Ext.destroy(this.overlay); delete this.overlay; } var newSize; if(this.orientation == Ext.SplitBar.HORIZONTAL){ 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 + (this.placement == Ext.SplitBar.TOP ? endPoint[1] - this.dragSpecs.startPoint[1] : this.dragSpecs.startPoint[1] - endPoint[1] ); } newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize); if(newSize != this.dragSpecs.startSize){ if(this.fireEvent('beforeapply', this, newSize) !== false){ this.adapter.setElementSize(this, newSize); this.fireEvent("moved", this, newSize); this.fireEvent("resize", this, newSize); } } }, /** * Get the adapter this SplitBar uses * @return The adapter object */ getAdapter : function(){ return this.adapter; }, /** * Set the adapter this SplitBar uses * @param {Object} adapter A SplitBar adapter object */ setAdapter : function(adapter){ this.adapter = adapter; this.adapter.init(this); }, /** * Gets the minimum size for the resizing element * @return {Number} The minimum size */ getMinimumSize : function(){ return this.minSize; }, /** * Sets the minimum size for the resizing element * @param {Number} minSize The minimum size */ setMinimumSize : function(minSize){ this.minSize = minSize; }, /** * Gets the maximum size for the resizing element * @return {Number} The maximum size */ getMaximumSize : function(){ return this.maxSize; }, /** * Sets the maximum size for the resizing element * @param {Number} maxSize The maximum size */ setMaximumSize : function(maxSize){ this.maxSize = maxSize; }, /** * Sets the initialize size for the resizing element * @param {Number} size The initial size */ setCurrentSize : function(size){ var oldAnimate = this.animate; this.animate = false; this.adapter.setElementSize(this, size); this.animate = oldAnimate; }, /** * Destroy this splitbar. * @param {Boolean} removeEl True to remove the element */ destroy : function(removeEl){ Ext.destroy(this.shim, Ext.get(this.proxy)); this.dd.unreg(); if(removeEl){ this.el.remove(); } this.purgeListeners(); } }); /** * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color. */ Ext.SplitBar.createProxy = function(dir){ var proxy = new Ext.Element(document.createElement("div")); 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. */ 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. * @param {Ext.SplitBar} s The SplitBar using this adapter */ getElementSize : function(s){ if(s.orientation == Ext.SplitBar.HORIZONTAL){ return s.resizingEl.getWidth(); }else{ 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 * @param {Number} newSize The new size to set * @param {Function} onComplete A function to be invoked when resizing is complete */ setElementSize : function(s, newSize, onComplete){ if(s.orientation == Ext.SplitBar.HORIZONTAL){ if(!s.animate){ s.resizingEl.setWidth(newSize); if(onComplete){ onComplete(s, newSize); } }else{ s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut'); } }else{ if(!s.animate){ s.resizingEl.setHeight(newSize); if(onComplete){ onComplete(s, newSize); } }else{ s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut'); } } } }; /** *@class Ext.SplitBar.AbsoluteLayoutAdapter * @extends Ext.SplitBar.BasicLayoutAdapter * 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. */ Ext.SplitBar.AbsoluteLayoutAdapter = function(container){ this.basic = new Ext.SplitBar.BasicLayoutAdapter(); this.container = Ext.get(container); }; 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){ case yes.LEFT: s.el.setX(s.resizingEl.getRight()); break; case yes.RIGHT: s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px"); break; case yes.TOP: s.el.setY(s.resizingEl.getBottom()); break; case yes.BOTTOM: s.el.setY(s.resizingEl.getTop() - s.el.getHeight()); break; } } }; /** * Orientation constant - Create a vertical SplitBar * @static * @type Number */ Ext.SplitBar.VERTICAL = 1; /** * Orientation constant - Create a horizontal SplitBar * @static * @type Number */ Ext.SplitBar.HORIZONTAL = 2; /** * Placement constant - The resizing element is to the left of the splitter element * @static * @type Number */ Ext.SplitBar.LEFT = 1; /** * Placement constant - The resizing element is to the right of the splitter element * @static * @type Number */ Ext.SplitBar.RIGHT = 2; /** * Placement constant - The resizing element is positioned above the splitter element * @static * @type Number */ Ext.SplitBar.TOP = 3; /** * Placement constant - The resizing element is positioned under splitter element * @static * @type Number */ Ext.SplitBar.BOTTOM = 4; /** * @class Ext.Container * @extends Ext.BoxComponent *

Base class for any {@link Ext.BoxComponent} that may contain other Components. Containers handle the * basic behavior of containing items, namely adding, inserting and removing items.

* *

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 * 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:


// explicitly create a Container
var embeddedColumns = new Ext.Container({
    autoEl: 'div',  // This is the default
    layout: 'column',
    defaults: {
        // implicitly create Container by specifying xtype
        xtype: 'container',
        autoEl: 'div', // This is the default.
        layout: 'form',
        columnWidth: 0.5,
        style: {
            padding: '10px'
        }
    },
//  The two items below will be Ext.Containers, each encapsulated by a <DIV> element.
    items: [{
        items: {
            xtype: 'datefield',
            name: 'startDate',
            fieldLabel: 'Start date'
        }
    }, {
        items: {
            xtype: 'datefield',
            name: 'endDate',
            fieldLabel: 'End date'
        }
    }]
});

* *

Layout

*

Container classes delegate the rendering of child Components to a layout * manager class which must be configured into the Container using the * {@link #layout} configuration property.

*

When either specifying child {@link #items} of a Container, * or dynamically {@link #add adding} Components to a Container, remember to * consider how you wish the Container to arrange those child elements, and * whether those child elements need to be sized using one of Ext's built-in * {@link #layout} schemes. By default, Containers use the * {@link Ext.layout.ContainerLayout ContainerLayout} scheme which only * renders child components, appending them one after the other inside the * 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} * 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 * is resized.

*

Certain layout managers allow dynamic addition of child components. * Those that do include {@link Ext.layout.CardLayout}, * {@link Ext.layout.AnchorLayout}, {@link Ext.layout.FormLayout}, and * {@link Ext.layout.TableLayout}. For example:


//  Create the GridPanel.
var myNewGrid = new Ext.grid.GridPanel({
    store: myStore,
    columns: myColumnModel,
    title: 'Results', // the title becomes the title of the tab
});

myTabPanel.add(myNewGrid); // {@link Ext.TabPanel} implicitly uses {@link Ext.layout.CardLayout CardLayout}
myTabPanel.{@link Ext.TabPanel#setActiveTab setActiveTab}(myNewGrid);
 * 

*

The example above adds a newly created GridPanel to a TabPanel. Note that * a TabPanel uses {@link Ext.layout.CardLayout} as its layout manager which * means all its child items are sized to {@link Ext.layout.FitLayout fit} * exactly into its client area. *

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 * 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 * GridPanel will not be sized as expected.

* *

Adding via remote configuration

* *

A server side script can be used to add Components which are generated dynamically on the server. * An example of adding a GridPanel to a TabPanel where the GridPanel is generated by the server * based on certain parameters: *


// execute an Ajax request to invoke server side script:
Ext.Ajax.request({
    url: 'gen-invoice-grid.php',
    // send additional parameters to instruct server script
    params: {
        startDate: Ext.getCmp('start-date').getValue(),
        endDate: Ext.getCmp('end-date').getValue()
    },
    // process the response object to add it to the TabPanel:
    success: function(xhr) {
        var newComponent = eval(xhr.responseText); // see discussion below
        myTabPanel.add(newComponent); // add the component to the TabPanel
        myTabPanel.setActiveTab(newComponent);
    },
    failure: function() {
        Ext.Msg.alert("Grid create failed", "Server communication failure");
    }
});
*

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}, * or an instantiated Component. The server might return this for example:


(function() {
    function formatDate(value){
        return value ? value.dateFormat('M d, Y') : '';
    };

    var store = new Ext.data.Store({
        url: 'get-invoice-data.php',
        baseParams: {
            startDate: '01/01/2008',
            endDate: '01/31/2008'
        },
        reader: new Ext.data.JsonReader({
            record: 'transaction',
            idProperty: 'id',
            totalRecords: 'total'
        }, [
           'customer',
           'invNo',
           {name: 'date', type: 'date', dateFormat: 'm/d/Y'},
           {name: 'value', type: 'float'}
        ])
    });

    var grid = new Ext.grid.GridPanel({
        title: 'Invoice Report',
        bbar: new Ext.PagingToolbar(store),
        store: store,
        columns: [
            {header: "Customer", width: 250, dataIndex: 'customer', sortable: true},
            {header: "Invoice Number", width: 120, dataIndex: 'invNo', sortable: true},
            {header: "Invoice Date", width: 100, dataIndex: 'date', renderer: formatDate, sortable: true},
            {header: "Value", width: 120, dataIndex: 'value', renderer: 'usMoney', sortable: true}
        ],
    });
    store.load();
    return grid;  // return instantiated component
})();
*

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

* * @xtype container */ Ext.Container = Ext.extend(Ext.BoxComponent, { /** * @cfg {Boolean} monitorResize * True to automatically monitor window resize events to handle anything that is sensitive to the current size * of the viewport. This value is typically managed by the chosen {@link #layout} and should not need * to be set manually. */ /** * @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:

new Ext.Window({
    width:300, height: 300,
    layout: 'fit', // explicitly set layout manager: override the default (layout:'auto')
    items: [{
        title: 'Panel inside a 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:

*
*/ /** * @cfg {Object} layoutConfig * This is a config object containing properties specific to the chosen * {@link #layout} if {@link #layout} * has been specified as a string.

*/ /** * @cfg {Boolean/Number} bufferResize * When set to true (100 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. */ bufferResize: 100, /** * @cfg {String/Number} activeItem * A string component id or the numeric index of the component that should be initially activated within the * container's layout on render. For example, activeItem: 'item-1' or activeItem: 0 (index 0 = the first * item in the container's collection). activeItem only applies to layout styles that can display * items one at a time (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout} and * {@link Ext.layout.FitLayout}). Related to {@link Ext.layout.ContainerLayout#activeItem}. */ /** * @cfg {Object/Array} items *
** IMPORTANT: be sure to specify a {@link #layout} ! **
*

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

*

// specifying a single item
items: {...},
layout: 'fit',    // specify a layout!

// specifying multiple items
items: [{...}, {...}],
layout: 'anchor', // specify a layout!
     * 
*

Each item may be:

*
*

Notes:

*
*/ /** * @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:


defaults: {               // defaults are applied to items, not the container
    autoScroll:true
},
items: [
    {
        xtype: 'panel',   // defaults do not have precedence over
        id: 'panel1',     // options in config objects, so the defaults
        autoScroll: false // will not be applied here, panel1 will be autoScroll:false
    },
    new Ext.Panel({       // defaults do have precedence over options
        id: 'panel2',     // options in components, so the defaults
        autoScroll: false // will be applied here, panel2 will be autoScroll:true.
    })
]
     * 
*/ /** @cfg {Boolean} autoDestroy * If true the container will automatically destroy any contained component that is removed from it, else * destruction must be handled manually (defaults to true). */ autoDestroy : true, /** @cfg {Boolean} forceLayout * If true the container will force a layout initially even if hidden or collapsed. This option * is useful for forcing forms to render in collapsed or hidden containers. (defaults to false). */ forceLayout: false, /** @cfg {Boolean} hideBorders * True to hide the borders of each contained component, false to defer to the component's existing * border settings (defaults to false). */ /** @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'.

*/ defaultType : 'panel', // private initComponent : function(){ Ext.Container.superclass.initComponent.call(this); this.addEvents( /** * @event afterlayout * Fires when the components in this container are arranged by the associated layout manager. * @param {Ext.Container} this * @param {ContainerLayout} layout The ContainerLayout implementation for this container */ 'afterlayout', /** * @event beforeadd * Fires before any {@link Ext.Component} is added or inserted into the container. * A handler can return false to cancel the add. * @param {Ext.Container} this * @param {Ext.Component} component The component being added * @param {Number} index The index at which the component will be added to the container's items collection */ 'beforeadd', /** * @event beforeremove * Fires before any {@link Ext.Component} is removed from the container. A handler can return * false to cancel the remove. * @param {Ext.Container} this * @param {Ext.Component} component The component being removed */ 'beforeremove', /** * @event add * @bubbles * Fires after any {@link Ext.Component} is added or inserted into the container. * @param {Ext.Container} this * @param {Ext.Component} component The component that was added * @param {Number} index The index at which the component was added to the container's items collection */ 'add', /** * @event remove * @bubbles * Fires after any {@link Ext.Component} is removed from the container. * @param {Ext.Container} this * @param {Ext.Component} component The component that was removed */ 'remove' ); this.enableBubble('add', 'remove'); /** * The collection of components in this container as a {@link Ext.util.MixedCollection} * @type MixedCollection * @property 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); } } }, // private initItems : function(){ if(!this.items){ this.items = new Ext.util.MixedCollection(false, this.getComponentId); this.getLayout(); // initialize the layout } }, // private setLayout : function(layout){ if(this.layout && this.layout != layout){ this.layout.setContainer(null); } this.initItems(); this.layout = layout; 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); if(this.activeItem !== undefined){ var item = this.activeItem; delete this.activeItem; this.layout.setActiveItem(item); } } if(!this.ownerCt){ // force a layout if no ownerCt is set this.doLayout(false, true); } if(this.monitorResize === true){ Ext.EventManager.onWindowResize(this.doLayout, this, [false]); } }, /** *

Returns the Element to be used to contain the child Components of this Container.

*

An implementation is provided which returns the Container's {@link #getEl Element}, but * if there is a more complex structure to a Container, this may be overridden to return * the element into which the {@link #layout layout} renders child Components.

* @return {Ext.Element} The Element to render child Components into. */ getLayoutTarget : function(){ return this.el; }, // private - used as the key lookup function for the items collection getComponentId : function(comp){ return comp.getItemId(); }, /** *

Adds {@link Ext.Component Component}(s) to this Container.

*

Description : *

*

Notes : *

* @param {Object/Array} component *

Either a single component or an Array of components to add. See * {@link #items} for additional information.

* @param {Object} (Optional) component_2 * @param {Object} (Optional) component_n * @return {Ext.Component} component The Component (or config object) that was added. */ add : function(comp){ this.initItems(); var args = arguments.length > 1; if(args || Ext.isArray(comp)){ Ext.each(args ? arguments : comp, function(c){ this.add(c); }, this); return; } var c = this.lookupComponent(this.applyDefaults(comp)); var pos = this.items.length; if(this.fireEvent('beforeadd', this, c, pos) !== false && this.onBeforeAdd(c) !== false){ this.items.add(c); c.ownerCt = this; this.fireEvent('add', this, c, pos); } return c; }, /** * 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 * Component has been inserted. * @param {Number} index The index at which the Component will be inserted * into the Container's items collection * @param {Ext.Component} component The child Component to insert.

* Ext uses lazy rendering, and will only render the inserted Component should * it become necessary.

* A Component config object may be passed in order to avoid the overhead of * constructing a real Component object if lazy rendering might mean that the * inserted Component will not be rendered immediately. To take advantage of * this 'lazy instantiation', set the {@link Ext.Component#xtype} config * property to the registered type of the Component wanted.

* For a list of all available xtypes, see {@link Ext.Component}. * @return {Ext.Component} component The Component (or config object) that was * inserted with the Container's default config values applied. */ insert : function(index, comp){ this.initItems(); var a = arguments, len = a.length; if(len > 2){ for(var i = len-1; i >= 1; --i) { this.insert(index, a[i]); } return; } var c = this.lookupComponent(this.applyDefaults(comp)); if(c.ownerCt == this && this.items.indexOf(c) < index){ --index; } if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){ this.items.insert(index, c); c.ownerCt = this; this.fireEvent('add', this, c, index); } return c; }, // private applyDefaults : function(c){ if(this.defaults){ if(typeof c == 'string'){ c = Ext.ComponentMgr.get(c); Ext.apply(c, this.defaults); }else if(!c.events){ Ext.applyIf(c, this.defaults); }else{ Ext.apply(c, this.defaults); } } return c; }, // private onBeforeAdd : function(item){ if(item.ownerCt){ item.ownerCt.remove(item, false); } if(this.hideBorders === true){ item.border = (item.border === true); } }, /** * Removes a component from this container. Fires the {@link #beforeremove} event before removing, then fires * the {@link #remove} event after the component has been removed. * @param {Component/String} component The component reference or id to remove. * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function. * Defaults to the value of this Container's {@link #autoDestroy} config. * @return {Ext.Component} component The Component that was removed. */ remove : function(comp, autoDestroy){ 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.fireEvent('remove', this, c); } return c; }, /** * Removes all components from this container. * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function. * Defaults to the value of this Container's {@link #autoDestroy} config. * @return {Array} Array of the destroyed components */ removeAll: function(autoDestroy){ this.initItems(); var item, rem = [], items = []; this.items.each(function(i){ rem.push(i); }); for (var i = 0, len = rem.length; i < len; ++i){ item = rem[i]; this.remove(item, autoDestroy); if(item.ownerCt !== this){ items.push(item); } } return items; }, /** * Examines this container's {@link #items} property * and gets a direct child component of this container. * @param {String/Number} comp This parameter may be any of the following: *
*

For additional information see {@link Ext.util.MixedCollection#get}. * @return Ext.Component The component (if found). */ getComponent : function(comp){ if(Ext.isObject(comp)){ return comp; } return this.items.get(comp); }, // private lookupComponent : function(comp){ if(typeof comp == 'string'){ return Ext.ComponentMgr.get(comp); }else if(!comp.events){ return this.createComponent(comp); } return comp; }, // private createComponent : function(config){ return Ext.create(config, this.defaultType); }, /** * Force this container's layout to be recalculated. A call to this function is required after adding a new component * to an already rendered container, or possibly after changing sizing/position properties of child components. * @param {Boolean} shallow (optional) True to only calc the layout of this component, and let child components auto * calc layouts as required (defaults to false, which calls doLayout recursively for each subcontainer) * @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){ var rendered = this.rendered, forceLayout = this.forceLayout; if(!this.isVisible() || this.collapsed){ this.deferLayout = this.deferLayout || !shallow; if(!(force || forceLayout)){ return; } shallow = shallow && !this.deferLayout; } else { delete this.deferLayout; } if(rendered && this.layout){ this.layout.layout(); } if(shallow !== true && this.items){ var cs = this.items.items; for(var i = 0, len = cs.length; i < len; i++){ var c = cs[i]; if(c.doLayout){ c.forceLayout = forceLayout; c.doLayout(); } } } if(rendered){ this.onLayout(shallow, force); } delete this.forceLayout; }, //private onLayout : Ext.emptyFn, onShow : function(){ Ext.Container.superclass.onShow.call(this); if(this.deferLayout !== undefined){ this.doLayout(true); } }, /** * Returns the layout currently in use by the container. If the container does not currently have a layout * set, a default {@link Ext.layout.ContainerLayout} will be created and set as the container's layout. * @return {ContainerLayout} layout The container's layout */ getLayout : function(){ if(!this.layout){ var layout = new Ext.layout.ContainerLayout(this.layoutConfig); this.setLayout(layout); } return this.layout; }, // private beforeDestroy : function(){ if(this.items){ Ext.destroy.apply(Ext, this.items.items); } if(this.monitorResize){ Ext.EventManager.removeResizeListener(this.doLayout, this); } Ext.destroy(this.layout); Ext.Container.superclass.beforeDestroy.call(this); }, /** * Bubbles up the component/container heirarchy, calling the specified function with each component. The scope (this) of * function call will be the scope provided or the current component. The arguments to the function * will be the args provided or the current component. If the function returns false at any point, * the bubble is stopped. * @param {Function} fn The function to call * @param {Object} scope (optional) The scope of the function (defaults to current node) * @param {Array} args (optional) The args to call the function with (default to passing the current component) * @return {Ext.Container} this */ bubble : function(fn, scope, args){ var p = this; while(p){ if(fn.apply(scope || p, args || [p]) === false){ break; } p = p.ownerCt; } return this; }, /** * Cascades down the component/container heirarchy from this component (called first), calling the specified function with * each component. The scope (this) of * function call will be the scope provided or the current component. The arguments to the function * will be the args provided or the current component. If the function returns false at any point, * the cascade is stopped on that branch. * @param {Function} fn The function to call * @param {Object} scope (optional) The scope of the function (defaults to current component) * @param {Array} args (optional) The args to call the function with (defaults to passing the current component) * @return {Ext.Container} this */ cascade : function(fn, scope, args){ if(fn.apply(scope || this, args || [this]) !== false){ if(this.items){ var cs = this.items.items; for(var i = 0, len = cs.length; i < len; i++){ if(cs[i].cascade){ cs[i].cascade(fn, scope, args); }else{ fn.apply(scope || cs[i], args || [cs[i]]); } } } } return this; }, /** * Find a component under this container at any level by id * @param {String} id * @return Ext.Component */ findById : function(id){ var m, ct = this; this.cascade(function(c){ if(ct != c && c.id === id){ m = c; return false; } }); return m || null; }, /** * Find a component under this container at any level by xtype or class * @param {String/Class} xtype The xtype string for a component, or the class of the component directly * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is * the default), or true to check whether this Component is directly of the specified xtype. * @return {Array} Array of Ext.Components */ findByType : function(xtype, shallow){ return this.findBy(function(c){ return c.isXType(xtype, shallow); }); }, /** * Find a component under this container at any level by property * @param {String} prop * @param {String} value * @return {Array} Array of Ext.Components */ find : function(prop, value){ return this.findBy(function(c){ return c[prop] === value; }); }, /** * Find a component under this container at any level by a custom function. If the passed function returns * true, the component will be included in the results. The passed function is called with the arguments (component, this container). * @param {Function} fn The function to call * @param {Object} scope (optional) * @return {Array} Array of Ext.Components */ findBy : function(fn, scope){ var m = [], ct = this; this.cascade(function(c){ if(ct != c && fn.call(scope || c, c, ct) === true){ m.push(c); } }); return m; }, /** * Get a component contained by this container (alias for items.get(key)) * @param {String/Number} key The index or id of the component * @return {Ext.Component} Ext.Component */ get : function(key){ return this.items.get(key); } }); 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 = { /** * @cfg {String} extraCls *

An optional extra CSS class that will be added to the container. This can be useful for adding * customized styles to the container or any of its children using standard CSS rules. See * {@link Ext.Component}.{@link Ext.Component#ctCls ctCls} also.

*

Note: extraCls defaults to '' except for the following classes * which assign a value by default: *

* To configure the above Classes with an extra CSS class append to the default. For example, * for ColumnLayout:

     * extraCls: 'x-column custom-class'
     * 
*

*/ /** * @cfg {Boolean} renderHidden * True to hide each contained item on render (defaults to false). */ /** * A reference to the {@link Ext.Component} that is active. For example,

     * if(myPanel.layout.activeItem.id == 'item-1') { ... }
     * 
* activeItem only applies to layout styles that can display items one at a time * (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout} * and {@link Ext.layout.FitLayout}). Read-only. Related to {@link Ext.Container#activeItem}. * @type {Ext.Component} * @property activeItem */ // private monitorResize:false, // private activeItem : null, // private layout : function(){ var target = this.container.getLayoutTarget(); this.onLayout(this.container, target); this.container.fireEvent('afterlayout', this.container, this); }, // private onLayout : function(ct, target){ this.renderAll(ct, target); }, // private isValidParent : function(c, target){ return target && c.getDomPositionEl().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]; if(c && (!c.rendered || !this.isValidParent(c, target))){ this.renderItem(c, i, target); } } }, // 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]; } target.dom.insertBefore(c.getDomPositionEl().dom, position || null); c.container = target; this.configureItem(c, position); } }, // private configureItem: function(c, position){ if(this.extraCls){ var t = c.getPositionEl ? c.getPositionEl() : c; t.addClass(this.extraCls); } if (this.renderHidden && c != this.activeItem) { c.hide(); } if(c.doLayout){ c.doLayout(false, this.forceLayout); } }, // private onResize: function(){ if(this.container.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; } this.resizeTask.delay(this.resizeBuffer); }else{ this.runLayout(); } }, // private runLayout: function(){ this.layout(); this.container.onLayout(); }, // private setContainer : function(ct){ if(this.monitorResize && ct != this.container){ if(this.container){ this.container.un('resize', this.onResize, this); this.container.un('bodyresize', this.onResize, this); } if(ct){ ct.on({ scope: this, resize: this.onResize, bodyresize: this.onResize }); } } this.container = ct; }, // private parseMargins : function(v){ if(typeof v == 'number'){ 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[2] = ms[0]; ms[3] = ms[1]; } if(len == 3){ ms[3] = ms[1]; } return { top:parseInt(ms[0], 10) || 0, right:parseInt(ms[1], 10) || 0, bottom:parseInt(ms[2], 10) || 0, left:parseInt(ms[3], 10) || 0 }; }, /** * The {@link 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 * {@link Ext.layout.FormLayout#getTemplateArgs}. * @property fieldTpl * @type Ext.Template */ fieldTpl: (function() { var t = new Ext.Template( '
', '', '
', '
', '
' ); 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;/** * @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 * container. This class is intended to be extended or created via the layout:'fit' {@link Ext.Container#layout} * config, and should generally not need to be created directly via the new keyword.

*

FitLayout does not have any direct config options (other than inherited ones). To fit a panel to a container * using FitLayout, simply set layout:'fit' on the container and add a single panel to it. If the container has * multiple panels, only the first one will be displayed. Example usage:

*

var p = new Ext.Panel({
    title: 'Fit Layout',
    layout:'fit',
    items: {
        title: 'Inner Panel',
        html: '<p>This is the inner panel content</p>',
        border: false
    }
});
*/ Ext.layout.FitLayout = Ext.extend(Ext.layout.ContainerLayout, { // private monitorResize:true, // 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); } }, // private setItemSize : function(item, size){ if(item && size.height > 0){ // display none? item.setSize(size); } } }); Ext.Container.LAYOUTS['fit'] = Ext.layout.FitLayout;/** * @class Ext.layout.CardLayout * @extends Ext.layout.FitLayout *

This layout manages multiple child Components, each fitted to the Container, where only a single child Component can be * visible at any given time. This layout style is most commonly used for wizards, tab implementations, etc. * This class is intended to be extended or created via the layout:'card' {@link Ext.Container#layout} config, * and should generally not need to be created directly via the new keyword.

*

The CardLayout's focal method is {@link #setActiveItem}. Since only one panel is displayed at a time, * the only way to move from one Component to the next is by calling setActiveItem, passing the id or index of * the next panel to display. The layout itself does not provide a user interface for handling this navigation, * so that functionality must be provided by the developer.

*

In the following example, a simplistic wizard setup is demonstrated. A button bar is added * to the footer of the containing panel to provide navigation buttons. The buttons will be handled by a * common navigation routine -- for this example, the implementation of that routine has been ommitted since * it can be any type of custom logic. Note that other uses of a CardLayout (like a tab control) would require a * completely different implementation. For serious implementations, a better approach would be to extend * CardLayout to provide the custom functionality needed. Example usage:

*

var navHandler = function(direction){
    // This routine could contain business logic required to manage the navigation steps.
    // It would call setActiveItem as needed, manage navigation button state, handle any
    // branching logic that might be required, handle alternate actions like cancellation
    // or finalization, etc.  A complete wizard implementation could get pretty
    // sophisticated depending on the complexity required, and should probably be
    // done as a subclass of CardLayout in a real-world implementation.
};

var card = new Ext.Panel({
    title: 'Example Wizard',
    layout:'card',
    activeItem: 0, // make sure the active item is set on the container config!
    bodyStyle: 'padding:15px',
    defaults: {
        // applied to each contained panel
        border:false
    },
    // just an example of one possible navigation scheme, using buttons
    bbar: [
        {
            id: 'move-prev',
            text: 'Back',
            handler: navHandler.createDelegate(this, [-1]),
            disabled: true
        },
        '->', // greedy spacer so that the buttons are aligned to each side
        {
            id: 'move-next',
            text: 'Next',
            handler: navHandler.createDelegate(this, [1])
        }
    ],
    // the panels (or "cards") within the layout
    items: [{
        id: 'card-0',
        html: '<h1>Welcome to the Wizard!</h1><p>Step 1 of 3</p>'
    },{
        id: 'card-1',
        html: '<p>Step 2 of 3</p>'
    },{
        id: 'card-2',
        html: '<h1>Congratulations!</h1><p>Step 3 of 3 - Complete</p>'
    }]
});
*/ Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, { /** * @cfg {Boolean} deferredRender * True to render each contained item at the time it becomes active, false to render all contained items * as soon as the layout is rendered (defaults to false). If there is a significant amount of content or * a lot of heavy controls being rendered into panels that are not displayed by default, setting this to * 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. */ layoutOnCardChange : false, /** * @cfg {Boolean} renderHidden @hide */ // private renderHidden : true, constructor: function(config){ Ext.layout.CardLayout.superclass.constructor.call(this, config); this.forceLayout = (this.deferredRender === false); }, /** * Sets the active (visible) item in the layout. * @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(); } this.activeItem = item; item.show(); this.container.doLayout(); if(this.layoutOnCardChange && item.doLayout){ item.doLayout(); } } }, // private renderAll : function(ct, target){ if(this.deferredRender){ this.renderItem(this.activeItem, undefined, target); }else{ Ext.layout.CardLayout.superclass.renderAll.call(this, ct, target); } } }); 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:

*/ // 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
    }]
});

// Mix of width and columnWidth -- all columnWidth values must add up
// to 1. The first column will take up exactly 120px, and the last two
// columns will fill the remaining container width.
var p = new Ext.Panel({
    title: 'Column Layout - Mixed',
    layout:'column',
    items: [{
        title: 'Column 1',
        width: 120
    },{
        title: 'Column 2',
        columnWidth: .8
    },{
        title: 'Column 3',
        columnWidth: .2
    }]
});
*/ Ext.layout.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, { // private monitorResize:true, extraCls: 'x-column', scrollOffset : 0, // private isValidParent : function(c, target){ return (c.getPositionEl ? c.getPositionEl() : c.getEl()).dom.parentNode == this.innerCt.dom; }, // private onLayout : function(ct, target){ var cs = ct.items.items, len = cs.length, c, i; 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); var size = Ext.isIE && target.dom != Ext.getBody().dom ? target.getStyleSize() : target.getViewSize(); 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'), 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 = pw < 0 ? 0 : pw; for(i = 0; i < len; i++){ c = cs[i]; if(c.columnWidth){ c.setSize(Math.floor(c.columnWidth*pw) - c.getEl().getMargins('lr')); } } } /** * @property activeItem * @hide */ }); Ext.Container.LAYOUTS['column'] = Ext.layout.ColumnLayout;/** * @class Ext.layout.BorderLayout * @extends Ext.layout.ContainerLayout *

This is a multi-pane, application-oriented UI layout style that supports multiple * nested panels, automatic {@link Ext.layout.BorderLayout.Region#split split} bars between * {@link Ext.layout.BorderLayout.Region#BorderLayout.Region regions} and built-in * {@link Ext.layout.BorderLayout.Region#collapsible expanding and collapsing} of regions.

*

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

*

BorderLayout does not have any direct config options (other than inherited ones). * All configuration options available for customizing the BorderLayout are at the * {@link Ext.layout.BorderLayout.Region} and {@link Ext.layout.BorderLayout.SplitRegion} * levels.

*

Example usage:

*

var myBorderPanel = new Ext.Panel({
    {@link Ext.Component#renderTo renderTo}: document.body,
    {@link Ext.BoxComponent#width width}: 700,
    {@link Ext.BoxComponent#height height}: 500,
    {@link Ext.Panel#title title}: 'Border Layout',
    {@link Ext.Container#layout layout}: 'border',
    {@link Ext.Container#items items}: [{
        {@link Ext.Panel#title title}: 'South Region is resizable',
        {@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#maxSize maxSize}: 150,
        {@link Ext.layout.BorderLayout.Region#margins margins}: '0 5 5 5'
    },{
        // xtype: 'panel' implied by default
        {@link Ext.Panel#title title}: 'West Region is collapsible',
        {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}:'west',
        {@link Ext.layout.BorderLayout.Region#margins margins}: '5 0 0 5',
        {@link Ext.BoxComponent#width width}: 200,
        {@link Ext.layout.BorderLayout.Region#collapsible collapsible}: true,   // make collapsible
        {@link Ext.layout.BorderLayout.Region#cmargins cmargins}: '5 5 0 5', // adjust top margin when collapsed
        {@link Ext.Component#id id}: 'west-region-container',
        {@link Ext.Container#layout layout}: 'fit',
        {@link Ext.Panel#unstyled unstyled}: true
    },{
        {@link Ext.Panel#title title}: 'Center Region',
        {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'center',     // center region is required, no width/height specified
        {@link Ext.Component#xtype xtype}: 'container',
        {@link Ext.Container#layout layout}: 'fit',
        {@link Ext.layout.BorderLayout.Region#margins margins}: '5 5 0 0'
    }]
});
*

Notes:

*/ Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, { // private monitorResize:true, // private rendered : false, // private onLayout : function(ct, target){ var collapsed; 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; 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); } this[pos] = pos != 'center' && c.split ? new Ext.layout.BorderLayout.SplitRegion(this, c.initialConfig, pos) : new Ext.layout.BorderLayout.Region(this, c.initialConfig, pos); this[pos].render(target, c); } this.rendered = true; } var size = target.getViewSize(); if(size.width < 20 || size.height < 20){ // display none? if(collapsed){ this.restoreCollapsed = collapsed; } return; }else if(this.restoreCollapsed){ collapsed = this.restoreCollapsed; 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; 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.width = w - (m.left+m.right); b.x = m.left; b.y = m.top; centerY = b.height + b.y + m.bottom; centerH -= centerY; n.applyLayout(b); } if(s && s.isVisible()){ var b = s.getSize(); var m = s.getMargins(); b.width = w - (m.left+m.right); b.x = m.left; var 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.height = centerH - (m.top+m.bottom); b.x = m.left; b.y = centerY + m.top; var 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.height = centerH - (m.top+m.bottom); var 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(); var centerBox = { x: centerX + m.left, y: centerY + m.top, width: centerW - (m.left+m.right), height: centerH - (m.top+m.bottom) }; c.applyLayout(centerBox); } if(collapsed){ for(var i = 0, len = collapsed.length; i < len; i++){ collapsed[i].collapse(false); } } if(Ext.isIE && Ext.isStrict){ // workaround IE strict repainting issue target.repaint(); } }, destroy: function() { var r = ['north', 'south', 'east', 'west']; for (var i = 0; i < r.length; i++) { var region = this[r[i]]; if(region){ if(region.destroy){ region.destroy(); }else if (region.split){ region.split.destroy(true); } } } Ext.layout.BorderLayout.superclass.destroy.call(this); } /** * @property activeItem * @hide */ }); /** * @class Ext.layout.BorderLayout.Region *

This is a region of a {@link Ext.layout.BorderLayout BorderLayout} that acts as a subcontainer * within the layout. Each region has its own {@link Ext.layout.ContainerLayout layout} that is * independent of other regions and the containing BorderLayout, and can be any of the * {@link Ext.layout.ContainerLayout valid Ext layout types}.

*

Region size is managed automatically and cannot be changed by the user -- for * {@link #split resizable regions}, see {@link Ext.layout.BorderLayout.SplitRegion}.

* @constructor * Create a new Region. * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region. * @param {Object} config The configuration options * @param {String} position The region position. Valid values are: north, south, * east, west and center. Every {@link Ext.layout.BorderLayout BorderLayout} * must have a center region for the primary content -- all other regions are optional. */ Ext.layout.BorderLayout.Region = function(layout, config, pos){ Ext.apply(this, config); this.layout = layout; this.position = pos; this.state = {}; if(typeof this.margins == 'string'){ this.margins = this.layout.parseMargins(this.margins); } this.margins = Ext.applyIf(this.margins || {}, this.defaultMargins); if(this.collapsible){ if(typeof this.cmargins == 'string'){ this.cmargins = this.layout.parseMargins(this.cmargins); } if(this.collapseMode == 'mini' && !this.cmargins){ this.cmargins = {left:0,top:0,right:0,bottom:0}; }else{ this.cmargins = Ext.applyIf(this.cmargins || {}, pos == 'north' || pos == 'south' ? this.defaultNSCMargins : this.defaultEWCMargins); } } }; Ext.layout.BorderLayout.Region.prototype = { /** * @cfg {Boolean} animFloat * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated * panel that will close again once the user mouses out of that panel (or clicks out if * {@link #autoHide} = false). Setting {@link #animFloat} = false will * prevent the open and close of these floated panels from being animated (defaults to true). */ /** * @cfg {Boolean} autoHide * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated * panel. If autoHide = true, the panel will automatically hide after the user mouses * out of the panel. If autoHide = false, the panel will continue to display until the * user clicks outside of the panel (defaults to true). */ /** * @cfg {String} collapseMode * collapseMode supports two configuration values:

*

Note: if a collapsible region does not have a title bar, then set collapseMode = * 'mini' and {@link #split} = true in order for the region to be {@link #collapsible} * by the user as the expand/collapse tool button (that would go in the title bar) will not be rendered.

*

See also {@link #cmargins}.

*/ /** * @cfg {Object} margins * An object containing margins to apply to the region when in the expanded state in the * format:

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

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

*

*

Defaults to:


     * {top:0, right:0, bottom:0, left:0}
     * 
*/ /** * @cfg {Object} cmargins * An object containing margins to apply to the region when in the collapsed state in the * format:

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

May also be a string containing space-separated, numeric margin values. The order of the * sides associated with each value matches the way CSS processes margin values.

*

*/ /** * @cfg {Boolean} collapsible *

true to allow the user to collapse this region (defaults to false). If * true, an expand/collapse tool button will automatically be rendered into the title * bar of the region, otherwise the button will not be shown.

*

Note: that a title bar is required to display the collapse/expand toggle button -- if * no title is specified for the region's panel, the region will only be collapsible if * {@link #collapseMode} = 'mini' and {@link #split} = true. */ collapsible : false, /** * @cfg {Boolean} split *

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:

*/ split:false, /** * @cfg {Boolean} floatable * true to allow clicking a collapsed region's bar to display the region's panel floated * above the layout, false to force the user to fully expand a collapsed region by * clicking the expand button to see it again (defaults to true). */ floatable: true, /** * @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 * minWidth / maxWidth.

*/ minWidth:50, /** * @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 * minHeight / maxHeight.

*/ minHeight:50, // private defaultMargins : {left:0,top:0,right:0,bottom:0}, // private defaultNSCMargins : {left:5,top:5,right:5,bottom:5}, // private defaultEWCMargins : {left:5,top:0,right:5,bottom:0}, floatingZIndex: 100, /** * True if this region is collapsed. Read-only. * @type Boolean * @property */ isCollapsed : false, /** * This region's panel. Read-only. * @type Ext.Panel * @property panel */ /** * This region's layout. Read-only. * @type Layout * @property layout */ /** * This region's layout position (north, south, east, west or center). Read-only. * @type String * @property position */ // private render : function(ct, p){ this.panel = p; p.el.enableDisplayMode(); this.targetEl = ct; this.el = p.el; var gs = p.getState, ps = this.position; p.getState = function(){ return Ext.apply(gs.call(p) || {}, this.state); }.createDelegate(this); if(ps != 'center'){ p.allowQueuedExpand = false; p.on({ beforecollapse: this.beforeCollapse, collapse: this.onCollapse, beforeexpand: this.beforeExpand, expand: this.onExpand, hide: this.onHide, show: this.onShow, scope: this }); if(this.collapsible || this.floatable){ p.collapseEl = 'el'; p.slideAnchor = this.getSlideAnchor(); } if(p.tools && p.tools.toggle){ p.tools.toggle.addClass('x-tool-collapse-'+ps); p.tools.toggle.addClassOnOver('x-tool-collapse-'+ps+'-over'); } } }, // private getCollapsedEl : function(){ if(!this.collapsedEl){ if(!this.toolTemplate){ var tt = new Ext.Template( '
 
' ); tt.disableFormats = true; tt.compile(); Ext.layout.BorderLayout.Region.prototype.toolTemplate = tt; } this.collapsedEl = this.targetEl.createChild({ cls: "x-layout-collapsed x-layout-collapsed-"+this.position, id: this.panel.id + '-xcollapsed' }); this.collapsedEl.enableDisplayMode('block'); if(this.collapseMode == 'mini'){ this.collapsedEl.addClass('x-layout-cmini-'+this.position); this.miniCollapsedEl = this.collapsedEl.createChild({ cls: "x-layout-mini x-layout-mini-"+this.position, html: " " }); this.miniCollapsedEl.addClassOnOver('x-layout-mini-over'); this.collapsedEl.addClassOnOver("x-layout-collapsed-over"); this.collapsedEl.on('click', this.onExpandClick, this, {stopEvent:true}); }else { if(this.collapsible !== false && !this.hideCollapseTool) { var t = this.toolTemplate.append( this.collapsedEl.dom, {id:'expand-'+this.position}, true); t.addClassOnOver('x-tool-expand-'+this.position+'-over'); t.on('click', this.onExpandClick, this, {stopEvent:true}); } if(this.floatable !== false || this.titleCollapse){ this.collapsedEl.addClassOnOver("x-layout-collapsed-over"); this.collapsedEl.on("click", this[this.floatable ? 'collapseClick' : 'onExpandClick'], this); } } } return this.collapsedEl; }, // private onExpandClick : function(e){ if(this.isSlid){ this.afterSlideIn(); this.panel.expand(false); }else{ this.panel.expand(); } }, // private onCollapseClick : function(e){ this.panel.collapse(); }, // private beforeCollapse : function(p, animate){ this.lastAnim = animate; if(this.splitEl){ this.splitEl.hide(); } this.getCollapsedEl().show(); this.panel.el.setStyle('z-index', 100); this.isCollapsed = true; this.layout.layout(); }, // private onCollapse : function(animate){ this.panel.el.setStyle('z-index', 1); if(this.lastAnim === false || this.panel.animCollapse === false){ this.getCollapsedEl().dom.style.visibility = 'visible'; }else{ this.getCollapsedEl().slideIn(this.panel.slideAnchor, {duration:.2}); } this.state.collapsed = true; this.panel.saveState(); }, // private beforeExpand : function(animate){ var c = this.getCollapsedEl(); this.el.show(); if(this.position == 'east' || this.position == 'west'){ this.panel.setSize(undefined, c.getHeight()); }else{ this.panel.setSize(c.getWidth(), undefined); } c.hide(); c.dom.style.visibility = 'hidden'; this.panel.el.setStyle('z-index', this.floatingZIndex); }, // private onExpand : function(){ this.isCollapsed = false; if(this.splitEl){ this.splitEl.show(); } this.layout.layout(); this.panel.el.setStyle('z-index', 1); this.state.collapsed = false; this.panel.saveState(); }, // private collapseClick : function(e){ if(this.isSlid){ e.stopPropagation(); this.slideIn(); }else{ e.stopPropagation(); this.slideOut(); } }, // private onHide : function(){ if(this.isCollapsed){ this.getCollapsedEl().hide(); }else if(this.splitEl){ this.splitEl.hide(); } }, // private onShow : function(){ if(this.isCollapsed){ this.getCollapsedEl().show(); }else if(this.splitEl){ this.splitEl.show(); } }, /** * True if this region is currently visible, else false. * @return {Boolean} */ isVisible : function(){ return !this.panel.hidden; }, /** * Returns the current margins for this region. If the region is collapsed, the * {@link #cmargins} (collapsed margins) value will be returned, otherwise the * {@link #margins} value will be returned. * @return {Object} An object containing the element's margins: {left: (left * margin), top: (top margin), right: (right margin), bottom: (bottom margin)} */ getMargins : function(){ return this.isCollapsed && this.cmargins ? this.cmargins : this.margins; }, /** * Returns the current size of this region. If the region is collapsed, the size of the * collapsedEl will be returned, otherwise the size of the region's panel will be returned. * @return {Object} An object containing the element's size: {width: (element width), * height: (element height)} */ getSize : function(){ return this.isCollapsed ? this.getCollapsedEl().getSize() : this.panel.getSize(); }, /** * Sets the specified panel as the container element for this region. * @param {Ext.Panel} panel The new panel */ setPanel : function(panel){ this.panel = panel; }, /** * Returns the minimum allowable width for this region. * @return {Number} The minimum width */ getMinWidth: function(){ return this.minWidth; }, /** * Returns the minimum allowable height for this region. * @return {Number} The minimum height */ getMinHeight: function(){ return this.minHeight; }, // private applyLayoutCollapsed : function(box){ var ce = this.getCollapsedEl(); ce.setLeftTop(box.x, box.y); ce.setSize(box.width, box.height); }, // private applyLayout : function(box){ if(this.isCollapsed){ this.applyLayoutCollapsed(box); }else{ this.panel.setPosition(box.x, box.y); this.panel.setSize(box.width, box.height); } }, // private beforeSlide: function(){ this.panel.beforeEffect(); }, // private afterSlide : function(){ this.panel.afterEffect(); }, // private initAutoHide : function(){ if(this.autoHide !== false){ if(!this.autoHideHd){ var st = new Ext.util.DelayedTask(this.slideIn, this); this.autoHideHd = { "mouseout": function(e){ if(!e.within(this.el, true)){ st.delay(500); } }, "mouseover" : function(e){ st.cancel(); }, scope : this }; } this.el.on(this.autoHideHd); } }, // private clearAutoHide : function(){ if(this.autoHide !== false){ this.el.un("mouseout", this.autoHideHd.mouseout); this.el.un("mouseover", this.autoHideHd.mouseover); } }, // private clearMonitor : function(){ Ext.getDoc().un("click", this.slideInIf, this); }, /** * If this Region is {@link #floatable}, this method slides this Region into full visibility over the top * of the center Region where it floats until either {@link #slideIn} is called, or other regions of the layout * are clicked, or the mouse exits the Region. */ slideOut : function(){ if(this.isSlid || this.el.hasActiveFx()){ return; } this.isSlid = true; var ts = this.panel.tools; if(ts && ts.toggle){ ts.toggle.hide(); } this.el.show(); if(this.position == 'east' || this.position == 'west'){ this.panel.setSize(undefined, this.collapsedEl.getHeight()); }else{ this.panel.setSize(this.collapsedEl.getWidth(), undefined); } 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); this.panel.el.replaceClass('x-panel-collapsed', 'x-panel-floating'); if(this.animFloat !== false){ this.beforeSlide(); this.el.slideIn(this.getSlideAnchor(), { callback: function(){ this.afterSlide(); this.initAutoHide(); Ext.getDoc().on("click", this.slideInIf, this); }, scope: this, block: true }); }else{ this.initAutoHide(); Ext.getDoc().on("click", this.slideInIf, this); } }, // private afterSlideIn : function(){ this.clearAutoHide(); this.isSlid = false; this.clearMonitor(); this.el.setStyle("z-index", ""); this.panel.el.replaceClass('x-panel-floating', 'x-panel-collapsed'); this.el.dom.style.left = this.restoreLT[0]; this.el.dom.style.top = this.restoreLT[1]; var ts = this.panel.tools; if(ts && ts.toggle){ ts.toggle.show(); } }, /** * If this Region is {@link #floatable}, and this Region has been slid into floating visibility, then this method slides * this region back into its collapsed state. */ slideIn : function(cb){ if(!this.isSlid || this.el.hasActiveFx()){ Ext.callback(cb); return; } this.isSlid = false; if(this.animFloat !== false){ this.beforeSlide(); this.el.slideOut(this.getSlideAnchor(), { callback: function(){ this.el.hide(); this.afterSlide(); this.afterSlideIn(); Ext.callback(cb); }, scope: this, block: true }); }else{ this.el.hide(); this.afterSlideIn(); } }, // private slideInIf : function(e){ if(!e.within(this.el)){ this.slideIn(); } }, // private anchors : { "west" : "left", "east" : "right", "north" : "top", "south" : "bottom" }, // private sanchors : { "west" : "l", "east" : "r", "north" : "t", "south" : "b" }, // private canchors : { "west" : "tl-tr", "east" : "tr-tl", "north" : "tl-bl", "south" : "bl-tl" }, // private getAnchor : function(){ return this.anchors[this.position]; }, // private getCollapseAnchor : function(){ return this.canchors[this.position]; }, // private getSlideAnchor : function(){ return this.sanchors[this.position]; }, // private getAlignAdj : function(){ var cm = this.cmargins; switch(this.position){ case "west": return [0, 0]; break; case "east": return [0, 0]; break; case "north": return [0, 0]; break; case "south": return [0, 0]; break; } }, // private getExpandAdj : function(){ var c = this.collapsedEl, cm = this.cmargins; switch(this.position){ case "west": return [-(cm.right+c.getWidth()+cm.left), 0]; break; case "east": return [cm.right+c.getWidth()+cm.left, 0]; break; case "north": return [0, -(cm.top+cm.bottom+c.getHeight())]; break; case "south": return [0, cm.top+cm.bottom+c.getHeight()]; break; } } }; /** * @class Ext.layout.BorderLayout.SplitRegion * @extends Ext.layout.BorderLayout.Region *

This is a specialized type of {@link Ext.layout.BorderLayout.Region BorderLayout region} that * has a built-in {@link Ext.SplitBar} for user resizing of regions. The movement of the split bar * is configurable to move either {@link #tickSize smooth or incrementally}.

* @constructor * Create a new SplitRegion. * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region. * @param {Object} config The configuration options * @param {String} position The region position. Valid values are: north, south, east, west and center. Every * BorderLayout must have a center region for the primary content -- all other regions are optional. */ Ext.layout.BorderLayout.SplitRegion = function(layout, config, pos){ Ext.layout.BorderLayout.SplitRegion.superclass.constructor.call(this, layout, config, pos); // prevent switch this.applyLayout = this.applyFns[pos]; }; Ext.extend(Ext.layout.BorderLayout.SplitRegion, Ext.layout.BorderLayout.Region, { /** * @cfg {Number} tickSize * The increment, in pixels by which to move this Region's {@link Ext.SplitBar SplitBar}. * By default, the {@link Ext.SplitBar SplitBar} moves smoothly. */ /** * @cfg {String} splitTip * The tooltip to display when the user hovers over a * {@link Ext.layout.BorderLayout.Region#collapsible non-collapsible} region's split bar * (defaults to "Drag to resize."). Only applies if * {@link #useSplitTips} = true. */ splitTip : "Drag to resize.", /** * @cfg {String} collapsibleSplitTip * The tooltip to display when the user hovers over a * {@link Ext.layout.BorderLayout.Region#collapsible collapsible} region's split bar * (defaults to "Drag to resize. Double click to hide."). Only applies if * {@link #useSplitTips} = true. */ collapsibleSplitTip : "Drag to resize. Double click to hide.", /** * @cfg {Boolean} useSplitTips * true to display a tooltip when the user hovers over a region's split bar * (defaults to false). The tooltip text will be the value of either * {@link #splitTip} or {@link #collapsibleSplitTip} as appropriate. */ useSplitTips : false, // private splitSettings : { north : { orientation: Ext.SplitBar.VERTICAL, placement: Ext.SplitBar.TOP, maxFn : 'getVMaxSize', minProp: 'minHeight', maxProp: 'maxHeight' }, south : { orientation: Ext.SplitBar.VERTICAL, placement: Ext.SplitBar.BOTTOM, maxFn : 'getVMaxSize', minProp: 'minHeight', maxProp: 'maxHeight' }, east : { orientation: Ext.SplitBar.HORIZONTAL, placement: Ext.SplitBar.RIGHT, maxFn : 'getHMaxSize', minProp: 'minWidth', maxProp: 'maxWidth' }, west : { orientation: Ext.SplitBar.HORIZONTAL, placement: Ext.SplitBar.LEFT, maxFn : 'getHMaxSize', minProp: 'minWidth', maxProp: 'maxWidth' } }, // private applyFns : { west : function(box){ if(this.isCollapsed){ return this.applyLayoutCollapsed(box); } var sd = this.splitEl.dom, s = sd.style; this.panel.setPosition(box.x, box.y); var sw = sd.offsetWidth; s.left = (box.x+box.width-sw)+'px'; s.top = (box.y)+'px'; s.height = Math.max(0, box.height)+'px'; this.panel.setSize(box.width-sw, box.height); }, east : function(box){ if(this.isCollapsed){ return this.applyLayoutCollapsed(box); } var sd = this.splitEl.dom, s = sd.style; var sw = sd.offsetWidth; this.panel.setPosition(box.x+sw, box.y); s.left = (box.x)+'px'; s.top = (box.y)+'px'; s.height = Math.max(0, box.height)+'px'; this.panel.setSize(box.width-sw, box.height); }, north : function(box){ if(this.isCollapsed){ return this.applyLayoutCollapsed(box); } var sd = this.splitEl.dom, s = sd.style; var sh = sd.offsetHeight; this.panel.setPosition(box.x, box.y); s.left = (box.x)+'px'; s.top = (box.y+box.height-sh)+'px'; s.width = Math.max(0, box.width)+'px'; this.panel.setSize(box.width, box.height-sh); }, south : function(box){ if(this.isCollapsed){ return this.applyLayoutCollapsed(box); } var sd = this.splitEl.dom, s = sd.style; var sh = sd.offsetHeight; this.panel.setPosition(box.x, box.y+sh); s.left = (box.x)+'px'; s.top = (box.y)+'px'; s.width = Math.max(0, box.width)+'px'; this.panel.setSize(box.width, box.height-sh); } }, // private render : function(ct, p){ Ext.layout.BorderLayout.SplitRegion.superclass.render.call(this, ct, p); var ps = this.position; this.splitEl = ct.createChild({ cls: "x-layout-split x-layout-split-"+ps, html: " ", id: this.panel.id + '-xsplit' }); if(this.collapseMode == 'mini'){ this.miniSplitEl = this.splitEl.createChild({ cls: "x-layout-mini x-layout-mini-"+ps, html: " " }); this.miniSplitEl.addClassOnOver('x-layout-mini-over'); this.miniSplitEl.on('click', this.onCollapseClick, this, {stopEvent:true}); } var s = this.splitSettings[ps]; this.split = new Ext.SplitBar(this.splitEl.dom, p.el, s.orientation); this.split.tickSize = this.tickSize; this.split.placement = s.placement; this.split.getMaximumSize = this[s.maxFn].createDelegate(this); this.split.minSize = this.minSize || this[s.minProp]; this.split.on("beforeapply", this.onSplitMove, this); this.split.useShim = this.useShim === true; this.maxSize = this.maxSize || this[s.maxProp]; if(p.hidden){ this.splitEl.hide(); } if(this.useSplitTips){ this.splitEl.dom.title = this.collapsible ? this.collapsibleSplitTip : this.splitTip; } if(this.collapsible){ this.splitEl.on("dblclick", this.onCollapseClick, this); } }, //docs inherit from superclass getSize : function(){ if(this.isCollapsed){ return this.collapsedEl.getSize(); } var s = this.panel.getSize(); if(this.position == 'north' || this.position == 'south'){ s.height += this.splitEl.dom.offsetHeight; }else{ s.width += this.splitEl.dom.offsetWidth; } return s; }, // private getHMaxSize : function(){ var cmax = this.maxSize || 10000; var center = this.layout.center; return Math.min(cmax, (this.el.getWidth()+center.el.getWidth())-center.getMinWidth()); }, // private getVMaxSize : function(){ var cmax = this.maxSize || 10000; var center = this.layout.center; return Math.min(cmax, (this.el.getHeight()+center.el.getHeight())-center.getMinHeight()); }, // private onSplitMove : function(split, newSize){ var s = this.panel.getSize(); this.lastSplitSize = newSize; if(this.position == 'north' || this.position == 'south'){ this.panel.setSize(s.width, newSize); this.state.height = newSize; }else{ this.panel.setSize(newSize, s.height); this.state.width = newSize; } this.layout.layout(); this.panel.saveState(); return false; }, /** * Returns a reference to the split bar in use by this region. * @return {Ext.SplitBar} The split bar */ getSplitBar : function(){ return this.split; }, // inherit docs destroy : function() { Ext.destroy( this.miniSplitEl, this.split, this.splitEl ); } }); Ext.Container.LAYOUTS['border'] = Ext.layout.BorderLayout;/** * @class Ext.layout.FormLayout * @extends Ext.layout.AnchorLayout *

This layout manager is specifically designed for rendering and managing child Components of * {@link Ext.form.FormPanel forms}. It is responsible for rendering the labels of * {@link Ext.form.Field Field}s.

* *

This layout manager is used when a Container is configured with the layout:'form' * {@link Ext.Container#layout layout} config option, and should generally not need to be created directly * via the new keyword. See {@link Ext.Container#layout} for additional details.

* *

In an application, it will usually be preferrable to use a {@link Ext.form.FormPanel FormPanel} * (which is configured with FormLayout as its layout class by default) since it also provides built-in * functionality for {@link Ext.form.BasicForm#doAction loading, validating and submitting} the form.

* *

A {@link Ext.Container Container} using the FormLayout layout manager (e.g. * {@link Ext.form.FormPanel} or specifying layout:'form') can also accept the following * layout-specific config properties:

* *

Any Component (including Fields) managed by FormLayout accepts the following as a config option: *

* *

Any Component managed by FormLayout may be rendered as a form field (with an associated label) by * configuring it with a non-null {@link Ext.Component#fieldLabel fieldLabel}. Components configured * in this way may be configured with the following options which affect the way the FormLayout renders them: *

* *

Example usage:

*

// Required if showing validation messages
Ext.QuickTips.init();

// While you can create a basic Panel with layout:'form', practically
// you should usually use a FormPanel to also get its form functionality
// since it already creates a FormLayout internally.
var form = new Ext.form.FormPanel({
    title: 'Form Layout',
    bodyStyle: 'padding:15px',
    width: 350,
    defaultType: 'textfield',
    defaults: {
        // applied to each contained item
        width: 230,
        msgTarget: 'side'
    },
    items: [{
            fieldLabel: 'First Name',
            name: 'first',
            allowBlank: false,
            {@link Ext.Component#labelSeparator labelSeparator}: ':' // override labelSeparator layout config
        },{
            fieldLabel: 'Last Name',
            name: 'last'
        },{
            fieldLabel: 'Email',
            name: 'email',
            vtype:'email'
        }, {
            xtype: 'textarea',
            hideLabel: true,     // override hideLabels layout config
            name: 'msg',
            anchor: '100% -53'
        }
    ],
    buttons: [
        {text: 'Save'},
        {text: 'Cancel'}
    ],
    layoutConfig: {
        {@link #labelSeparator}: '~' // superseded by assignment below
    },
    // config options applicable to container when layout='form':
    hideLabels: false,
    labelAlign: 'left',   // or 'right' or 'top'
    {@link Ext.form.FormPanel#labelSeparator labelSeparator}: '>>', // takes precedence over layoutConfig value
    labelWidth: 65,       // defaults to 100
    labelPad: 8           // defaults to 5, must specify labelWidth to be honored
});
*/ Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, { /** * @cfg {String} labelSeparator * See {@link Ext.form.FormPanel}.{@link Ext.form.FormPanel#labelSeparator labelSeparator}. Configuration * of this property at the container level takes precedence. */ labelSeparator : ':', /** * Read only. The CSS style specification string added to field labels in this layout if not * otherwise {@link Ext.Component#labelStyle specified by each contained field}. * @type String * @property labelStyle */ // private setContainer : function(ct){ Ext.layout.FormLayout.superclass.setContainer.call(this, ct); if(ct.labelAlign){ ct.addClass('x-form-label-'+ct.labelAlign); } if(ct.hideLabels){ this.labelStyle = "display:none"; this.elementStyle = "padding-left:0;"; this.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(ct.labelAlign == 'top'){ this.labelStyle = "width:auto;"; this.labelAdjust = 0; this.elementStyle = "padding-left:0;"; } } }, //private getLabelStyle: function(s){ var ls = '', items = [this.labelStyle, s]; for (var i = 0, len = items.length; i < len; ++i){ if (items[i]){ ls += items[i]; if (ls.substr(-1, 1) != ';'){ ls += ';' } } } return ls; }, /** * @cfg {Ext.Template} fieldTpl * A {@link Ext.Template#compile compile}d {@link Ext.Template} for rendering * the fully wrapped, labeled and styled form Field. Defaults to:


new Ext.Template(
    '<div class="x-form-item {itemCls}" tabIndex="-1">',
        '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{labelSeparator}</label>',
        '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
        '</div><div class="{clearCls}"></div>',
    '</div>'
);
*

This may be specified to produce a different DOM structure when rendering form Fields.

*

A description of the properties within the template follows:

*

Also see {@link #getTemplateArgs}

*/ // private renderItem : function(c, position, target){ if(c && !c.rendered && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){ var args = this.getTemplateArgs(c); if(typeof position == 'number'){ position = target.dom.childNodes[position] || null; } if(position){ this.fieldTpl.insertBefore(position, args); }else{ this.fieldTpl.append(target, args); } c.render('x-form-el-'+c.id); }else { Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments); } }, /** *

Provides template arguments for rendering the fully wrapped, labeled and styled form Field.

*

This method returns an object hash containing properties used by the layout's {@link #fieldTpl} * to create a correctly wrapped, labeled and styled form Field. This may be overriden to * create custom layouts. The properties which must be returned are:

* @param field The {@link Field Ext.form.Field} being rendered. * @return An object hash containing the properties required to render the Field. */ getTemplateArgs: function(field) { var noLabelSep = !field.fieldLabel || field.hideLabel; return { id: field.id, label: field.fieldLabel, labelStyle: field.labelStyle||this.labelStyle||'', elementStyle: this.elementStyle||'', labelSeparator: noLabelSep ? '' : (typeof field.labelSeparator == 'undefined' ? this.labelSeparator : field.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); }, // private isValidParent : function(c, target){ return true; } /** * @property activeItem * @hide */ }); 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 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 accordion = new Ext.Panel({
    title: 'Accordion Layout',
    layout:'accordion',
    defaults: {
        // applied to each contained panel
        bodyStyle: 'padding:15px'
    },
    layoutConfig: {
        // layout-specific configs go here
        titleCollapse: false,
        animate: true,
        activeOnTop: true
    },
    items: [{
        title: 'Panel 1',
        html: '<p>Panel content!</p>'
    },{
        title: 'Panel 2',
        html: '<p>Panel content!</p>'
    },{
        title: 'Panel 3',
        html: '<p>Panel content!</p>'
    }]
});
*/ Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, { /** * @cfg {Boolean} fill * True to adjust the active item's height to fill the available space in the container, false to use the * item's current height, or auto height if not explicitly set (defaults to true). */ fill : true, /** * @cfg {Boolean} autoWidth * True to set each contained item's width to 'auto', false to use the item's current width (defaults to true). * Note that some components, in particular the {@link Ext.grid.GridPanel grid}, will not function properly within * layouts if they have auto width, so in such cases this config should be set to false. */ autoWidth : true, /** * @cfg {Boolean} titleCollapse * True to allow expand/collapse of each contained panel by clicking anywhere on the title bar, false to allow * expand/collapse only when the toggle tool button is clicked (defaults to true). When set to false, * {@link #hideCollapseTool} should be false also. */ titleCollapse : true, /** * @cfg {Boolean} hideCollapseTool * True to hide the contained panels' collapse/expand toggle buttons, false to display them (defaults to false). * When set to true, {@link #titleCollapse} should be true also. */ hideCollapseTool : 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 contained panels' title bars, false to render it last (defaults to false). */ collapseFirst : false, /** * @cfg {Boolean} animate * True to slide the contained panels open and closed during expand/collapse using animation, false to open and * close directly with no animation (defaults to false). Note: to defer to the specific config setting of each * contained panel for this property, set this to undefined at the layout level. */ animate : false, /** * @cfg {Boolean} sequence * Experimental. If animate is set to true, this will result in each animation running in sequence. */ sequence : false, /** * @cfg {Boolean} activeOnTop * True to swap the position of each panel as it is expanded so that it becomes the first item in the container, * false to keep the panels in the rendered order. This is NOT compatible with "animate:true" (defaults to false). */ activeOnTop : false, renderItem : function(c){ if(this.animate === false){ c.animCollapse = false; } c.collapsible = true; if(this.autoWidth){ c.autoWidth = true; } if(this.titleCollapse){ c.titleCollapse = true; } if(this.hideCollapseTool){ c.hideCollapseTool = true; } if(this.collapseFirst !== undefined){ c.collapseFirst = this.collapseFirst; } if(!this.activeItem && !c.collapsed){ this.activeItem = c; }else if(this.activeItem && this.activeItem != c){ c.collapsed = true; } Ext.layout.AccordionLayout.superclass.renderItem.apply(this, arguments); c.header.addClass('x-accordion-hd'); c.on('beforeexpand', this.beforeExpand, this); }, // private beforeExpand : function(p, anim){ var ai = this.activeItem; if(ai){ if(this.sequence){ delete this.activeItem; if (!ai.collapsed){ ai.collapse({callback:function(){ p.expand(anim || true); }, scope: this}); return false; } }else{ ai.collapse(this.animate); } } this.activeItem = p; if(this.activeOnTop){ p.el.dom.parentNode.insertBefore(p.el.dom, p.el.dom.parentNode.firstChild); } this.layout(); }, // private setItemSize : function(item, size){ if(this.fill && item){ var hh = 0; this.container.items.each(function(p){ if(p != item){ hh += p.header.getHeight(); } }); size.height -= hh; item.setSize(size); } }, /** * Sets the active (expanded) item in the layout. * @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(item.rendered && item.collapsed){ item.expand(); }else{ this.activeItem = item; } } } }); Ext.Container.LAYOUTS.accordion = Ext.layout.AccordionLayout; //backwards compat Ext.layout.Accordion = Ext.layout.AccordionLayout;/** * @class Ext.layout.TableLayout * @extends Ext.layout.ContainerLayout *

This layout allows you to easily render content into an HTML table. The total number of columns can be * specified, and rowspan and colspan can be used to create complex layouts within the table. * This class is intended to be extended or created via the layout:'table' {@link Ext.Container#layout} config, * and should generally not need to be created directly via the new keyword.

*

Note that when creating a layout via config, the layout-specific config properties must be passed in via * the {@link Ext.Container#layoutConfig} object which will then be applied internally to the layout. In the * case of TableLayout, the only valid layout config property is {@link #columns}. However, the items added to a * TableLayout can supply the following table-specific config properties:

* *

The basic concept of building up a TableLayout is conceptually very similar to building up a standard * HTML table. You simply add each panel (or "cell") that you want to include along with any span attributes * specified as the special config properties of rowspan and colspan which work exactly like their HTML counterparts. * Rather than explicitly creating and nesting rows and columns as you would in HTML, you simply specify the * total column count in the layoutConfig and start adding panels in their natural order from left to right, * top to bottom. The layout will automatically figure out, based on the column count, rowspans and colspans, * how to position each panel within the table. Just like with HTML tables, your rowspans and colspans must add * up correctly in your overall layout or you'll end up with missing and/or extra cells! Example usage:

*

// This code will generate a layout table that is 3 columns by 2 rows
// with some spanning included.  The basic layout will be:
// +--------+-----------------+
// |   A    |   B             |
// |        |--------+--------|
// |        |   C    |   D    |
// +--------+--------+--------+
var table = new Ext.Panel({
    title: 'Table Layout',
    layout:'table',
    defaults: {
        // applied to each contained panel
        bodyStyle:'padding:20px'
    },
    layoutConfig: {
        // The total column count must be specified here
        columns: 3
    },
    items: [{
        html: '<p>Cell A content</p>',
        rowspan: 2
    },{
        html: '<p>Cell B content</p>',
        colspan: 2
    },{
        html: '<p>Cell C content</p>',
        cellCls: 'highlight'
    },{
        html: '<p>Cell D content</p>'
    }]
});
*/ Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, { /** * @cfg {Number} columns * The total number of columns to create in the table for this layout. If not specified, all Components added to * this layout will be rendered into a single row using one column per Component. */ // private monitorResize:false, /** * @cfg {Object} tableAttrs *

An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification * used to create the layout's <table> element. Example:


{
    xtype: 'panel',
    layout: 'table',
    layoutConfig: {
        tableAttrs: {
        	style: {
        		width: '100%'
        	}
        },
        columns: 3
    }
}
*/ tableAttrs:null, // private setContainer : function(ct){ Ext.layout.TableLayout.superclass.setContainer.call(this, ct); this.currentRow = 0; this.currentColumn = 0; this.cells = []; }, // private onLayout : function(ct, target){ var cs = ct.items.items, len = cs.length, c, i; if(!this.table){ target.addClass('x-table-layout-ct'); this.table = target.createChild( Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true); } this.renderAll(ct, target); }, // private getRow : function(index){ var row = this.table.tBodies[0].childNodes[index]; if(!row){ row = document.createElement('tr'); this.table.tBodies[0].appendChild(row); } return row; }, // private getNextCell : function(c){ var cell = this.getNextNonSpan(this.currentColumn, this.currentRow); var curCol = this.currentColumn = cell[0], curRow = this.currentRow = cell[1]; for(var rowIndex = curRow; rowIndex < curRow + (c.rowspan || 1); rowIndex++){ if(!this.cells[rowIndex]){ this.cells[rowIndex] = []; } for(var colIndex = curCol; colIndex < curCol + (c.colspan || 1); colIndex++){ this.cells[rowIndex][colIndex] = true; } } var td = document.createElement('td'); if(c.cellId){ td.id = c.cellId; } var cls = 'x-table-layout-cell'; if(c.cellCls){ cls += ' ' + c.cellCls; } td.className = cls; if(c.colspan){ td.colSpan = c.colspan; } if(c.rowspan){ td.rowSpan = c.rowspan; } this.getRow(curRow).appendChild(td); return td; }, // private getNextNonSpan: function(colIndex, rowIndex){ var cols = this.columns; while((cols && colIndex >= cols) || (this.cells[rowIndex] && this.cells[rowIndex][colIndex])) { if(cols && colIndex >= cols){ rowIndex++; colIndex = 0; }else{ colIndex++; } } return [colIndex, rowIndex]; }, // private renderItem : function(c, position, target){ if(c && !c.rendered){ c.render(this.getNextCell(c)); if(this.extraCls){ var t = c.getPositionEl ? c.getPositionEl() : c; t.addClass(this.extraCls); } } }, // private isValidParent : function(c, target){ return true; } /** * @property activeItem * @hide */ }); 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:

*
*

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: *
*/ 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: *
*/ /** * @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: *