/*! * Ext JS Library 3.4.0 * Copyright(c) 2006-2011 Sencha Inc. * licensing@sencha.com * http://www.sencha.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 Component with the specified id is added to ComponentMgr. This will happen on instantiation. * @param {String} id The component {@link Ext.Component#id id} * @param {Function} fn The callback function * @param {Object} scope The scope (this reference) in which the callback is executed. Defaults to the Component. */ 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, /** * The xtypes that have been registered with the component manager. * @type {Object} */ types : types, /** * The ptypes that have been registered with the component manager. * @type {Object} */ ptypes: ptypes, /** * Checks if a Component type is registered. * @param {Ext.Component} xtype The mnemonic string by which the Component class may be looked up * @return {Boolean} Whether the type is registered. */ isRegistered : function(xtype){ return types[xtype] !== undefined; }, /** * Checks if a Plugin type is registered. * @param {Ext.Component} ptype The mnemonic string by which the Plugin class may be looked up * @return {Boolean} Whether the type is registered. */ isPluginRegistered : function(ptype){ return ptypes[ptype] !== undefined; }, /** *

Registers a new Component constructor, keyed by a new * {@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){ var PluginCls = ptypes[config.ptype || defaultType]; if (PluginCls.init) { return PluginCls; } else { return new PluginCls(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; /** * Shorthand for {@link Ext.ComponentMgr#create} * Creates a new Component from the specified config object using the * config object's {@link Ext.component#xtype xtype} to determine the class to instantiate. * @param {Object} config A configuration object for the Component you wish to create. * @param {Constructor} defaultType The constructor to provide the default Component type if * the config object does not contain a xtype. (Optional if the config contains a xtype). * @return {Ext.Component} The newly instantiated Component. * @member Ext * @method create */ Ext.create = Ext.ComponentMgr.create;/** * @class Ext.Component * @extends Ext.util.Observable *

Base class for all Ext components. All subclasses of Component may participate in the automated * 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}
multislider      {@link Ext.slider.MultiSlider}
panel            {@link Ext.Panel}
progress         {@link Ext.ProgressBar}
propertygrid     {@link Ext.grid.PropertyGrid}
slider           {@link Ext.slider.SingleSlider}
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.form.FormPanel}
checkbox         {@link Ext.form.Checkbox}
checkboxgroup    {@link Ext.form.CheckboxGroup}
combo            {@link Ext.form.ComboBox}
compositefield   {@link Ext.form.CompositeField}
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 added * Fires when a component is added to an Ext.Container * @param {Ext.Component} this * @param {Ext.Container} ownerCt Container which holds the component * @param {number} index Position at which the component was added */ 'added', /** * @event disable * Fires after the component is disabled. * @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 removed * Fires when a component is removed from an Ext.Container * @param {Ext.Component} this * @param {Ext.Container} ownerCt Container which holds the component */ 'removed', /** * @event beforerender * Fires before the component is {@link #rendered}. Return false from an * 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(); } 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 *

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


*

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

*

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'
    }]
});
*/ /** * @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 */ /** * This Component's owner {@link Ext.Container Container} (defaults to undefined, and is set automatically when * this Component is added to a Container). Read-only. *

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

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

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

* */ /** * @cfg {String/Object} html * An HTML fragment, or a {@link Ext.DomHelper DomHelper} specification to use as the layout element * content (defaults to ''). The HTML content is added after the component is rendered, * so the document will not contain this HTML at the time the {@link #render} event is fired. * This content is inserted into the body before any configured {@link #contentEl} is appended. */ /** * @cfg {Mixed} tpl * An {@link Ext.Template}, {@link Ext.XTemplate} * or an array of strings to form an Ext.XTemplate. * Used in conjunction with the {@link #data} and * {@link #tplWriteMode} configurations. */ /** * @cfg {String} tplWriteMode The Ext.(X)Template method to use when * updating the content area of the Component. Defaults to 'overwrite' * (see {@link Ext.XTemplate#overwrite}). */ tplWriteMode : 'overwrite', /** * @cfg {Mixed} data * The initial set of data to apply to the {@link #tpl} to * update the content area of the Component. */ /** * @cfg {Array} bubbleEvents *

An array of events that, when fired, should be bubbled to any parent container. * See {@link Ext.util.Observable#enableBubble}. * Defaults to []. */ bubbleEvents: [], // 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 : function(){ /* * this is double processing, however it allows people to be able to do * Ext.apply(this, { * listeners: { * //here * } * }); * MyClass.superclass.initComponent.call(this); */ if(this.listeners){ this.on(this.listeners); delete this.listeners; } this.enableBubble(this.bubbleEvents); }, /** *

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); // Populate content of the component with html, contentEl or // a tpl. var contentTarget = this.getContentTarget(); if (this.html){ contentTarget.update(Ext.DomHelper.markup(this.html)); delete this.html; } if (this.contentEl){ var ce = Ext.getDom(this.contentEl); Ext.fly(ce).removeClass(['x-hidden', 'x-hide-display']); contentTarget.appendChild(ce); } if (this.tpl) { if (!this.tpl.compile) { this.tpl = new Ext.XTemplate(this.tpl); } if (this.data) { this.tpl[this.tplWriteMode](contentTarget, this.data); delete this.data; } } this.afterRender(this.container); if(this.hidden){ // call this so we don't fire initial hide events. this.doHide(); } if(this.disabled){ // pass silent so the event doesn't fire the first time. this.disable(true); } if(this.stateful !== false){ this.initStateEvents(); } this.fireEvent('afterrender', this); } return this; }, /** * Update the content area of a component. * @param {Mixed} htmlOrData * If this component has been configured with a template via the tpl config * then it will use this argument as data to populate the template. * If this component was not configured with a template, the components * content area will be updated via Ext.Element update * @param {Boolean} loadScripts * (optional) Only legitimate when using the html configuration. Defaults to false * @param {Function} callback * (optional) Only legitimate when using the html configuration. Callback to execute when scripts have finished loading */ update: function(htmlOrData, loadScripts, cb) { var contentTarget = this.getContentTarget(); if (this.tpl && typeof htmlOrData !== "string") { this.tpl[this.tplWriteMode](contentTarget, htmlOrData || {}); } else { var html = Ext.isObject(htmlOrData) ? Ext.DomHelper.markup(htmlOrData) : htmlOrData; contentTarget.update(html, loadScripts, cb); } }, /** * @private * Method to manage awareness of when components are added to their * respective Container, firing an added event. * References are established at add time rather than at render time. * @param {Ext.Container} container Container which holds the component * @param {number} pos Position at which the component was added */ onAdded : function(container, pos) { this.ownerCt = container; this.initRef(); this.fireEvent('added', this, container, pos); }, /** * @private * Method to manage awareness of when components are removed from their * respective Container, firing an removed event. References are properly * cleaned up after removing a component from its owning container. */ onRemoved : function() { this.removeRef(); this.fireEvent('removed', this, this.ownerCt); delete this.ownerCt; }, /** * @private * Method to establish a reference to a component. */ initRef : function() { /** * @cfg {String} ref *

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

*

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

*

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

*/ if(this.ref && !this.refOwner){ var levels = this.ref.split('/'), last = levels.length, i = 0, t = this; while(t && i < last){ t = t.ownerCt; ++i; } if(t){ t[this.refName = levels[--i]] = this; /** * @type Ext.Container * @property refOwner * The ancestor Container into which the {@link #ref} reference was inserted if this Component * is a child of a Container, and has been configured with a ref. */ this.refOwner = t; } } }, removeRef : function() { if (this.refOwner && this.refName) { delete this.refOwner[this.refName]; delete this.refOwner; } }, // private initState : function(){ 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(Ext.apply({}, state)); this.fireEvent('staterestore', this, state); } } } } }, // private getStateId : function(){ return this.stateId || ((/^(ext-comp-|ext-gen)/).test(String(this.id)) ? 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){ 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); if (div) { Ext.removeNode(div); div = null; } } } }, // 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.isDestroyed){ if(this.fireEvent('beforedestroy', this) !== false){ this.destroying = true; this.beforeDestroy(); if(this.ownerCt && this.ownerCt.remove){ this.ownerCt.remove(this, false); } if(this.rendered){ this.el.remove(); if(this.actionMode == 'container' || this.removeMode == 'container'){ this.container.remove(); } } // Stop any buffered tasks if(this.focusTask && this.focusTask.cancel){ this.focusTask.cancel(); } this.onDestroy(); Ext.ComponentMgr.unregister(this); this.fireEvent('destroy', this); this.purgeListeners(); this.destroying = false; this.isDestroyed = true; } } }, deleteMembers : function(){ var args = arguments; for(var i = 0, len = args.length; i < len; ++i){ delete this[args[i]]; } }, // 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; }, // private getContentTarget : function(){ return this.el; }, /** * Returns the id of this component or automatically generates and * returns an id if an id is not defined yet:

     * '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.focusTask = new Ext.util.DelayedTask(this.focus, this, [selectText, false]); this.focusTask.delay(Ext.isNumber(delay) ? delay : 10); return this; } if(this.rendered && !this.isDestroyed){ 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.getVisibilityEl().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.getVisibilityEl().addClass('x-hide-' + this.hideMode); }, // private getVisibilityEl : 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.getVisibilityEl().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/Ext.Component/Class} xtype The xtype to check for this Component. Note that the the component can either be an instance * or a component class: *

var c = new Ext.Component();
console.log(c.isXType(c));
console.log(c.isXType(Ext.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/Ext.Component/Class} xtype The xtype to check for this Component. Note that the the component can either be an instance * or a component class: * @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 {Ext.Container} The first Container which matches the given xtype or class */ findParentByType : function(xtype, shallow){ return this.findParentBy(function(c){ return c.isXType(xtype, shallow); }); }, /** * 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.Component} 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; }, // protected getPositionEl : function(){ return this.positionEl || this.el; }, // 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 = []; }, // private createMons: function(){ if(!this.mons){ this.mons = []; this.on('beforedestroy', this.clearMons, this, {single: true}); } }, /** *

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

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

or:

myGridPanel.mon(myGridPanel.getSelectionModel(), {
    selectionchange: handleSelectionChange,
    buffer: 50
});
* @param {Observable|Element} item The item to which to add a listener/listeners. * @param {Object|String} ename The event name, or an object containing event name properties. * @param {Function} fn Optional. If the ename parameter was an event name, this * is the handler function. * @param {Object} scope Optional. If the ename parameter was an event name, this * is the scope (this reference) in which the handler function is executed. * @param {Object} opt Optional. If the ename parameter was an event name, this * is the {@link Ext.util.Observable#addListener addListener} options. */ mon : function(item, ename, fn, scope, opt){ this.createMons(); if(Ext.isObject(ename)){ var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/; var 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); }, /** * Removes listeners that were added by the {@link #mon} method. * @param {Observable|Element} item The item from which to remove a listener/listeners. * @param {Object|String} ename The event name, or an object containing event name properties. * @param {Function} fn Optional. If the ename parameter was an event name, this * is the handler function. * @param {Object} scope Optional. If the ename parameter was an event name, this * is the scope (this reference) in which the handler function is executed. */ mun : function(item, ename, fn, scope){ var found, mon; this.createMons(); for(var i = 0, len = this.mons.length; i < len; ++i){ mon = this.mons[i]; if(item === mon.item && ename == mon.ename && fn === mon.fn && scope === mon.scope){ 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 = Ext.extend(Object, { /** * @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 (this reference) in which the * {@link #handler} is executed. Defaults to this Button. */ constructor : function(config){ this.initialConfig = config; this.itemId = config.itemId = (config.itemId || config.id || Ext.id()); this.items = []; }, // private isAction : true, /** * 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 (this reference) in which the function is executed. Defaults to the Component firing the event. */ 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 (this reference) in which the function is executed. Defaults to the Component. */ 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, 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; if(Ext.isDefined(this.lastShadowOffset)) { 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 shadow = this.shadow; if(!this.updating && this.isVisible() && (shadow || this.useShim)){ var shim = this.getShim(), w = this.getWidth(), h = this.getHeight(), l = this.getLeft(true), t = this.getTop(true); if(shadow && !this.shadowDisabled){ if(doShow && !shadow.isVisible()){ shadow.show(this); }else{ shadow.realign(l, t, w, h); } if(shim){ if(doShow){ shim.show(); } // fit the shim behind the shadow, so it is shimmed too var shadowAdj = shadow.el.getXY(), shimStyle = shim.dom.style, shadowSize = shadow.el.getSize(); shimStyle.left = (shadowAdj[0])+'px'; shimStyle.top = (shadowAdj[1])+'px'; shimStyle.width = (shadowSize.width)+'px'; shimStyle.height = (shadowSize.height)+'px'; } }else if(shim){ if(doShow){ shim.show(); } shim.setSize(w, h); shim.setLeftTop(l, t); } } }, // private destroy : function(){ this.hideShim(); if(this.shadow){ this.shadow.hide(); } this.removeAllListeners(); Ext.removeNode(this.dom); delete this.dom; }, 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; }, getConstrainOffset : function(){ return this.shadowOffset; }, 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 }, 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, iea = 0, sw = (w + a.w), sh = (h + a.h), sws = sw + "px", shs = sh + "px", cn, sww; s.left = (l + a.l) + "px"; s.top = (t + a.t) + "px"; if (s.width != sws || s.height != shs) { s.width = sws; s.height = shs; if (!Ext.isIE) { cn = d.childNodes; 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 = [], 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 BoxLayout. /** * @cfg {Number} flex *

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

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

*

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

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

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

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

Note: this config is only used when this BoxComponent is rendered * 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:

*

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

*

Defaults to:


     * {top:0, right:0, bottom:0, left:0}
     * 
*/ /** * @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 {Number} boxMinHeight *

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

*

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

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

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

*

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

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

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

*

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

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

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

*

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

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

True to use height:'auto', false to use fixed height (or allow it to be managed by its parent * 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'
    }],
});
*/ /** * @cfg {Boolean} autoScroll * true to use overflow:'auto' on the components layout element and show scroll bars automatically when * necessary, false to clip any overflowing content (defaults to false). */ /* // private internal config * {Boolean} deferHeight * 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:
    *
  • A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).
  • *
  • A String used to set the CSS width style.
  • *
  • A size object in the format {width: widthValue, height: heightValue}.
  • *
  • undefined to leave the width unchanged.
  • *
* @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:
    *
  • A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).
  • *
  • A String used to set the CSS height style. Animation may not be used.
  • *
  • undefined to leave the height unchanged.
  • *
* @return {Ext.BoxComponent} this */ setSize : function(w, h){ // support for standard size objects if(typeof w == 'object'){ h = w.height; w = w.width; } if (Ext.isDefined(w) && Ext.isDefined(this.boxMinWidth) && (w < this.boxMinWidth)) { w = this.boxMinWidth; } if (Ext.isDefined(h) && Ext.isDefined(this.boxMinHeight) && (h < this.boxMinHeight)) { h = this.boxMinHeight; } if (Ext.isDefined(w) && Ext.isDefined(this.boxMaxWidth) && (w > this.boxMaxWidth)) { w = this.boxMaxWidth; } if (Ext.isDefined(h) && Ext.isDefined(this.boxMaxHeight) && (h > this.boxMaxHeight)) { h = this.boxMaxHeight; } // not rendered if(!this.boxReady){ this.width = w; this.height = h; 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), aw = adj.width, ah = adj.height, rz; if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters 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 {Mixed} width The new width to set. This may be one of:
    *
  • A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit defaultUnit}s (by default, pixels).
  • *
  • A String used to set the CSS width style.
  • *
* @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 {Mixed} height The new height to set. This may be one of:
    *
  • A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit defaultUnit}s (by default, pixels).
  • *
  • A String used to set the CSS height style.
  • *
  • undefined to leave the height unchanged.
  • *
* @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. * @return {Ext.Element} The Element which is to be resized by size managing layouts. */ getResizeEl : function(){ return this.resizeEl || this.el; }, /** * Sets the overflow on the content element of the component. * @param {Boolean} scroll True to allow the Component to auto scroll. * @return {Ext.BoxComponent} this */ setAutoScroll : function(scroll){ if(this.rendered){ this.getContentTarget().setOverflow(scroll ? 'auto' : ''); } this.autoScroll = scroll; return this; }, /** * 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 afterRender : function(){ Ext.BoxComponent.superclass.afterRender.call(this); if(this.resizeEl){ this.resizeEl = Ext.get(this.resizeEl); } if(this.positionEl){ this.positionEl = Ext.get(this.positionEl); } this.boxReady = true; Ext.isDefined(this.autoScroll) && this.setAutoScroll(this.autoScroll); this.setSize(this.width, this.height); if(this.x || this.y){ this.setPosition(this.x, this.y); }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")); document.body.appendChild(proxy.dom); proxy.unselectable(); var cls = 'x-splitbar-proxy'; proxy.addClass(cls + ' ' + (dir == Ext.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v')); 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 *

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

*

The sizing and positioning of child {@link items} is the responsibility of * the Container's layout manager which creates and manages the type of layout * you have in mind. For example:


new Ext.Window({
    width:300, height: 300,
    layout: 'fit', // explicitly set layout manager: override the default (layout:'auto')
    items: [{
        title: 'Panel inside a Window'
    }]
}).show();
     * 
*

If the {@link #layout} configuration is not explicitly specified for * a general purpose container (e.g. Container or Panel) the * {@link Ext.layout.ContainerLayout default layout manager} will be used * which does nothing but render child components sequentially into the * Container (no sizing or positioning will be performed in this situation). * Some container classes implicitly specify a default layout * (e.g. FormPanel specifies layout:'form'). Other specific * purpose classes internally specify/manage their internal layout (e.g. * GridPanel, TabPanel, TreePanel, Toolbar, Menu, etc.).

*

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

    * *
  • Specify as an Object
  • *
      *
    • Example usage:
    • 
      layout: {
          type: 'vbox',
          padding: '5',
          align: 'left'
      }
      
      * *
    • type
    • *

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

      *

      Valid layout type values are:

      *
        *
      • {@link Ext.layout.AbsoluteLayout absolute}
      • *
      • {@link Ext.layout.AccordionLayout accordion}
      • *
      • {@link Ext.layout.AnchorLayout anchor}
      • *
      • {@link Ext.layout.ContainerLayout auto}     Default
      • *
      • {@link Ext.layout.BorderLayout border}
      • *
      • {@link Ext.layout.CardLayout card}
      • *
      • {@link Ext.layout.ColumnLayout column}
      • *
      • {@link Ext.layout.FitLayout fit}
      • *
      • {@link Ext.layout.FormLayout form}
      • *
      • {@link Ext.layout.HBoxLayout hbox}
      • *
      • {@link Ext.layout.MenuLayout menu}
      • *
      • {@link Ext.layout.TableLayout table}
      • *
      • {@link Ext.layout.ToolbarLayout toolbar}
      • *
      • {@link Ext.layout.VBoxLayout vbox}
      • *
      * *
    • Layout specific configuration properties
    • *

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

      * *
    * *
  • Specify as a String
  • *
      *
    • Example usage:
    • 
      layout: 'vbox',
      layoutConfig: {
          padding: '5',
          align: 'left'
      }
      
      *
    • layout
    • *

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


      *
    • {@link #layoutConfig}
    • *

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

      *
*/ /** * @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 (50 milliseconds) or a number of milliseconds, the layout assigned for this container will buffer * the frequency it calculates and does a re-layout of components. This is useful for heavy containers or containers * with a large quantity of sub-components for which frequent layout calls would be expensive. Defaults to 50. */ bufferResize: 50, /** * @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 {@link #layout specify a layout} if needed ! **
*

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:

*
    *
  • any type of object based on {@link Ext.Component}
  • *
  • a fully instanciated object or
  • *
  • an object literal that:
  • *
      *
    • has a specified {@link Ext.Component#xtype xtype}
    • *
    • the {@link Ext.Component#xtype} specified is associated with the Component * desired and should be chosen from one of the available xtypes as listed * in {@link Ext.Component}.
    • *
    • If an {@link Ext.Component#xtype xtype} is not explicitly * specified, the {@link #defaultType} for that Container is used.
    • *
    • will be "lazily instanciated", avoiding the overhead of constructing a fully * instanciated Component object
    • *
*

Notes:

*
    *
  • Ext uses lazy rendering. Child Components will only be rendered * should it become necessary. Items are automatically laid out when they are first * shown (no sizing is done while hidden), or in response to a {@link #doLayout} call.
  • *
  • Do not specify {@link Ext.Panel#contentEl contentEl}/ * {@link Ext.Panel#html html} with items.
  • *
*/ /** * @cfg {Object|Function} defaults *

This option is a means of applying default settings to all added items whether added through the {@link #items} * config or via the {@link #add} or {@link #insert} methods.

*

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

*

If the defaults option is specified as a function, then the function will be called using this Container as the * scope (this reference) and passing the added item as the first parameter. Any resulting object * from that call is then applied to the item as default properties.

*

For example, to automatically apply padding to the body of each of a set of * contained {@link Ext.Panel} items, you could pass: defaults: {bodyStyle:'padding:15px'}.

*

Usage:


defaults: {               // defaults are applied to items, not the container
    autoScroll:true
},
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', /** @cfg {String} resizeEvent * The event to listen to for resizing in layouts. Defaults to 'resize'. */ resizeEvent: 'resize', /** * @cfg {Array} bubbleEvents *

An array of events that, when fired, should be bubbled to any parent container. * See {@link Ext.util.Observable#enableBubble}. * Defaults to ['add', 'remove']. */ bubbleEvents: ['add', 'remove'], // private initComponent : function(){ Ext.Container.superclass.initComponent.call(this); 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' ); /** * 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; 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.layout = layout; this.initItems(); layout.setContainer(this); }, afterRender: function(){ // Render this Container, this should be done before setLayout is called which // will hook onResize Ext.Container.superclass.afterRender.call(this); if(!this.layout){ this.layout = 'auto'; } if(Ext.isObject(this.layout) && !this.layout.layout){ this.layoutConfig = this.layout; this.layout = this.layoutConfig.type; } if(Ext.isString(this.layout)){ this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig); } this.setLayout(this.layout); // If a CardLayout, the active item set if(this.activeItem !== undefined && this.layout.setActiveItem){ var item = this.activeItem; delete this.activeItem; this.layout.setActiveItem(item); } // If we have no ownerCt, render and size all children if(!this.ownerCt){ this.doLayout(false, true); } // This is a manually configured flag set by users in conjunction with renderTo. // Not to be confused with the flag by the same name used in Layouts. if(this.monitorResize === true){ Ext.EventManager.onWindowResize(this.doLayout, this, [false]); } }, /** *

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

    *
  • Fires the {@link #beforeadd} event before adding
  • *
  • The Container's {@link #defaults default config values} will be applied * accordingly (see {@link #defaults} for details).
  • *
  • Fires the {@link #add} event after the component has been added.
  • *
*

Notes : *

    *
  • If the Container is already rendered when add * is called, you may need to call {@link #doLayout} to refresh the view which causes * any unrendered child Components to be rendered. This is required so that you can * add multiple child components if needed while only refreshing the layout * once. For example:
    
    var tb = new {@link Ext.Toolbar}();
    tb.render(document.body);  // toolbar is rendered
    tb.add({text:'Button 1'}); // add multiple items ({@link #defaultType} for {@link Ext.Toolbar Toolbar} is 'button')
    tb.add({text:'Button 2'});
    tb.{@link #doLayout}();             // refresh the layout
         * 
  • *
  • Warning: Containers directly managed by the BorderLayout layout manager * may not be removed or added. See the Notes for {@link Ext.layout.BorderLayout BorderLayout} * for more details.
  • *
* @param {...Object/Array} component *

Either one or more Components to add or an Array of Components to add. See * {@link #items} for additional information.

* @return {Ext.Component/Array} The Components that were added. */ add : function(comp){ this.initItems(); var args = arguments.length > 1; if(args || Ext.isArray(comp)){ var result = []; Ext.each(args ? arguments : comp, function(c){ result.push(this.add(c)); }, this); return result; } var c = this.lookupComponent(this.applyDefaults(comp)); var index = this.items.length; if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){ this.items.add(c); // *onAdded c.onAdded(this, index); this.onAdd(c); this.fireEvent('add', this, c, index); } return c; }, onAdd : function(c){ // Empty template method }, // private onAdded : function(container, pos) { //overridden here so we can cascade down, not worth creating a template method. this.ownerCt = container; this.initRef(); //initialize references for child items this.cascade(function(c){ c.initRef(); }); this.fireEvent('added', this, container, pos); }, /** * Inserts a Component into this Container at a specified index. Fires the * {@link #beforeadd} event before inserting, then fires the {@link #add} event after the * 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) { var args = arguments, length = args.length, result = [], i, c; this.initItems(); if (length > 2) { for (i = length - 1; i >= 1; --i) { result.push(this.insert(index, args[i])); } return result; } c = this.lookupComponent(this.applyDefaults(comp)); index = Math.min(index, this.items.length); if (this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false) { if (c.ownerCt == this) { this.items.remove(c); } this.items.insert(index, c); c.onAdded(this, index); this.onAdd(c); this.fireEvent('add', this, c, index); } return c; }, // private applyDefaults : function(c){ var d = this.defaults; if(d){ if(Ext.isFunction(d)){ d = d.call(this, c); } if(Ext.isString(c)){ c = Ext.ComponentMgr.get(c); Ext.apply(c, d); }else if(!c.events){ Ext.applyIf(c.isAction ? c.initialConfig : c, d); }else{ Ext.apply(c, d); } } 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.doRemove(c, autoDestroy); this.fireEvent('remove', this, c); } return c; }, onRemove: function(c){ // Empty template method }, // private doRemove: function(c, autoDestroy){ var l = this.layout, hasLayout = l && this.rendered; if(hasLayout){ l.onRemove(c); } this.items.remove(c); c.onRemoved(); this.onRemove(c); if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){ c.destroy(); } if(hasLayout){ l.afterRemove(c); } }, /** * Removes all components from this container. * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function. * 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: *
    *
  • a String : representing the {@link Ext.Component#itemId itemId} * or {@link Ext.Component#id id} of the child component
  • *
  • a Number : representing the position of the child component * within the {@link #items} property
  • *
*

For additional information see {@link Ext.util.MixedCollection#get}. * @return Ext.Component The component (if found). */ getComponent : function(comp){ if(Ext.isObject(comp)){ comp = comp.getItemId(); } return this.items.get(comp); }, // private lookupComponent : function(comp){ if(Ext.isString(comp)){ return Ext.ComponentMgr.get(comp); }else if(!comp.events){ return this.createComponent(comp); } return comp; }, // private createComponent : function(config, defaultType){ if (config.render) { return config; } // add in ownerCt at creation time but then immediately // remove so that onBeforeAdd can handle it var c = Ext.create(Ext.apply({ ownerCt: this }, config), defaultType || this.defaultType); delete c.initialConfig.ownerCt; delete c.ownerCt; return c; }, /** * @private * We can only lay out if there is a view area in which to layout. * display:none on the layout target, *or any of its parent elements* will mean it has no view area. */ canLayout : function() { var el = this.getVisibilityEl(); return el && el.dom && !el.isStyle("display", "none"); }, /** * 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 = force || this.forceLayout; if(this.collapsed || !this.canLayout()){ this.deferLayout = this.deferLayout || !shallow; if(!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.doLayout(false, forceLayout); } } } if(rendered){ this.onLayout(shallow, forceLayout); } // Initial layout completed this.hasLayout = true; delete this.forceLayout; }, onLayout : Ext.emptyFn, // private shouldBufferLayout: function(){ /* * Returns true if the container should buffer a layout. * This is true only if the container has previously been laid out * and has a parent container that is pending a layout. */ var hl = this.hasLayout; if(this.ownerCt){ // Only ever buffer if we've laid out the first time and we have one pending. return hl ? !this.hasLayoutPending() : false; } // Never buffer initial layout return hl; }, // private hasLayoutPending: function(){ // Traverse hierarchy to see if any parent container has a pending layout. var pending = false; this.ownerCt.bubble(function(c){ if(c.layoutPending){ pending = true; return false; } }); return pending; }, onShow : function(){ // removes css classes that were added to hide Ext.Container.superclass.onShow.call(this); // If we were sized during the time we were hidden, layout. if(Ext.isDefined(this.deferLayout)){ delete this.deferLayout; 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.AutoLayout(this.layoutConfig); this.setLayout(layout); } return this.layout; }, // private beforeDestroy : function(){ var c; if(this.items){ while(c = this.items.first()){ this.doRemove(c, true); } } if(this.monitorResize){ Ext.EventManager.removeResizeListener(this.doLayout, this); } Ext.destroy(this.layout); Ext.Container.superclass.beforeDestroy.call(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 * @deprecated Fairly useless method, since you can just use Ext.getCmp. Should be removed for 4.0 * If you need to test if an id belongs to a container, you can use getCmp and findParent*. * @return Ext.Component */ findById : function(id){ var m = null, ct = this; this.cascade(function(c){ if(ct != c && c.id === id){ m = c; return false; } }); return m; }, /** * 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 * @deprecated Should be removed in 4.0, since getComponent does the same thing. * @return {Ext.Component} Ext.Component */ get : function(key){ return this.getComponent(key); } }); Ext.Container.LAYOUTS = {}; Ext.reg('container', Ext.Container); /** * @class Ext.layout.ContainerLayout *

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 = Ext.extend(Object, { /** * @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: *

    *
  • {@link Ext.layout.AbsoluteLayout Absolute Layout} : 'x-abs-layout-item'
  • *
  • {@link Ext.layout.Box Box Layout} : 'x-box-item'
  • *
  • {@link Ext.layout.ColumnLayout Column Layout} : 'x-column'
  • *
* 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, constructor : function(config){ this.id = Ext.id(null, 'ext-layout-'); Ext.apply(this, config); }, type: 'container', /* Workaround for how IE measures autoWidth elements. It prefers bottom-up measurements whereas other browser prefer top-down. We will hide all target child elements before we measure and put them back to get an accurate measurement. */ IEMeasureHack : function(target, viewFlag) { var tChildren = target.dom.childNodes, tLen = tChildren.length, c, d = [], e, i, ret; for (i = 0 ; i < tLen ; i++) { c = tChildren[i]; e = Ext.get(c); if (e) { d[i] = e.getStyle('display'); e.setStyle({display: 'none'}); } } ret = target ? target.getViewSize(viewFlag) : {}; for (i = 0 ; i < tLen ; i++) { c = tChildren[i]; e = Ext.get(c); if (e) { e.setStyle({display: d[i]}); } } return ret; }, // Placeholder for the derived layouts getLayoutTargetSize : Ext.EmptyFn, // private layout : function(){ var ct = this.container, target = ct.getLayoutTarget(); if(!(this.hasLayout || Ext.isEmpty(this.targetCls))){ target.addClass(this.targetCls); } this.onLayout(ct, target); ct.fireEvent('afterlayout', ct, this); }, // private onLayout : function(ct, target){ this.renderAll(ct, target); }, // private isValidParent : function(c, target){ return target && c.getPositionEl().dom.parentNode == (target.dom || target); }, // private renderAll : function(ct, target){ var items = ct.items.items, i, c, len = items.length; for(i = 0; i < len; i++) { c = items[i]; if(c && (!c.rendered || !this.isValidParent(c, target))){ this.renderItem(c, i, target); } } }, /** * @private * Renders the given Component into the target Element. If the Component is already rendered, * it is moved to the provided target instead. * @param {Ext.Component} c The Component to render * @param {Number} position The position within the target to render the item to * @param {Ext.Element} target The target Element */ renderItem : function(c, position, target){ if (c) { if (!c.rendered) { c.render(target, position); this.configureItem(c); } else if (!this.isValidParent(c, target)) { if (Ext.isNumber(position)) { position = target.dom.childNodes[position]; } target.dom.insertBefore(c.getPositionEl().dom, position || null); c.container = target; this.configureItem(c); } } }, // private. // Get all rendered items to lay out. getRenderedItems: function(ct){ var t = ct.getLayoutTarget(), cti = ct.items.items, len = cti.length, i, c, items = []; for (i = 0; i < len; i++) { if((c = cti[i]).rendered && this.isValidParent(c, t) && c.shouldLayout !== false){ items.push(c); } }; return items; }, /** * @private * Applies extraCls and hides the item if renderHidden is true */ configureItem: function(c){ if (this.extraCls) { var t = c.getPositionEl ? c.getPositionEl() : c; t.addClass(this.extraCls); } // If we are forcing a layout, do so *before* we hide so elements have height/width if (c.doLayout && this.forceLayout) { c.doLayout(); } if (this.renderHidden && c != this.activeItem) { c.hide(); } }, onRemove: function(c){ if(this.activeItem == c){ delete this.activeItem; } if(c.rendered && this.extraCls){ var t = c.getPositionEl ? c.getPositionEl() : c; t.removeClass(this.extraCls); } }, afterRemove: function(c){ if(c.removeRestore){ c.removeMode = 'container'; delete c.removeRestore; } }, // private onResize: function(){ var ct = this.container, b; if(ct.collapsed){ return; } if(b = ct.bufferResize && ct.shouldBufferLayout()){ if(!this.resizeTask){ this.resizeTask = new Ext.util.DelayedTask(this.runLayout, this); this.resizeBuffer = Ext.isNumber(b) ? b : 50; } ct.layoutPending = true; this.resizeTask.delay(this.resizeBuffer); }else{ this.runLayout(); } }, runLayout: function(){ var ct = this.container; this.layout(); ct.onLayout(); delete ct.layoutPending; }, // private setContainer : function(ct){ /** * This monitorResize flag will be renamed soon as to avoid confusion * with the Container version which hooks onWindowResize to doLayout * * monitorResize flag in this context attaches the resize event between * a container and it's layout */ if(this.monitorResize && ct != this.container){ var old = this.container; if(old){ old.un(old.resizeEvent, this.onResize, this); } if(ct){ ct.on(ct.resizeEvent, this.onResize, this); } } this.container = ct; }, /** * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result) * @param {Number|String} v The encoded margins * @return {Object} An object with margin sizes for top, right, bottom and left */ parseMargins : function(v){ if (Ext.isNumber(v)) { v = v.toString(); } var ms = v.split(' '), len = ms.length; if (len == 1) { ms[1] = ms[2] = ms[3] = ms[0]; } else if(len == 2) { ms[2] = ms[0]; ms[3] = ms[1]; } else 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 Ext.Template Ext.Template} used by Field rendering layout classes (such as * {@link Ext.layout.FormLayout}) to create the DOM structure of a fully wrapped, * labeled and styled form Field. A default Template is supplied, but this may be * overriden to create custom field structures. The template processes values returned from * {@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 : function(){ // Stop any buffered layout tasks if(this.resizeTask && this.resizeTask.cancel){ this.resizeTask.cancel(); } if(this.container) { this.container.un(this.container.resizeEvent, this.onResize, this); } if(!Ext.isEmpty(this.targetCls)){ var target = this.container.getLayoutTarget(); if(target){ target.removeClass(this.targetCls); } } } });/** * @class Ext.layout.AutoLayout *

The AutoLayout is the default layout manager delegated by {@link Ext.Container} to * render any child Components when no {@link Ext.Container#layout layout} is configured into * a {@link Ext.Container Container}.. AutoLayout provides only a passthrough of any layout calls * to any child containers.

*/ Ext.layout.AutoLayout = Ext.extend(Ext.layout.ContainerLayout, { type: 'auto', monitorResize: true, onLayout : function(ct, target){ Ext.layout.AutoLayout.superclass.onLayout.call(this, ct, target); var cs = this.getRenderedItems(ct), len = cs.length, i, c; for(i = 0; i < len; i++){ c = cs[i]; if (c.doLayout){ // Shallow layout children c.doLayout(true); } } } }); Ext.Container.LAYOUTS['auto'] = Ext.layout.AutoLayout; /** * @class Ext.layout.FitLayout * @extends Ext.layout.ContainerLayout *

This is a base class for layouts that contain a single item that automatically expands to fill the layout's * 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, type: 'fit', getLayoutTargetSize : function() { var target = this.container.getLayoutTarget(); if (!target) { return {}; } // Style Sized (scrollbars not included) return target.getStyleSize(); }, // private onLayout : function(ct, target){ Ext.layout.FitLayout.superclass.onLayout.call(this, ct, target); if(!ct.collapsed){ this.setItemSize(this.activeItem || ct.items.itemAt(0), this.getLayoutTargetSize()); } }, // 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, type: 'card', /** * 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){ var ai = this.activeItem, ct = this.container; item = ct.getComponent(item); // Is this a valid, different card? if(item && ai != item){ // Changing cards, hide the current one if(ai){ ai.hide(); if (ai.hidden !== true) { return false; } ai.fireEvent('deactivate', ai); } var layout = item.doLayout && (this.layoutOnCardChange || !item.rendered); // Change activeItem reference this.activeItem = item; // The container is about to get a recursive layout, remove any deferLayout reference // because it will trigger a redundant layout. delete item.deferLayout; // Show the new component item.show(); this.layout(); if(layout){ item.doLayout(); } item.fireEvent('activate', item); } }, // 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, type : 'anchor', /** * @cfg {String} defaultAnchor * * default anchor for all child container items applied if no anchor or specific width is set on the child item. Defaults to '100%'. * */ defaultAnchor : '100%', parseAnchorRE : /^(r|right|b|bottom)$/i, getLayoutTargetSize : function() { var target = this.container.getLayoutTarget(), ret = {}; if (target) { ret = target.getViewSize(); // IE in strict mode will return a width of 0 on the 1st pass of getViewSize. // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly // with getViewSize if (Ext.isIE && Ext.isStrict && ret.width == 0){ ret = target.getStyleSize(); } ret.width -= target.getPadding('lr'); ret.height -= target.getPadding('tb'); } return ret; }, // private onLayout : function(container, target) { Ext.layout.AnchorLayout.superclass.onLayout.call(this, container, target); var size = this.getLayoutTargetSize(), containerWidth = size.width, containerHeight = size.height, overflow = target.getStyle('overflow'), components = this.getRenderedItems(container), len = components.length, boxes = [], box, anchorWidth, anchorHeight, component, anchorSpec, calcWidth, calcHeight, anchorsArray, totalHeight = 0, i, el; if(containerWidth < 20 && containerHeight < 20){ return; } // find the container anchoring size if(container.anchorSize) { if(typeof container.anchorSize == 'number') { anchorWidth = container.anchorSize; } else { anchorWidth = container.anchorSize.width; anchorHeight = container.anchorSize.height; } } else { anchorWidth = container.initialConfig.width; anchorHeight = container.initialConfig.height; } for(i = 0; i < len; i++) { component = components[i]; el = component.getPositionEl(); // If a child container item has no anchor and no specific width, set the child to the default anchor size if (!component.anchor && component.items && !Ext.isNumber(component.width) && !(Ext.isIE6 && Ext.isStrict)){ component.anchor = this.defaultAnchor; } if(component.anchor) { anchorSpec = component.anchorSpec; // cache all anchor values if(!anchorSpec){ anchorsArray = component.anchor.split(' '); component.anchorSpec = anchorSpec = { right: this.parseAnchor(anchorsArray[0], component.initialConfig.width, anchorWidth), bottom: this.parseAnchor(anchorsArray[1], component.initialConfig.height, anchorHeight) }; } calcWidth = anchorSpec.right ? this.adjustWidthAnchor(anchorSpec.right(containerWidth) - el.getMargins('lr'), component) : undefined; calcHeight = anchorSpec.bottom ? this.adjustHeightAnchor(anchorSpec.bottom(containerHeight) - el.getMargins('tb'), component) : undefined; if(calcWidth || calcHeight) { boxes.push({ component: component, width: calcWidth || undefined, height: calcHeight || undefined }); } } } for (i = 0, len = boxes.length; i < len; i++) { box = boxes[i]; box.component.setSize(box.width, box.height); } if (overflow && overflow != 'hidden' && !this.adjustmentPass) { var newTargetSize = this.getLayoutTargetSize(); if (newTargetSize.width != size.width || newTargetSize.height != size.height){ this.adjustmentPass = true; this.onLayout(container, target); } } delete this.adjustmentPass; }, // private parseAnchor : function(a, start, cstart) { if (a && a != 'none') { var last; // standard anchor if (this.parseAnchorRE.test(a)) { var diff = cstart - start; return function(v){ if(v !== last){ last = v; return v - diff; } }; // percentage } else if(a.indexOf('%') != -1) { var ratio = parseFloat(a.replace('%', ''))*.01; return function(v){ if(v !== last){ last = v; return Math.floor(v*ratio); } }; // simple offset adjustment } else { a = parseInt(a, 10); if (!isNaN(a)) { 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, type: 'column', extraCls: 'x-column', scrollOffset : 0, // private targetCls: 'x-column-layout-ct', isValidParent : function(c, target){ return this.innerCt && c.getPositionEl().dom.parentNode == this.innerCt.dom; }, getLayoutTargetSize : function() { var target = this.container.getLayoutTarget(), ret; if (target) { ret = target.getViewSize(); // IE in strict mode will return a width of 0 on the 1st pass of getViewSize. // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly // with getViewSize if (Ext.isIE && Ext.isStrict && ret.width == 0){ ret = target.getStyleSize(); } ret.width -= target.getPadding('lr'); ret.height -= target.getPadding('tb'); } return ret; }, renderAll : function(ct, target) { if(!this.innerCt){ // 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'}); } Ext.layout.ColumnLayout.superclass.renderAll.call(this, ct, this.innerCt); }, // private onLayout : function(ct, target){ var cs = ct.items.items, len = cs.length, c, i, m, margins = []; this.renderAll(ct, target); var size = this.getLayoutTargetSize(); if(size.width < 1 && size.height < 1){ // display none? return; } var w = size.width - this.scrollOffset, h = size.height, pw = w; this.innerCt.setWidth(w); // some columns can be percentages while others are fixed // so we need to make 2 passes for(i = 0; i < len; i++){ c = cs[i]; m = c.getPositionEl().getMargins('lr'); margins[i] = m; if(!c.columnWidth){ pw -= (c.getWidth() + m); } } pw = pw < 0 ? 0 : pw; for(i = 0; i < len; i++){ c = cs[i]; m = margins[i]; if(c.columnWidth){ c.setSize(Math.floor(c.columnWidth * pw) - m); } } // Browsers differ as to when they account for scrollbars. We need to re-measure to see if the scrollbar // spaces were accounted for properly. If not, re-layout. if (Ext.isIE) { if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) { var ts = this.getLayoutTargetSize(); if (ts.width != size.width){ this.adjustmentPass = true; this.onLayout(ct, target); } } } delete this.adjustmentPass; } /** * @property activeItem * @hide */ }); 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, type: 'border', targetCls: 'x-border-layout-ct', getLayoutTargetSize : function() { var target = this.container.getLayoutTarget(); return target ? target.getViewSize() : {}; }, // private onLayout : function(ct, target){ var collapsed, i, c, pos, items = ct.items.items, len = items.length; if(!this.rendered){ collapsed = []; for(i = 0; i < len; i++) { c = items[i]; pos = c.region; if(c.collapsed){ collapsed.push(c); } c.collapsed = false; if(!c.rendered){ c.render(target, i); c.getPositionEl().addClass('x-border-panel'); } 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 = this.getLayoutTargetSize(); 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, centerW = w, centerH = h, centerY = 0, centerX = 0, n = this.north, s = this.south, west = this.west, e = this.east, c = this.center, b, m, totalWidth, totalHeight; if(!c && Ext.layout.BorderLayout.WARN !== false){ throw 'No center region defined in BorderLayout ' + ct.id; } if(n && n.isVisible()){ b = n.getSize(); 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()){ b = s.getSize(); m = s.getMargins(); b.width = w - (m.left+m.right); b.x = m.left; totalHeight = (b.height + m.top + m.bottom); b.y = h - totalHeight + m.top; centerH -= totalHeight; s.applyLayout(b); } if(west && west.isVisible()){ b = west.getSize(); m = west.getMargins(); b.height = centerH - (m.top+m.bottom); b.x = m.left; b.y = centerY + m.top; totalWidth = (b.width + m.left + m.right); centerX += totalWidth; centerW -= totalWidth; west.applyLayout(b); } if(e && e.isVisible()){ b = e.getSize(); m = e.getMargins(); b.height = centerH - (m.top+m.bottom); 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){ 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(i = 0, len = collapsed.length; i < len; i++){ collapsed[i].collapse(false); } } if(Ext.isIE && Ext.isStrict){ // workaround IE strict repainting issue target.repaint(); } // Putting a border layout into an overflowed container is NOT correct and will make a second layout pass necessary. if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) { var ts = this.getLayoutTargetSize(); if (ts.width != size.width || ts.height != size.height){ this.adjustmentPass = true; this.onLayout(ct, target); } } delete this.adjustmentPass; }, destroy: function() { var r = ['north', 'south', 'east', 'west'], i, region; for (i = 0; i < r.length; i++) { 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.expandToolEl = 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.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(); var el = this.panel.getEl(); this.originalZIndex = el.getStyle('z-index'); 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){ if(this.isSlid){ this.afterSlideIn(); } 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', this.originalZIndex); 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){ this.autoHideSlideTask = new Ext.util.DelayedTask(this.slideIn, this); this.autoHideHd = { "mouseout": function(e){ if(!e.within(this.el, true)){ this.autoHideSlideTask.delay(500); } }, "mouseover" : function(e){ this.autoHideSlideTask.cancel(); }, scope : this }; } this.el.on(this.autoHideHd); this.collapsedEl.on(this.autoHideHd); } }, // private clearAutoHide : function(){ if(this.autoHide !== false){ this.el.un("mouseout", this.autoHideHd.mouseout); this.el.un("mouseover", this.autoHideHd.mouseover); this.collapsedEl.un("mouseout", this.autoHideHd.mouseout); this.collapsedEl.un("mouseover", this.autoHideHd.mouseover); } }, // 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, dh, pc; if(ts && ts.toggle){ ts.toggle.hide(); } this.el.show(); // Temporarily clear the collapsed flag so we can onResize the panel on the slide pc = this.panel.collapsed; this.panel.collapsed = false; if(this.position == 'east' || this.position == 'west'){ // Temporarily clear the deferHeight flag so we can size the height on the slide dh = this.panel.deferHeight; this.panel.deferHeight = false; this.panel.setSize(undefined, this.collapsedEl.getHeight()); // Put the deferHeight flag back after setSize this.panel.deferHeight = dh; }else{ this.panel.setSize(this.collapsedEl.getWidth(), undefined); } // Put the collapsed flag back after onResize this.panel.collapsed = pc; this.restoreLT = [this.el.dom.style.left, this.el.dom.style.top]; this.el.alignTo(this.collapsedEl, this.getCollapseAnchor()); this.el.setStyle("z-index", this.floatingZIndex+2); 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; } }, destroy : function(){ if (this.autoHideSlideTask && this.autoHideSlideTask.cancel){ this.autoHideSlideTask.cancel(); } Ext.destroyMembers(this, 'miniCollapsedEl', 'collapsedEl', 'expandToolEl'); } }; /** * @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.layout.BorderLayout.SplitRegion.superclass.destroy.call(this); } }); 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 */ /** * @cfg {Boolean} trackLabels * True to show/hide the field label when the field is hidden. Defaults to true. */ trackLabels: true, type: 'form', onRemove: function(c){ Ext.layout.FormLayout.superclass.onRemove.call(this, c); if(this.trackLabels){ c.un('show', this.onFieldShow, this); c.un('hide', this.onFieldHide, this); } // check for itemCt, since we may be removing a fieldset or something similar var el = c.getPositionEl(), ct = c.getItemCt && c.getItemCt(); if (c.rendered && ct) { if (el && el.dom) { el.insertAfter(ct); } Ext.destroy(ct); Ext.destroyMembers(c, 'label', 'itemCt'); if (c.customItemCt) { Ext.destroyMembers(c, 'getItemCt', 'customItemCt'); } } }, // private setContainer : function(ct){ Ext.layout.FormLayout.superclass.setContainer.call(this, ct); if(ct.labelAlign){ ct.addClass('x-form-label-'+ct.labelAlign); } if(ct.hideLabels){ Ext.apply(this, { labelStyle: 'display:none', elementStyle: 'padding-left:0;', labelAdjust: 0 }); }else{ this.labelSeparator = Ext.isDefined(ct.labelSeparator) ? ct.labelSeparator : this.labelSeparator; ct.labelWidth = ct.labelWidth || 100; if(Ext.isNumber(ct.labelWidth)){ var pad = Ext.isNumber(ct.labelPad) ? ct.labelPad : 5; Ext.apply(this, { labelAdjust: ct.labelWidth + pad, labelStyle: 'width:' + ct.labelWidth + 'px;', elementStyle: 'padding-left:' + (ct.labelWidth + pad) + 'px' }); } if(ct.labelAlign == 'top'){ Ext.apply(this, { labelStyle: 'width:auto;', labelAdjust: 0, elementStyle: 'padding-left:0;' }); } } }, // private isHide: function(c){ return c.hideLabel || this.container.hideLabels; }, onFieldShow: function(c){ c.getItemCt().removeClass('x-hide-' + c.hideMode); // Composite fields will need to layout after the container is made visible if (c.isComposite) { c.doLayout(); } }, onFieldHide: function(c){ c.getItemCt().addClass('x-hide-' + c.hideMode); }, //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.isFormField || c.fieldLabel) && c.inputType != 'hidden'){ var args = this.getTemplateArgs(c); if(Ext.isNumber(position)){ position = target.dom.childNodes[position] || null; } if(position){ c.itemCt = this.fieldTpl.insertBefore(position, args, true); }else{ c.itemCt = this.fieldTpl.append(target, args, true); } if(!c.getItemCt){ // Non form fields don't have getItemCt, apply it here // This will get cleaned up in onRemove Ext.apply(c, { getItemCt: function(){ return c.itemCt; }, customItemCt: true }); } c.label = c.getItemCt().child('label.x-form-item-label'); if(!c.rendered){ c.render('x-form-el-' + c.id); }else if(!this.isValidParent(c, target)){ Ext.fly('x-form-el-' + c.id).appendChild(c.getPositionEl()); } if(this.trackLabels){ if(c.hidden){ this.onFieldHide(c); } c.on({ scope: this, show: this.onFieldShow, hide: this.onFieldHide }); } this.configureItem(c); }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 (Ext.form.Field} field The {@link Ext.form.Field Field} being rendered. * @return {Object} An object hash containing the properties required to render the Field. */ getTemplateArgs: function(field) { var noLabelSep = !field.fieldLabel || field.hideLabel, itemCls = (field.itemCls || this.container.itemCls || '') + (field.hideLabel ? ' x-hide-label' : ''); // IE9 quirks needs an extra, identifying class on wrappers of TextFields if (Ext.isIE9 && Ext.isIEQuirks && field instanceof Ext.form.TextField) { itemCls += ' x-input-wrapper'; } return { id : field.id, label : field.fieldLabel, itemCls : itemCls, clearCls : field.clearCls || 'x-form-clear-left', labelStyle : this.getLabelStyle(field.labelStyle), elementStyle : this.elementStyle || '', labelSeparator: noLabelSep ? '' : (Ext.isDefined(field.labelSeparator) ? field.labelSeparator : this.labelSeparator) }; }, // private adjustWidthAnchor: function(value, c){ if(c.label && !this.isHide(c) && (this.container.labelAlign != 'top')){ var adjust = Ext.isIE6 || (Ext.isIE && !Ext.isStrict); return value - this.labelAdjust + (adjust ? -3 : 0); } return value; }, adjustHeightAnchor : function(value, c){ if(c.label && !this.isHide(c) && (this.container.labelAlign == 'top')){ return value - c.label.getHeight(); } return value; }, // private isValidParent : function(c, target){ return target && this.container.getEl().contains(c.getPositionEl()); } /** * @property activeItem * @hide */ }); Ext.Container.LAYOUTS['form'] = Ext.layout.FormLayout; /** * @class Ext.layout.AccordionLayout * @extends Ext.layout.FitLayout *

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

*

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

*

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

*

Example usage:

*

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, type: 'accordion', 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.setActiveItem(c, true); }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); }, onRemove: function(c){ Ext.layout.AccordionLayout.superclass.onRemove.call(this, c); if(c.rendered){ c.header.removeClass('x-accordion-hd'); } c.un('beforeexpand', this.beforeExpand, this); }, // private beforeExpand : function(p, anim){ var ai = this.activeItem; 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.setActive(p); if(this.activeOnTop){ p.el.dom.parentNode.insertBefore(p.el.dom, p.el.dom.parentNode.firstChild); } // Items have been hidden an possibly rearranged, we need to get the container size again. this.layout(); }, // private setItemSize : function(item, size){ if(this.fill && item){ var hh = 0, i, ct = this.getRenderedItems(this.container), len = ct.length, p; // Add up all the header heights for (i = 0; i < len; i++) { if((p = ct[i]) != item && !p.hidden){ hh += p.header.getHeight(); } }; // Subtract the header heights from the container size size.height -= hh; // Call setSize on the container to set the correct height. For Panels, deferedHeight // will simply store this size for when the expansion is done. item.setSize(size); } }, /** * 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){ this.setActive(item, true); }, // private setActive : function(item, expand){ var ai = this.activeItem; item = this.container.getComponent(item); if(ai != item){ if(item.rendered && item.collapsed && expand){ item.expand(); }else{ if(ai){ ai.fireEvent('deactivate', ai); } this.activeItem = item; item.fireEvent('activate', item); } } } }); Ext.Container.LAYOUTS.accordion = Ext.layout.AccordionLayout; //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, type: 'table', targetCls: 'x-table-layout-ct', /** * @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){ // Ensure we have our inner table to get cells to render into. if(!this.table){ this.table = target.createChild( Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true); } if(c && !c.rendered){ c.render(this.getNextCell(c)); this.configureItem(c); }else if(c && !this.isValidParent(c, target)){ var container = this.getNextCell(c); container.insertBefore(c.getPositionEl().dom, null); c.container = Ext.get(container); this.configureItem(c); } }, // private isValidParent : function(c, target){ return c.getPositionEl().up('table', 5).dom.parentNode === (target.dom || target); }, destroy: function(){ delete this.table; Ext.layout.TableLayout.superclass.destroy.call(this); } /** * @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', type: 'absolute', 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 *

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

*

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

*
*

Defaults to: "0"

*/ padding : '0', // documented in subclasses pack : 'start', // private monitorResize : true, type: 'box', scrollOffset : 0, extraCls : 'x-box-item', targetCls : 'x-box-layout-ct', innerCls : 'x-box-inner', constructor : function(config){ Ext.layout.BoxLayout.superclass.constructor.call(this, config); if (Ext.isString(this.defaultMargins)) { this.defaultMargins = this.parseMargins(this.defaultMargins); } var handler = this.overflowHandler; if (typeof handler == 'string') { handler = { type: handler }; } var handlerType = 'none'; if (handler && handler.type != undefined) { handlerType = handler.type; } var constructor = Ext.layout.boxOverflow[handlerType]; if (constructor[this.type]) { constructor = constructor[this.type]; } this.overflowHandler = new constructor(this, handler); }, /** * @private * Runs the child box calculations and caches them in childBoxCache. Subclasses can used these cached values * when laying out */ onLayout: function(container, target) { Ext.layout.BoxLayout.superclass.onLayout.call(this, container, target); var tSize = this.getLayoutTargetSize(), items = this.getVisibleItems(container), calcs = this.calculateChildBoxes(items, tSize), boxes = calcs.boxes, meta = calcs.meta; //invoke the overflow handler, if one is configured if (tSize.width > 0) { var handler = this.overflowHandler, method = meta.tooNarrow ? 'handleOverflow' : 'clearOverflow'; var results = handler[method](calcs, tSize); if (results) { if (results.targetSize) { tSize = results.targetSize; } if (results.recalculate) { items = this.getVisibleItems(container); calcs = this.calculateChildBoxes(items, tSize); boxes = calcs.boxes; } } } /** * @private * @property layoutTargetLastSize * @type Object * Private cache of the last measured size of the layout target. This should never be used except by * BoxLayout subclasses during their onLayout run. */ this.layoutTargetLastSize = tSize; /** * @private * @property childBoxCache * @type Array * Array of the last calculated height, width, top and left positions of each visible rendered component * within the Box layout. */ this.childBoxCache = calcs; this.updateInnerCtSize(tSize, calcs); this.updateChildBoxes(boxes); // Putting a box layout into an overflowed container is NOT correct and will make a second layout pass necessary. this.handleTargetOverflow(tSize, container, target); }, /** * Resizes and repositions each child component * @param {Array} boxes The box measurements */ updateChildBoxes: function(boxes) { for (var i = 0, length = boxes.length; i < length; i++) { var box = boxes[i], comp = box.component; if (box.dirtySize) { comp.setSize(box.width, box.height); } // Don't set positions to NaN if (isNaN(box.left) || isNaN(box.top)) { continue; } comp.setPosition(box.left, box.top); } }, /** * @private * Called by onRender just before the child components are sized and positioned. This resizes the innerCt * to make sure all child items fit within it. We call this before sizing the children because if our child * items are larger than the previous innerCt size the browser will insert scrollbars and then remove them * again immediately afterwards, giving a performance hit. * Subclasses should provide an implementation. * @param {Object} currentSize The current height and width of the innerCt * @param {Array} calculations The new box calculations of all items to be laid out */ updateInnerCtSize: function(tSize, calcs) { var align = this.align, padding = this.padding, width = tSize.width, height = tSize.height; if (this.type == 'hbox') { var innerCtWidth = width, innerCtHeight = calcs.meta.maxHeight + padding.top + padding.bottom; if (align == 'stretch') { innerCtHeight = height; } else if (align == 'middle') { innerCtHeight = Math.max(height, innerCtHeight); } } else { var innerCtHeight = height, innerCtWidth = calcs.meta.maxWidth + padding.left + padding.right; if (align == 'stretch') { innerCtWidth = width; } else if (align == 'center') { innerCtWidth = Math.max(width, innerCtWidth); } } this.innerCt.setSize(innerCtWidth || undefined, innerCtHeight || undefined); }, /** * @private * This should be called after onLayout of any BoxLayout subclass. If the target's overflow is not set to 'hidden', * we need to lay out a second time because the scrollbars may have modified the height and width of the layout * target. Having a Box layout inside such a target is therefore not recommended. * @param {Object} previousTargetSize The size and height of the layout target before we just laid out * @param {Ext.Container} container The container * @param {Ext.Element} target The target element */ handleTargetOverflow: function(previousTargetSize, container, target) { var overflow = target.getStyle('overflow'); if (overflow && overflow != 'hidden' &&!this.adjustmentPass) { var newTargetSize = this.getLayoutTargetSize(); if (newTargetSize.width != previousTargetSize.width || newTargetSize.height != previousTargetSize.height){ this.adjustmentPass = true; this.onLayout(container, target); } } delete this.adjustmentPass; }, // private isValidParent : function(c, target) { return this.innerCt && c.getPositionEl().dom.parentNode == this.innerCt.dom; }, /** * @private * Returns all items that are both rendered and visible * @return {Array} All matching items */ getVisibleItems: function(ct) { var ct = ct || this.container, t = ct.getLayoutTarget(), cti = ct.items.items, len = cti.length, i, c, items = []; for (i = 0; i < len; i++) { if((c = cti[i]).rendered && this.isValidParent(c, t) && c.hidden !== true && c.collapsed !== true && c.shouldLayout !== false){ items.push(c); } } return items; }, // private renderAll : function(ct, target) { if (!this.innerCt) { // the innerCt prevents wrapping and shuffling while the container is resizing this.innerCt = target.createChild({cls:this.innerCls}); this.padding = this.parseMargins(this.padding); } Ext.layout.BoxLayout.superclass.renderAll.call(this, ct, this.innerCt); }, getLayoutTargetSize : function() { var target = this.container.getLayoutTarget(), ret; if (target) { ret = target.getViewSize(); // IE in strict mode will return a width of 0 on the 1st pass of getViewSize. // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly // with getViewSize if (Ext.isIE && Ext.isStrict && ret.width == 0){ ret = target.getStyleSize(); } ret.width -= target.getPadding('lr'); ret.height -= target.getPadding('tb'); } return ret; }, // private renderItem : function(c) { if(Ext.isString(c.margins)){ c.margins = this.parseMargins(c.margins); }else if(!c.margins){ c.margins = this.defaultMargins; } Ext.layout.BoxLayout.superclass.renderItem.apply(this, arguments); }, /** * @private */ destroy: function() { Ext.destroy(this.overflowHandler); Ext.layout.BoxLayout.superclass.destroy.apply(this, arguments); } }); /** * @class Ext.layout.boxOverflow.None * @extends Object * Base class for Box Layout overflow handlers. These specialized classes are invoked when a Box Layout * (either an HBox or a VBox) has child items that are either too wide (for HBox) or too tall (for VBox) * for its container. */ Ext.layout.boxOverflow.None = Ext.extend(Object, { constructor: function(layout, config) { this.layout = layout; Ext.apply(this, config || {}); }, handleOverflow: Ext.emptyFn, clearOverflow: Ext.emptyFn }); Ext.layout.boxOverflow.none = Ext.layout.boxOverflow.None; /** * @class Ext.layout.boxOverflow.Menu * @extends Ext.layout.boxOverflow.None * Description */ Ext.layout.boxOverflow.Menu = Ext.extend(Ext.layout.boxOverflow.None, { /** * @cfg afterCls * @type String * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers, * which must always be present at the rightmost edge of the Container */ afterCls: 'x-strip-right', /** * @property noItemsMenuText * @type String * HTML fragment to render into the toolbar overflow menu if there are no items to display */ noItemsMenuText : '
(None)
', constructor: function(layout) { Ext.layout.boxOverflow.Menu.superclass.constructor.apply(this, arguments); /** * @property menuItems * @type Array * Array of all items that are currently hidden and should go into the dropdown menu */ this.menuItems = []; }, /** * @private * Creates the beforeCt, innerCt and afterCt elements if they have not already been created * @param {Ext.Container} container The Container attached to this Layout instance * @param {Ext.Element} target The target Element */ createInnerElements: function() { if (!this.afterCt) { this.afterCt = this.layout.innerCt.insertSibling({cls: this.afterCls}, 'before'); } }, /** * @private */ clearOverflow: function(calculations, targetSize) { var newWidth = targetSize.width + (this.afterCt ? this.afterCt.getWidth() : 0), items = this.menuItems; this.hideTrigger(); for (var index = 0, length = items.length; index < length; index++) { items.pop().component.show(); } return { targetSize: { height: targetSize.height, width : newWidth } }; }, /** * @private */ showTrigger: function() { this.createMenu(); this.menuTrigger.show(); }, /** * @private */ hideTrigger: function() { if (this.menuTrigger != undefined) { this.menuTrigger.hide(); } }, /** * @private * Called before the overflow menu is shown. This constructs the menu's items, caching them for as long as it can. */ beforeMenuShow: function(menu) { var items = this.menuItems, len = items.length, item, prev; var needsSep = function(group, item){ return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator); }; this.clearMenu(); menu.removeAll(); for (var i = 0; i < len; i++) { item = items[i].component; if (prev && (needsSep(item, prev) || needsSep(prev, item))) { menu.add('-'); } this.addComponentToMenu(menu, item); prev = item; } // put something so the menu isn't empty if no compatible items found if (menu.items.length < 1) { menu.add(this.noItemsMenuText); } }, /** * @private * Returns a menu config for a given component. This config is used to create a menu item * to be added to the expander menu * @param {Ext.Component} component The component to create the config for * @param {Boolean} hideOnClick Passed through to the menu item */ createMenuConfig : function(component, hideOnClick){ var config = Ext.apply({}, component.initialConfig), group = component.toggleGroup; Ext.copyTo(config, component, [ 'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu' ]); Ext.apply(config, { text : component.overflowText || component.text, hideOnClick: hideOnClick }); if (group || component.enableToggle) { Ext.apply(config, { group : group, checked: component.pressed, listeners: { checkchange: function(item, checked){ component.toggle(checked); } } }); } delete config.ownerCt; delete config.xtype; delete config.id; return config; }, /** * @private * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually. * @param {Ext.menu.Menu} menu The menu to add to * @param {Ext.Component} component The component to add */ addComponentToMenu : function(menu, component) { if (component instanceof Ext.Toolbar.Separator) { menu.add('-'); } else if (Ext.isFunction(component.isXType)) { if (component.isXType('splitbutton')) { menu.add(this.createMenuConfig(component, true)); } else if (component.isXType('button')) { menu.add(this.createMenuConfig(component, !component.menu)); } else if (component.isXType('buttongroup')) { component.items.each(function(item){ this.addComponentToMenu(menu, item); }, this); } } }, /** * @private * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item */ clearMenu : function(){ var menu = this.moreMenu; if (menu && menu.items) { menu.items.each(function(item){ delete item.menu; }); } }, /** * @private * Creates the overflow trigger and menu used when enableOverflow is set to true and the items * in the layout are too wide to fit in the space available */ createMenu: function() { if (!this.menuTrigger) { this.createInnerElements(); /** * @private * @property menu * @type Ext.menu.Menu * The expand menu - holds items for every item that cannot be shown * because the container is currently not large enough. */ this.menu = new Ext.menu.Menu({ ownerCt : this.layout.container, listeners: { scope: this, beforeshow: this.beforeMenuShow } }); /** * @private * @property menuTrigger * @type Ext.Button * The expand button which triggers the overflow menu to be shown */ this.menuTrigger = new Ext.Button({ iconCls : 'x-toolbar-more-icon', cls : 'x-toolbar-more', menu : this.menu, renderTo: this.afterCt }); } }, /** * @private */ destroy: function() { Ext.destroy(this.menu, this.menuTrigger); } }); Ext.layout.boxOverflow.menu = Ext.layout.boxOverflow.Menu; /** * @class Ext.layout.boxOverflow.HorizontalMenu * @extends Ext.layout.boxOverflow.Menu * Description */ Ext.layout.boxOverflow.HorizontalMenu = Ext.extend(Ext.layout.boxOverflow.Menu, { constructor: function() { Ext.layout.boxOverflow.HorizontalMenu.superclass.constructor.apply(this, arguments); var me = this, layout = me.layout, origFunction = layout.calculateChildBoxes; layout.calculateChildBoxes = function(visibleItems, targetSize) { var calcs = origFunction.apply(layout, arguments), meta = calcs.meta, items = me.menuItems; //calculate the width of the items currently hidden solely because there is not enough space //to display them var hiddenWidth = 0; for (var index = 0, length = items.length; index < length; index++) { hiddenWidth += items[index].width; } meta.minimumWidth += hiddenWidth; meta.tooNarrow = meta.minimumWidth > targetSize.width; return calcs; }; }, handleOverflow: function(calculations, targetSize) { this.showTrigger(); var newWidth = targetSize.width - this.afterCt.getWidth(), boxes = calculations.boxes, usedWidth = 0, recalculate = false; //calculate the width of all visible items and any spare width for (var index = 0, length = boxes.length; index < length; index++) { usedWidth += boxes[index].width; } var spareWidth = newWidth - usedWidth, showCount = 0; //see if we can re-show any of the hidden components for (var index = 0, length = this.menuItems.length; index < length; index++) { var hidden = this.menuItems[index], comp = hidden.component, width = hidden.width; if (width < spareWidth) { comp.show(); spareWidth -= width; showCount ++; recalculate = true; } else { break; } } if (recalculate) { this.menuItems = this.menuItems.slice(showCount); } else { for (var i = boxes.length - 1; i >= 0; i--) { var item = boxes[i].component, right = boxes[i].left + boxes[i].width; if (right >= newWidth) { this.menuItems.unshift({ component: item, width : boxes[i].width }); item.hide(); } else { break; } } } if (this.menuItems.length == 0) { this.hideTrigger(); } return { targetSize: { height: targetSize.height, width : newWidth }, recalculate: recalculate }; } }); Ext.layout.boxOverflow.menu.hbox = Ext.layout.boxOverflow.HorizontalMenu;/** * @class Ext.layout.boxOverflow.Scroller * @extends Ext.layout.boxOverflow.None * Description */ Ext.layout.boxOverflow.Scroller = Ext.extend(Ext.layout.boxOverflow.None, { /** * @cfg animateScroll * @type Boolean * True to animate the scrolling of items within the layout (defaults to true, ignored if enableScroll is false) */ animateScroll: true, /** * @cfg scrollIncrement * @type Number * The number of pixels to scroll by on scroller click (defaults to 100) */ scrollIncrement: 100, /** * @cfg wheelIncrement * @type Number * The number of pixels to increment on mouse wheel scrolling (defaults to 3). */ wheelIncrement: 3, /** * @cfg scrollRepeatInterval * @type Number * Number of milliseconds between each scroll while a scroller button is held down (defaults to 400) */ scrollRepeatInterval: 400, /** * @cfg scrollDuration * @type Number * Number of seconds that each scroll animation lasts (defaults to 0.4) */ scrollDuration: 0.4, /** * @cfg beforeCls * @type String * CSS class added to the beforeCt element. This is the element that holds any special items such as scrollers, * which must always be present at the leftmost edge of the Container */ beforeCls: 'x-strip-left', /** * @cfg afterCls * @type String * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers, * which must always be present at the rightmost edge of the Container */ afterCls: 'x-strip-right', /** * @cfg scrollerCls * @type String * CSS class added to both scroller elements if enableScroll is used */ scrollerCls: 'x-strip-scroller', /** * @cfg beforeScrollerCls * @type String * CSS class added to the left scroller element if enableScroll is used */ beforeScrollerCls: 'x-strip-scroller-left', /** * @cfg afterScrollerCls * @type String * CSS class added to the right scroller element if enableScroll is used */ afterScrollerCls: 'x-strip-scroller-right', /** * @private * Sets up an listener to scroll on the layout's innerCt mousewheel event */ createWheelListener: function() { this.layout.innerCt.on({ scope : this, mousewheel: function(e) { e.stopEvent(); this.scrollBy(e.getWheelDelta() * this.wheelIncrement * -1, false); } }); }, /** * @private * Most of the heavy lifting is done in the subclasses */ handleOverflow: function(calculations, targetSize) { this.createInnerElements(); this.showScrollers(); }, /** * @private */ clearOverflow: function() { this.hideScrollers(); }, /** * @private * Shows the scroller elements in the beforeCt and afterCt. Creates the scrollers first if they are not already * present. */ showScrollers: function() { this.createScrollers(); this.beforeScroller.show(); this.afterScroller.show(); this.updateScrollButtons(); }, /** * @private * Hides the scroller elements in the beforeCt and afterCt */ hideScrollers: function() { if (this.beforeScroller != undefined) { this.beforeScroller.hide(); this.afterScroller.hide(); } }, /** * @private * Creates the clickable scroller elements and places them into the beforeCt and afterCt */ createScrollers: function() { if (!this.beforeScroller && !this.afterScroller) { var before = this.beforeCt.createChild({ cls: String.format("{0} {1} ", this.scrollerCls, this.beforeScrollerCls) }); var after = this.afterCt.createChild({ cls: String.format("{0} {1}", this.scrollerCls, this.afterScrollerCls) }); before.addClassOnOver(this.beforeScrollerCls + '-hover'); after.addClassOnOver(this.afterScrollerCls + '-hover'); before.setVisibilityMode(Ext.Element.DISPLAY); after.setVisibilityMode(Ext.Element.DISPLAY); this.beforeRepeater = new Ext.util.ClickRepeater(before, { interval: this.scrollRepeatInterval, handler : this.scrollLeft, scope : this }); this.afterRepeater = new Ext.util.ClickRepeater(after, { interval: this.scrollRepeatInterval, handler : this.scrollRight, scope : this }); /** * @property beforeScroller * @type Ext.Element * The left scroller element. Only created when needed. */ this.beforeScroller = before; /** * @property afterScroller * @type Ext.Element * The left scroller element. Only created when needed. */ this.afterScroller = after; } }, /** * @private */ destroy: function() { Ext.destroy(this.beforeScroller, this.afterScroller, this.beforeRepeater, this.afterRepeater, this.beforeCt, this.afterCt); }, /** * @private * Scrolls left or right by the number of pixels specified * @param {Number} delta Number of pixels to scroll to the right by. Use a negative number to scroll left */ scrollBy: function(delta, animate) { this.scrollTo(this.getScrollPosition() + delta, animate); }, /** * @private * Normalizes an item reference, string id or numerical index into a reference to the item * @param {Ext.Component|String|Number} item The item reference, id or index * @return {Ext.Component} The item */ getItem: function(item) { if (Ext.isString(item)) { item = Ext.getCmp(item); } else if (Ext.isNumber(item)) { item = this.items[item]; } return item; }, /** * @private * @return {Object} Object passed to scrollTo when scrolling */ getScrollAnim: function() { return { duration: this.scrollDuration, callback: this.updateScrollButtons, scope : this }; }, /** * @private * Enables or disables each scroller button based on the current scroll position */ updateScrollButtons: function() { if (this.beforeScroller == undefined || this.afterScroller == undefined) { return; } var beforeMeth = this.atExtremeBefore() ? 'addClass' : 'removeClass', afterMeth = this.atExtremeAfter() ? 'addClass' : 'removeClass', beforeCls = this.beforeScrollerCls + '-disabled', afterCls = this.afterScrollerCls + '-disabled'; this.beforeScroller[beforeMeth](beforeCls); this.afterScroller[afterMeth](afterCls); this.scrolling = false; }, /** * @private * Returns true if the innerCt scroll is already at its left-most point * @return {Boolean} True if already at furthest left point */ atExtremeBefore: function() { return this.getScrollPosition() === 0; }, /** * @private * Scrolls to the left by the configured amount */ scrollLeft: function(animate) { this.scrollBy(-this.scrollIncrement, animate); }, /** * @private * Scrolls to the right by the configured amount */ scrollRight: function(animate) { this.scrollBy(this.scrollIncrement, animate); }, /** * Scrolls to the given component. * @param {String|Number|Ext.Component} item The item to scroll to. Can be a numerical index, component id * or a reference to the component itself. * @param {Boolean} animate True to animate the scrolling */ scrollToItem: function(item, animate) { item = this.getItem(item); if (item != undefined) { var visibility = this.getItemVisibility(item); if (!visibility.fullyVisible) { var box = item.getBox(true, true), newX = box.x; if (visibility.hiddenRight) { newX -= (this.layout.innerCt.getWidth() - box.width); } this.scrollTo(newX, animate); } } }, /** * @private * For a given item in the container, return an object with information on whether the item is visible * with the current innerCt scroll value. * @param {Ext.Component} item The item * @return {Object} Values for fullyVisible, hiddenLeft and hiddenRight */ getItemVisibility: function(item) { var box = this.getItem(item).getBox(true, true), itemLeft = box.x, itemRight = box.x + box.width, scrollLeft = this.getScrollPosition(), scrollRight = this.layout.innerCt.getWidth() + scrollLeft; return { hiddenLeft : itemLeft < scrollLeft, hiddenRight : itemRight > scrollRight, fullyVisible: itemLeft > scrollLeft && itemRight < scrollRight }; } }); Ext.layout.boxOverflow.scroller = Ext.layout.boxOverflow.Scroller; /** * @class Ext.layout.boxOverflow.VerticalScroller * @extends Ext.layout.boxOverflow.Scroller * Description */ Ext.layout.boxOverflow.VerticalScroller = Ext.extend(Ext.layout.boxOverflow.Scroller, { scrollIncrement: 75, wheelIncrement : 2, handleOverflow: function(calculations, targetSize) { Ext.layout.boxOverflow.VerticalScroller.superclass.handleOverflow.apply(this, arguments); return { targetSize: { height: targetSize.height - (this.beforeCt.getHeight() + this.afterCt.getHeight()), width : targetSize.width } }; }, /** * @private * Creates the beforeCt and afterCt elements if they have not already been created */ createInnerElements: function() { var target = this.layout.innerCt; //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of //special items such as scrollers or dropdown menu triggers if (!this.beforeCt) { this.beforeCt = target.insertSibling({cls: this.beforeCls}, 'before'); this.afterCt = target.insertSibling({cls: this.afterCls}, 'after'); this.createWheelListener(); } }, /** * @private * Scrolls to the given position. Performs bounds checking. * @param {Number} position The position to scroll to. This is constrained. * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll */ scrollTo: function(position, animate) { var oldPosition = this.getScrollPosition(), newPosition = position.constrain(0, this.getMaxScrollBottom()); if (newPosition != oldPosition && !this.scrolling) { if (animate == undefined) { animate = this.animateScroll; } this.layout.innerCt.scrollTo('top', newPosition, animate ? this.getScrollAnim() : false); if (animate) { this.scrolling = true; } else { this.scrolling = false; this.updateScrollButtons(); } } }, /** * Returns the current scroll position of the innerCt element * @return {Number} The current scroll position */ getScrollPosition: function(){ return parseInt(this.layout.innerCt.dom.scrollTop, 10) || 0; }, /** * @private * Returns the maximum value we can scrollTo * @return {Number} The max scroll value */ getMaxScrollBottom: function() { return this.layout.innerCt.dom.scrollHeight - this.layout.innerCt.getHeight(); }, /** * @private * Returns true if the innerCt scroll is already at its right-most point * @return {Boolean} True if already at furthest right point */ atExtremeAfter: function() { return this.getScrollPosition() >= this.getMaxScrollBottom(); } }); Ext.layout.boxOverflow.scroller.vbox = Ext.layout.boxOverflow.VerticalScroller; /** * @class Ext.layout.boxOverflow.HorizontalScroller * @extends Ext.layout.boxOverflow.Scroller * Description */ Ext.layout.boxOverflow.HorizontalScroller = Ext.extend(Ext.layout.boxOverflow.Scroller, { handleOverflow: function(calculations, targetSize) { Ext.layout.boxOverflow.HorizontalScroller.superclass.handleOverflow.apply(this, arguments); return { targetSize: { height: targetSize.height, width : targetSize.width - (this.beforeCt.getWidth() + this.afterCt.getWidth()) } }; }, /** * @private * Creates the beforeCt and afterCt elements if they have not already been created */ createInnerElements: function() { var target = this.layout.innerCt; //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of //special items such as scrollers or dropdown menu triggers if (!this.beforeCt) { this.afterCt = target.insertSibling({cls: this.afterCls}, 'before'); this.beforeCt = target.insertSibling({cls: this.beforeCls}, 'before'); this.createWheelListener(); } }, /** * @private * Scrolls to the given position. Performs bounds checking. * @param {Number} position The position to scroll to. This is constrained. * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll */ scrollTo: function(position, animate) { var oldPosition = this.getScrollPosition(), newPosition = position.constrain(0, this.getMaxScrollRight()); if (newPosition != oldPosition && !this.scrolling) { if (animate == undefined) { animate = this.animateScroll; } this.layout.innerCt.scrollTo('left', newPosition, animate ? this.getScrollAnim() : false); if (animate) { this.scrolling = true; } else { this.scrolling = false; this.updateScrollButtons(); } } }, /** * Returns the current scroll position of the innerCt element * @return {Number} The current scroll position */ getScrollPosition: function(){ return parseInt(this.layout.innerCt.dom.scrollLeft, 10) || 0; }, /** * @private * Returns the maximum value we can scrollTo * @return {Number} The max scroll value */ getMaxScrollRight: function() { return this.layout.innerCt.dom.scrollWidth - this.layout.innerCt.getWidth(); }, /** * @private * Returns true if the innerCt scroll is already at its right-most point * @return {Boolean} True if already at furthest right point */ atExtremeAfter: function() { return this.getScrollPosition() >= this.getMaxScrollRight(); } }); Ext.layout.boxOverflow.scroller.hbox = Ext.layout.boxOverflow.HorizontalScroller;/** * @class Ext.layout.HBoxLayout * @extends Ext.layout.BoxLayout *

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

* This layout may also be used to set the heights of child items by configuring it with the {@link #align} option. */ Ext.layout.HBoxLayout = Ext.extend(Ext.layout.BoxLayout, { /** * @cfg {String} align * Controls how the child items of the container are aligned. Acceptable configuration values for this * property are: *