3 * Copyright(c) 2006-2010 Ext JS, Inc.
5 * http://www.extjs.com/license
8 * @class Ext.ComponentMgr
9 * <p>Provides a registry of all Components (instances of {@link Ext.Component} or any subclass
10 * thereof) on a page so that they can be easily accessed by {@link Ext.Component component}
11 * {@link Ext.Component#id id} (see {@link #get}, or the convenience method {@link Ext#getCmp Ext.getCmp}).</p>
12 * <p>This object also provides a registry of available Component <i>classes</i>
13 * indexed by a mnemonic code known as the Component's {@link Ext.Component#xtype xtype}.
14 * The <code>{@link Ext.Component#xtype xtype}</code> provides a way to avoid instantiating child Components
15 * when creating a full, nested config object for a complete Ext page.</p>
16 * <p>A child Component may be specified simply as a <i>config object</i>
17 * as long as the correct <code>{@link Ext.Component#xtype xtype}</code> is specified so that if and when the Component
18 * needs rendering, the correct type can be looked up for lazy instantiation.</p>
19 * <p>For a list of all available <code>{@link Ext.Component#xtype xtypes}</code>, see {@link Ext.Component}.</p>
22 Ext.ComponentMgr = function(){
23 var all = new Ext.util.MixedCollection();
29 * Registers a component.
30 * @param {Ext.Component} c The component
32 register : function(c){
37 * Unregisters a component.
38 * @param {Ext.Component} c The component
40 unregister : function(c){
45 * Returns a component by {@link Ext.Component#id id}.
46 * For additional details see {@link Ext.util.MixedCollection#get}.
47 * @param {String} id The component {@link Ext.Component#id id}
48 * @return Ext.Component The Component, <code>undefined</code> if not found, or <code>null</code> if a
56 * Registers a function that will be called when a Component with the specified id is added to ComponentMgr. This will happen on instantiation.
57 * @param {String} id The component {@link Ext.Component#id id}
58 * @param {Function} fn The callback function
59 * @param {Object} scope The scope (<code>this</code> reference) in which the callback is executed. Defaults to the Component.
61 onAvailable : function(id, fn, scope){
62 all.on("add", function(index, o){
64 fn.call(scope || o, o);
65 all.un("add", fn, scope);
71 * The MixedCollection used internally for the component cache. An example usage may be subscribing to
72 * events on the MixedCollection to monitor addition or removal. Read-only.
73 * @type {MixedCollection}
78 * The xtypes that have been registered with the component manager.
84 * The ptypes that have been registered with the component manager.
90 * Checks if a Component type is registered.
91 * @param {Ext.Component} xtype The mnemonic string by which the Component class may be looked up
92 * @return {Boolean} Whether the type is registered.
94 isRegistered : function(xtype){
95 return types[xtype] !== undefined;
99 * Checks if a Plugin type is registered.
100 * @param {Ext.Component} ptype The mnemonic string by which the Plugin class may be looked up
101 * @return {Boolean} Whether the type is registered.
103 isPluginRegistered : function(ptype){
104 return ptypes[ptype] !== undefined;
108 * <p>Registers a new Component constructor, keyed by a new
109 * {@link Ext.Component#xtype}.</p>
110 * <p>Use this method (or its alias {@link Ext#reg Ext.reg}) to register new
111 * subclasses of {@link Ext.Component} so that lazy instantiation may be used when specifying
113 * see {@link Ext.Container#items}</p>
114 * @param {String} xtype The mnemonic string by which the Component class may be looked up.
115 * @param {Constructor} cls The new Component class.
117 registerType : function(xtype, cls){
123 * Creates a new Component from the specified config object using the
124 * config object's {@link Ext.component#xtype xtype} to determine the class to instantiate.
125 * @param {Object} config A configuration object for the Component you wish to create.
126 * @param {Constructor} defaultType The constructor to provide the default Component type if
127 * the config object does not contain a <code>xtype</code>. (Optional if the config contains a <code>xtype</code>).
128 * @return {Ext.Component} The newly instantiated Component.
130 create : function(config, defaultType){
131 return config.render ? config : new types[config.xtype || defaultType](config);
135 * <p>Registers a new Plugin constructor, keyed by a new
136 * {@link Ext.Component#ptype}.</p>
137 * <p>Use this method (or its alias {@link Ext#preg Ext.preg}) to register new
138 * plugins for {@link Ext.Component}s so that lazy instantiation may be used when specifying
140 * @param {String} ptype The mnemonic string by which the Plugin class may be looked up.
141 * @param {Constructor} cls The new Plugin class.
143 registerPlugin : function(ptype, cls){
149 * Creates a new Plugin from the specified config object using the
150 * config object's {@link Ext.component#ptype ptype} to determine the class to instantiate.
151 * @param {Object} config A configuration object for the Plugin you wish to create.
152 * @param {Constructor} defaultType The constructor to provide the default Plugin type if
153 * the config object does not contain a <code>ptype</code>. (Optional if the config contains a <code>ptype</code>).
154 * @return {Ext.Component} The newly instantiated Plugin.
156 createPlugin : function(config, defaultType){
157 var PluginCls = ptypes[config.ptype || defaultType];
158 if (PluginCls.init) {
161 return new PluginCls(config);
168 * Shorthand for {@link Ext.ComponentMgr#registerType}
169 * @param {String} xtype The {@link Ext.component#xtype mnemonic string} by which the Component class
171 * @param {Constructor} cls The new Component class.
175 Ext.reg = Ext.ComponentMgr.registerType; // this will be called a lot internally, shorthand to keep the bytes down
177 * Shorthand for {@link Ext.ComponentMgr#registerPlugin}
178 * @param {String} ptype The {@link Ext.component#ptype mnemonic string} by which the Plugin class
180 * @param {Constructor} cls The new Plugin class.
184 Ext.preg = Ext.ComponentMgr.registerPlugin;
186 * Shorthand for {@link Ext.ComponentMgr#create}
187 * Creates a new Component from the specified config object using the
188 * config object's {@link Ext.component#xtype xtype} to determine the class to instantiate.
189 * @param {Object} config A configuration object for the Component you wish to create.
190 * @param {Constructor} defaultType The constructor to provide the default Component type if
191 * the config object does not contain a <code>xtype</code>. (Optional if the config contains a <code>xtype</code>).
192 * @return {Ext.Component} The newly instantiated Component.
196 Ext.create = Ext.ComponentMgr.create;/**
197 * @class Ext.Component
198 * @extends Ext.util.Observable
199 * <p>Base class for all Ext components. All subclasses of Component may participate in the automated
200 * Ext component lifecycle of creation, rendering and destruction which is provided by the {@link Ext.Container Container} class.
201 * Components may be added to a Container through the {@link Ext.Container#items items} config option at the time the Container is created,
202 * or they may be added dynamically via the {@link Ext.Container#add add} method.</p>
203 * <p>The Component base class has built-in support for basic hide/show and enable/disable behavior.</p>
204 * <p>All Components are registered with the {@link Ext.ComponentMgr} on construction so that they can be referenced at any time via
205 * {@link Ext#getCmp}, passing the {@link #id}.</p>
206 * <p>All user-developed visual widgets that are required to participate in automated lifecycle and size management should subclass Component (or
207 * {@link Ext.BoxComponent} if managed box model handling is required, ie height and width management).</p>
208 * <p>See the <a href="http://extjs.com/learn/Tutorial:Creating_new_UI_controls">Creating new UI controls</a> tutorial for details on how
209 * and to either extend or augment ExtJs base classes to create custom Components.</p>
210 * <p>Every component has a specific xtype, which is its Ext-specific type name, along with methods for checking the
211 * xtype like {@link #getXType} and {@link #isXType}. This is the list of all valid xtypes:</p>
214 ------------- ------------------
215 box {@link Ext.BoxComponent}
216 button {@link Ext.Button}
217 buttongroup {@link Ext.ButtonGroup}
218 colorpalette {@link Ext.ColorPalette}
219 component {@link Ext.Component}
220 container {@link Ext.Container}
221 cycle {@link Ext.CycleButton}
222 dataview {@link Ext.DataView}
223 datepicker {@link Ext.DatePicker}
224 editor {@link Ext.Editor}
225 editorgrid {@link Ext.grid.EditorGridPanel}
226 flash {@link Ext.FlashComponent}
227 grid {@link Ext.grid.GridPanel}
228 listview {@link Ext.ListView}
229 multislider {@link Ext.slider.MultiSlider}
230 panel {@link Ext.Panel}
231 progress {@link Ext.ProgressBar}
232 propertygrid {@link Ext.grid.PropertyGrid}
233 slider {@link Ext.slider.SingleSlider}
234 spacer {@link Ext.Spacer}
235 splitbutton {@link Ext.SplitButton}
236 tabpanel {@link Ext.TabPanel}
237 treepanel {@link Ext.tree.TreePanel}
238 viewport {@link Ext.ViewPort}
239 window {@link Ext.Window}
242 ---------------------------------------
243 paging {@link Ext.PagingToolbar}
244 toolbar {@link Ext.Toolbar}
245 tbbutton {@link Ext.Toolbar.Button} (deprecated; use button)
246 tbfill {@link Ext.Toolbar.Fill}
247 tbitem {@link Ext.Toolbar.Item}
248 tbseparator {@link Ext.Toolbar.Separator}
249 tbspacer {@link Ext.Toolbar.Spacer}
250 tbsplit {@link Ext.Toolbar.SplitButton} (deprecated; use splitbutton)
251 tbtext {@link Ext.Toolbar.TextItem}
254 ---------------------------------------
255 menu {@link Ext.menu.Menu}
256 colormenu {@link Ext.menu.ColorMenu}
257 datemenu {@link Ext.menu.DateMenu}
258 menubaseitem {@link Ext.menu.BaseItem}
259 menucheckitem {@link Ext.menu.CheckItem}
260 menuitem {@link Ext.menu.Item}
261 menuseparator {@link Ext.menu.Separator}
262 menutextitem {@link Ext.menu.TextItem}
265 ---------------------------------------
266 form {@link Ext.form.FormPanel}
267 checkbox {@link Ext.form.Checkbox}
268 checkboxgroup {@link Ext.form.CheckboxGroup}
269 combo {@link Ext.form.ComboBox}
270 compositefield {@link Ext.form.CompositeField}
271 datefield {@link Ext.form.DateField}
272 displayfield {@link Ext.form.DisplayField}
273 field {@link Ext.form.Field}
274 fieldset {@link Ext.form.FieldSet}
275 hidden {@link Ext.form.Hidden}
276 htmleditor {@link Ext.form.HtmlEditor}
277 label {@link Ext.form.Label}
278 numberfield {@link Ext.form.NumberField}
279 radio {@link Ext.form.Radio}
280 radiogroup {@link Ext.form.RadioGroup}
281 textarea {@link Ext.form.TextArea}
282 textfield {@link Ext.form.TextField}
283 timefield {@link Ext.form.TimeField}
284 trigger {@link Ext.form.TriggerField}
287 ---------------------------------------
288 chart {@link Ext.chart.Chart}
289 barchart {@link Ext.chart.BarChart}
290 cartesianchart {@link Ext.chart.CartesianChart}
291 columnchart {@link Ext.chart.ColumnChart}
292 linechart {@link Ext.chart.LineChart}
293 piechart {@link Ext.chart.PieChart}
296 ---------------------------------------
297 arraystore {@link Ext.data.ArrayStore}
298 directstore {@link Ext.data.DirectStore}
299 groupingstore {@link Ext.data.GroupingStore}
300 jsonstore {@link Ext.data.JsonStore}
301 simplestore {@link Ext.data.SimpleStore} (deprecated; use arraystore)
302 store {@link Ext.data.Store}
303 xmlstore {@link Ext.data.XmlStore}
306 * @param {Ext.Element/String/Object} config The configuration options may be specified as either:
307 * <div class="mdetail-params"><ul>
308 * <li><b>an element</b> :
309 * <p class="sub-desc">it is set as the internal element and its id used as the component id</p></li>
310 * <li><b>a string</b> :
311 * <p class="sub-desc">it is assumed to be the id of an existing element and is used as the component id</p></li>
312 * <li><b>anything else</b> :
313 * <p class="sub-desc">it is assumed to be a standard config object and is applied to the component</p></li>
316 Ext.Component = function(config){
317 config = config || {};
318 if(config.initialConfig){
319 if(config.isAction){ // actions
320 this.baseAction = config;
322 config = config.initialConfig; // component cloning / action set up
323 }else if(config.tagName || config.dom || Ext.isString(config)){ // element object
324 config = {applyTo: config, id: config.id || config};
328 * This Component's initial configuration specification. Read-only.
330 * @property initialConfig
332 this.initialConfig = config;
334 Ext.apply(this, config);
338 * Fires when a component is added to an Ext.Container
339 * @param {Ext.Component} this
340 * @param {Ext.Container} ownerCt Container which holds the component
341 * @param {number} index Position at which the component was added
346 * Fires after the component is disabled.
347 * @param {Ext.Component} this
352 * Fires after the component is enabled.
353 * @param {Ext.Component} this
358 * Fires before the component is shown by calling the {@link #show} method.
359 * Return false from an event handler to stop the show.
360 * @param {Ext.Component} this
365 * Fires after the component is shown when calling the {@link #show} method.
366 * @param {Ext.Component} this
371 * Fires before the component is hidden by calling the {@link #hide} method.
372 * Return false from an event handler to stop the hide.
373 * @param {Ext.Component} this
378 * Fires after the component is hidden.
379 * Fires after the component is hidden when calling the {@link #hide} method.
380 * @param {Ext.Component} this
385 * Fires when a component is removed from an Ext.Container
386 * @param {Ext.Component} this
387 * @param {Ext.Container} ownerCt Container which holds the component
391 * @event beforerender
392 * Fires before the component is {@link #rendered}. Return false from an
393 * event handler to stop the {@link #render}.
394 * @param {Ext.Component} this
399 * Fires after the component markup is {@link #rendered}.
400 * @param {Ext.Component} this
405 * <p>Fires after the component rendering is finished.</p>
406 * <p>The afterrender event is fired after this Component has been {@link #rendered}, been postprocesed
407 * by any afterRender method defined for the Component, and, if {@link #stateful}, after state
408 * has been restored.</p>
409 * @param {Ext.Component} this
413 * @event beforedestroy
414 * Fires before the component is {@link #destroy}ed. Return false from an event handler to stop the {@link #destroy}.
415 * @param {Ext.Component} this
420 * Fires after the component is {@link #destroy}ed.
421 * @param {Ext.Component} this
425 * @event beforestaterestore
426 * Fires before the state of the component is restored. Return false from an event handler to stop the restore.
427 * @param {Ext.Component} this
428 * @param {Object} state The hash of state values returned from the StateProvider. If this
429 * event is not vetoed, then the state object is passed to <b><tt>applyState</tt></b>. By default,
430 * that simply copies property values into this Component. The method maybe overriden to
431 * provide custom state restoration.
433 'beforestaterestore',
435 * @event staterestore
436 * Fires after the state of the component is restored.
437 * @param {Ext.Component} this
438 * @param {Object} state The hash of state values returned from the StateProvider. This is passed
439 * to <b><tt>applyState</tt></b>. By default, that simply copies property values into this
440 * Component. The method maybe overriden to provide custom state restoration.
444 * @event beforestatesave
445 * Fires before the state of the component is saved to the configured state provider. Return false to stop the save.
446 * @param {Ext.Component} this
447 * @param {Object} state The hash of state values. This is determined by calling
448 * <b><tt>getState()</tt></b> on the Component. This method must be provided by the
449 * developer to return whetever representation of state is required, by default, Ext.Component
450 * has a null implementation.
455 * Fires after the state of the component is saved to the configured state provider.
456 * @param {Ext.Component} this
457 * @param {Object} state The hash of state values. This is determined by calling
458 * <b><tt>getState()</tt></b> on the Component. This method must be provided by the
459 * developer to return whetever representation of state is required, by default, Ext.Component
460 * has a null implementation.
465 Ext.ComponentMgr.register(this);
466 Ext.Component.superclass.constructor.call(this);
469 this.baseAction.addComponent(this);
472 this.initComponent();
475 if(Ext.isArray(this.plugins)){
476 for(var i = 0, len = this.plugins.length; i < len; i++){
477 this.plugins[i] = this.initPlugin(this.plugins[i]);
480 this.plugins = this.initPlugin(this.plugins);
484 if(this.stateful !== false){
489 this.applyToMarkup(this.applyTo);
491 }else if(this.renderTo){
492 this.render(this.renderTo);
493 delete this.renderTo;
498 Ext.Component.AUTO_ID = 1000;
500 Ext.extend(Ext.Component, Ext.util.Observable, {
501 // Configs below are used for all Components when rendered by FormLayout.
503 * @cfg {String} fieldLabel <p>The label text to display next to this Component (defaults to '').</p>
504 * <br><p><b>Note</b>: this config is only used when this Component is rendered by a Container which
505 * has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout manager (e.g.
506 * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>).</p><br>
507 * <p>Also see <tt>{@link #hideLabel}</tt> and
508 * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</p>
509 * Example use:<pre><code>
512 renderTo: Ext.getBody(),
521 * @cfg {String} labelStyle <p>A CSS style specification string to apply directly to this field's
522 * label. Defaults to the container's labelStyle value if set (e.g.,
523 * <tt>{@link Ext.layout.FormLayout#labelStyle}</tt> , or '').</p>
524 * <br><p><b>Note</b>: see the note for <code>{@link #clearCls}</code>.</p><br>
525 * <p>Also see <code>{@link #hideLabel}</code> and
526 * <code>{@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</code></p>
527 * Example use:<pre><code>
530 renderTo: Ext.getBody(),
534 labelStyle: 'font-weight:bold;'
540 * @cfg {String} labelSeparator <p>The separator to display after the text of each
541 * <tt>{@link #fieldLabel}</tt>. This property may be configured at various levels.
542 * The order of precedence is:
543 * <div class="mdetail-params"><ul>
544 * <li>field / component level</li>
545 * <li>container level</li>
546 * <li>{@link Ext.layout.FormLayout#labelSeparator layout level} (defaults to colon <tt>':'</tt>)</li>
548 * To display no separator for this field's label specify empty string ''.</p>
549 * <br><p><b>Note</b>: see the note for <tt>{@link #clearCls}</tt>.</p><br>
550 * <p>Also see <tt>{@link #hideLabel}</tt> and
551 * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</p>
552 * Example use:<pre><code>
555 renderTo: Ext.getBody(),
557 labelSeparator: '~' // layout config has lowest priority (defaults to ':')
559 {@link Ext.layout.FormLayout#labelSeparator labelSeparator}: '>>', // config at container level
562 fieldLabel: 'Field 1',
563 labelSeparator: '...' // field/component level config supersedes others
566 fieldLabel: 'Field 2' // labelSeparator will be '='
572 * @cfg {Boolean} hideLabel <p><tt>true</tt> to completely hide the label element
573 * ({@link #fieldLabel label} and {@link #labelSeparator separator}). Defaults to <tt>false</tt>.
574 * By default, even if you do not specify a <tt>{@link #fieldLabel}</tt> the space will still be
575 * reserved so that the field will line up with other fields that do have labels.
576 * Setting this to <tt>true</tt> will cause the field to not reserve that space.</p>
577 * <br><p><b>Note</b>: see the note for <tt>{@link #clearCls}</tt>.</p><br>
578 * Example use:<pre><code>
581 renderTo: Ext.getBody(),
590 * @cfg {String} clearCls <p>The CSS class used to to apply to the special clearing div rendered
591 * directly after each form field wrapper to provide field clearing (defaults to
592 * <tt>'x-form-clear-left'</tt>).</p>
593 * <br><p><b>Note</b>: this config is only used when this Component is rendered by a Container
594 * which has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout
595 * manager (e.g. {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>) and either a
596 * <tt>{@link #fieldLabel}</tt> is specified or <tt>isFormField=true</tt> is specified.</p><br>
597 * <p>See {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl} also.</p>
600 * @cfg {String} itemCls
601 * <p><b>Note</b>: this config is only used when this Component is rendered by a Container which
602 * has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout manager (e.g.
603 * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>).</p><br>
604 * <p>An additional CSS class to apply to the div wrapping the form item
605 * element of this field. If supplied, <tt>itemCls</tt> at the <b>field</b> level will override
606 * the default <tt>itemCls</tt> supplied at the <b>container</b> level. The value specified for
607 * <tt>itemCls</tt> will be added to the default class (<tt>'x-form-item'</tt>).</p>
608 * <p>Since it is applied to the item wrapper (see
609 * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}), it allows
610 * you to write standard CSS rules that can apply to the field, the label (if specified), or
611 * any other element within the markup for the field.</p>
612 * <br><p><b>Note</b>: see the note for <tt>{@link #fieldLabel}</tt>.</p><br>
613 * Example use:<pre><code>
614 // Apply a style to the field's label:
616 .required .x-form-item-label {font-weight:bold;color:red;}
621 renderTo: Ext.getBody(),
625 itemCls: 'required' //this label will be styled
628 fieldLabel: 'Favorite Color'
636 * <p>The <b>unique</b> id of this component (defaults to an {@link #getId auto-assigned id}).
637 * You should assign an id if you need to be able to access the component later and you do
638 * not have an object reference available (e.g., using {@link Ext}.{@link Ext#getCmp getCmp}).</p>
639 * <p>Note that this id will also be used as the element id for the containing HTML element
640 * that is rendered to the page for this component. This allows you to write id-based CSS
641 * rules to style the specific instance of this component uniquely, and also to select
642 * sub-elements using this component's id as the parent.</p>
643 * <p><b>Note</b>: to avoid complications imposed by a unique <tt>id</tt> also see
644 * <code>{@link #itemId}</code> and <code>{@link #ref}</code>.</p>
645 * <p><b>Note</b>: to access the container of an item see <code>{@link #ownerCt}</code>.</p>
648 * @cfg {String} itemId
649 * <p>An <tt>itemId</tt> can be used as an alternative way to get a reference to a component
650 * when no object reference is available. Instead of using an <code>{@link #id}</code> with
651 * {@link Ext}.{@link Ext#getCmp getCmp}, use <code>itemId</code> with
652 * {@link Ext.Container}.{@link Ext.Container#getComponent getComponent} which will retrieve
653 * <code>itemId</code>'s or <tt>{@link #id}</tt>'s. Since <code>itemId</code>'s are an index to the
654 * container's internal MixedCollection, the <code>itemId</code> is scoped locally to the container --
655 * avoiding potential conflicts with {@link Ext.ComponentMgr} which requires a <b>unique</b>
656 * <code>{@link #id}</code>.</p>
658 var c = new Ext.Panel({ //
659 {@link Ext.BoxComponent#height height}: 300,
660 {@link #renderTo}: document.body,
661 {@link Ext.Container#layout layout}: 'auto',
662 {@link Ext.Container#items items}: [
665 {@link Ext.Panel#title title}: 'Panel 1',
666 {@link Ext.BoxComponent#height height}: 150
670 {@link Ext.Panel#title title}: 'Panel 2',
671 {@link Ext.BoxComponent#height height}: 150
675 p1 = c.{@link Ext.Container#getComponent getComponent}('p1'); // not the same as {@link Ext#getCmp Ext.getCmp()}
676 p2 = p1.{@link #ownerCt}.{@link Ext.Container#getComponent getComponent}('p2'); // reference via a sibling
678 * <p>Also see <tt>{@link #id}</tt> and <code>{@link #ref}</code>.</p>
679 * <p><b>Note</b>: to access the container of an item see <tt>{@link #ownerCt}</tt>.</p>
682 * @cfg {String} xtype
683 * The registered <tt>xtype</tt> to create. This config option is not used when passing
684 * a config object into a constructor. This config option is used only when
685 * lazy instantiation is being used, and a child item of a Container is being
686 * specified not as a fully instantiated Component, but as a <i>Component config
687 * object</i>. The <tt>xtype</tt> will be looked up at render time up to determine what
688 * type of child Component to create.<br><br>
689 * The predefined xtypes are listed {@link Ext.Component here}.
691 * If you subclass Components to create your own Components, you may register
692 * them using {@link Ext.ComponentMgr#registerType} in order to be able to
693 * take advantage of lazy instantiation and rendering.
696 * @cfg {String} ptype
697 * The registered <tt>ptype</tt> to create. This config option is not used when passing
698 * a config object into a constructor. This config option is used only when
699 * lazy instantiation is being used, and a Plugin is being
700 * specified not as a fully instantiated Component, but as a <i>Component config
701 * object</i>. The <tt>ptype</tt> will be looked up at render time up to determine what
702 * type of Plugin to create.<br><br>
703 * If you create your own Plugins, you may register them using
704 * {@link Ext.ComponentMgr#registerPlugin} in order to be able to
705 * take advantage of lazy instantiation and rendering.
709 * An optional extra CSS class that will be added to this component's Element (defaults to ''). This can be
710 * useful for adding customized styles to the component or any of its children using standard CSS rules.
713 * @cfg {String} overCls
714 * An optional extra CSS class that will be added to this component's Element when the mouse moves
715 * over the Element, and removed when the mouse moves out. (defaults to ''). This can be
716 * useful for adding customized 'active' or 'hover' styles to the component or any of its children using standard CSS rules.
719 * @cfg {String} style
720 * A custom style specification to be applied to this component's Element. Should be a valid argument to
721 * {@link Ext.Element#applyStyles}.
725 renderTo: Ext.getBody(),
726 width: 400, height: 300,
747 * @cfg {String} ctCls
748 * <p>An optional extra CSS class that will be added to this component's container. This can be useful for
749 * adding customized styles to the container or any of its children using standard CSS rules. See
750 * {@link Ext.layout.ContainerLayout}.{@link Ext.layout.ContainerLayout#extraCls extraCls} also.</p>
751 * <p><b>Note</b>: <tt>ctCls</tt> defaults to <tt>''</tt> except for the following class
752 * which assigns a value by default:
753 * <div class="mdetail-params"><ul>
754 * <li>{@link Ext.layout.Box Box Layout} : <tt>'x-box-layout-ct'</tt></li>
756 * To configure the above Class with an extra CSS class append to the default. For example,
757 * for BoxLayout (Hbox and Vbox):<pre><code>
758 * ctCls: 'x-box-layout-ct custom-class'
763 * @cfg {Boolean} disabled
764 * Render this component disabled (default is false).
768 * @cfg {Boolean} hidden
769 * Render this component hidden (default is false). If <tt>true</tt>, the
770 * {@link #hide} method will be called internally.
774 * @cfg {Object/Array} plugins
775 * An object or array of objects that will provide custom functionality for this component. The only
776 * requirement for a valid plugin is that it contain an init method that accepts a reference of type Ext.Component.
777 * When a component is created, if any plugins are available, the component will call the init method on each
778 * plugin, passing a reference to itself. Each plugin can then call methods or respond to events on the
779 * component as needed to provide its functionality.
782 * @cfg {Mixed} applyTo
783 * <p>Specify the id of the element, a DOM element or an existing Element corresponding to a DIV
784 * that is already present in the document that specifies some structural markup for this
785 * component.</p><div><ul>
786 * <li><b>Description</b> : <ul>
787 * <div class="sub-desc">When <tt>applyTo</tt> is used, constituent parts of the component can also be specified
788 * by id or CSS class name within the main element, and the component being created may attempt
789 * to create its subcomponents from that markup if applicable.</div>
791 * <li><b>Notes</b> : <ul>
792 * <div class="sub-desc">When using this config, a call to render() is not required.</div>
793 * <div class="sub-desc">If applyTo is specified, any value passed for {@link #renderTo} will be ignored and the target
794 * element's parent node will automatically be used as the component's container.</div>
799 * @cfg {Mixed} renderTo
800 * <p>Specify the id of the element, a DOM element or an existing Element that this component
801 * will be rendered into.</p><div><ul>
802 * <li><b>Notes</b> : <ul>
803 * <div class="sub-desc">Do <u>not</u> use this option if the Component is to be a child item of
804 * a {@link Ext.Container Container}. It is the responsibility of the
805 * {@link Ext.Container Container}'s {@link Ext.Container#layout layout manager}
806 * to render and manage its child items.</div>
807 * <div class="sub-desc">When using this config, a call to render() is not required.</div>
810 * <p>See <tt>{@link #render}</tt> also.</p>
813 * @cfg {Boolean} stateful
814 * <p>A flag which causes the Component to attempt to restore the state of
815 * internal properties from a saved state on startup. The component must have
816 * either a <code>{@link #stateId}</code> or <code>{@link #id}</code> assigned
817 * for state to be managed. Auto-generated ids are not guaranteed to be stable
818 * across page loads and cannot be relied upon to save and restore the same
819 * state for a component.<p>
820 * <p>For state saving to work, the state manager's provider must have been
821 * set to an implementation of {@link Ext.state.Provider} which overrides the
822 * {@link Ext.state.Provider#set set} and {@link Ext.state.Provider#get get}
823 * methods to save and recall name/value pairs. A built-in implementation,
824 * {@link Ext.state.CookieProvider} is available.</p>
825 * <p>To set the state provider for the current page:</p>
827 Ext.state.Manager.setProvider(new Ext.state.CookieProvider({
828 expires: new Date(new Date().getTime()+(1000*60*60*24*7)), //7 days from now
831 * <p>A stateful Component attempts to save state when one of the events
832 * listed in the <code>{@link #stateEvents}</code> configuration fires.</p>
833 * <p>To save state, a stateful Component first serializes its state by
834 * calling <b><code>getState</code></b>. By default, this function does
835 * nothing. The developer must provide an implementation which returns an
836 * object hash which represents the Component's restorable state.</p>
837 * <p>The value yielded by getState is passed to {@link Ext.state.Manager#set}
838 * which uses the configured {@link Ext.state.Provider} to save the object
839 * keyed by the Component's <code>{@link stateId}</code>, or, if that is not
840 * specified, its <code>{@link #id}</code>.</p>
841 * <p>During construction, a stateful Component attempts to <i>restore</i>
842 * its state by calling {@link Ext.state.Manager#get} passing the
843 * <code>{@link #stateId}</code>, or, if that is not specified, the
844 * <code>{@link #id}</code>.</p>
845 * <p>The resulting object is passed to <b><code>applyState</code></b>.
846 * The default implementation of <code>applyState</code> simply copies
847 * properties into the object, but a developer may override this to support
848 * more behaviour.</p>
849 * <p>You can perform extra processing on state save and restore by attaching
850 * handlers to the {@link #beforestaterestore}, {@link #staterestore},
851 * {@link #beforestatesave} and {@link #statesave} events.</p>
854 * @cfg {String} stateId
855 * The unique id for this component to use for state management purposes
856 * (defaults to the component id if one was set, otherwise null if the
857 * component is using a generated id).
858 * <p>See <code>{@link #stateful}</code> for an explanation of saving and
859 * restoring Component state.</p>
862 * @cfg {Array} stateEvents
863 * <p>An array of events that, when fired, should trigger this component to
864 * save its state (defaults to none). <code>stateEvents</code> may be any type
865 * of event supported by this component, including browser or custom events
866 * (e.g., <tt>['click', 'customerchange']</tt>).</p>
867 * <p>See <code>{@link #stateful}</code> for an explanation of saving and
868 * restoring Component state.</p>
871 * @cfg {Mixed} autoEl
872 * <p>A tag name or {@link Ext.DomHelper DomHelper} spec used to create the {@link #getEl Element} which will
873 * encapsulate this Component.</p>
874 * <p>You do not normally need to specify this. For the base classes {@link Ext.Component}, {@link Ext.BoxComponent},
875 * and {@link Ext.Container}, this defaults to <b><tt>'div'</tt></b>. The more complex Ext classes use a more complex
876 * DOM structure created by their own onRender methods.</p>
877 * <p>This is intended to allow the developer to create application-specific utility Components encapsulated by
878 * different DOM elements. Example usage:</p><pre><code>
883 src: 'http://www.example.com/example.jpg'
889 html: 'autoEl is cool!'
894 cls: 'ux-unordered-list',
898 html: 'First list item'
906 * @cfg {String} disabledClass
907 * CSS class added to the component when it is disabled (defaults to 'x-item-disabled').
909 disabledClass : 'x-item-disabled',
911 * @cfg {Boolean} allowDomMove
912 * Whether the component can move the Dom node when rendering (defaults to true).
916 * @cfg {Boolean} autoShow
917 * True if the component should check for hidden classes (e.g. 'x-hidden' or 'x-hide-display') and remove
918 * them on render (defaults to false).
922 * @cfg {String} hideMode
923 * <p>How this component should be hidden. Supported values are <tt>'visibility'</tt>
924 * (css visibility), <tt>'offsets'</tt> (negative offset position) and <tt>'display'</tt>
926 * <br><p><b>Note</b>: the default of <tt>'display'</tt> is generally preferred
927 * since items are automatically laid out when they are first shown (no sizing
928 * is done while hidden).</p>
930 hideMode : 'display',
932 * @cfg {Boolean} hideParent
933 * True to hide and show the component's container when hide/show is called on the component, false to hide
934 * and show the component itself (defaults to false). For example, this can be used as a shortcut for a hide
935 * button on a window by setting hide:true on the button when adding it to its parent container.
939 * <p>The {@link Ext.Element} which encapsulates this Component. Read-only.</p>
940 * <p>This will <i>usually</i> be a <DIV> element created by the class's onRender method, but
941 * that may be overridden using the <code>{@link #autoEl}</code> config.</p>
942 * <br><p><b>Note</b>: this element will not be available until this Component has been rendered.</p><br>
943 * <p>To add listeners for <b>DOM events</b> to this Component (as opposed to listeners
944 * for this Component's own Observable events), see the {@link Ext.util.Observable#listeners listeners}
945 * config for a suggestion, or use a render listener directly:</p><pre><code>
947 title: 'The Clickable Panel',
949 render: function(p) {
950 // Append the Panel to the click handler's argument list.
951 p.getEl().on('click', handlePanelClick.createDelegate(null, [p], true));
953 single: true // Remove the listener after first invocation
957 * <p>See also <tt>{@link #getEl getEl}</p>
962 * This Component's owner {@link Ext.Container Container} (defaults to undefined, and is set automatically when
963 * this Component is added to a Container). Read-only.
964 * <p><b>Note</b>: to access items within the Container see <tt>{@link #itemId}</tt>.</p>
965 * @type Ext.Container
969 * True if this component is hidden. Read-only.
974 * True if this component is disabled. Read-only.
979 * True if this component has been rendered. Read-only.
986 * @cfg {String} contentEl
987 * <p>Optional. Specify an existing HTML element, or the <code>id</code> of an existing HTML element to use as the content
988 * for this component.</p>
990 * <li><b>Description</b> :
991 * <div class="sub-desc">This config option is used to take an existing HTML element and place it in the layout element
992 * of a new component (it simply moves the specified DOM element <i>after the Component is rendered</i> to use as the content.</div></li>
994 * <div class="sub-desc">The specified HTML element is appended to the layout element of the component <i>after any configured
995 * {@link #html HTML} has been inserted</i>, and so the document will not contain this element at the time the {@link #render} event is fired.</div>
996 * <div class="sub-desc">The specified HTML element used will not participate in any <code><b>{@link Ext.Container#layout layout}</b></code>
997 * scheme that the Component may use. It is just HTML. Layouts operate on child <code><b>{@link Ext.Container#items items}</b></code>.</div>
998 * <div class="sub-desc">Add either the <code>x-hidden</code> or the <code>x-hide-display</code> CSS class to
999 * prevent a brief flicker of the content before it is rendered to the panel.</div></li>
1003 * @cfg {String/Object} html
1004 * An HTML fragment, or a {@link Ext.DomHelper DomHelper} specification to use as the layout element
1005 * content (defaults to ''). The HTML content is added after the component is rendered,
1006 * so the document will not contain this HTML at the time the {@link #render} event is fired.
1007 * This content is inserted into the body <i>before</i> any configured {@link #contentEl} is appended.
1012 * An <bold>{@link Ext.Template}</bold>, <bold>{@link Ext.XTemplate}</bold>
1013 * or an array of strings to form an Ext.XTemplate.
1014 * Used in conjunction with the <code>{@link #data}</code> and
1015 * <code>{@link #tplWriteMode}</code> configurations.
1019 * @cfg {String} tplWriteMode The Ext.(X)Template method to use when
1020 * updating the content area of the Component. Defaults to <tt>'overwrite'</tt>
1021 * (see <code>{@link Ext.XTemplate#overwrite}</code>).
1023 tplWriteMode : 'overwrite',
1027 * The initial set of data to apply to the <code>{@link #tpl}</code> to
1028 * update the content area of the Component.
1032 * @cfg {Array} bubbleEvents
1033 * <p>An array of events that, when fired, should be bubbled to any parent container.
1034 * See {@link Ext.util.Observable#enableBubble}.
1035 * Defaults to <tt>[]</tt>.
1041 ctype : 'Ext.Component',
1047 getActionEl : function(){
1048 return this[this.actionMode];
1051 initPlugin : function(p){
1052 if(p.ptype && !Ext.isFunction(p.init)){
1053 p = Ext.ComponentMgr.createPlugin(p);
1054 }else if(Ext.isString(p)){
1055 p = Ext.ComponentMgr.createPlugin({
1064 * Function to be implemented by Component subclasses to be part of standard component initialization flow (it is empty by default).
1066 // Traditional constructor:
1067 Ext.Foo = function(config){
1068 // call superclass constructor:
1069 Ext.Foo.superclass.constructor.call(this, config);
1075 Ext.extend(Ext.Foo, Ext.Bar, {
1079 // initComponent replaces the constructor:
1080 Ext.Foo = Ext.extend(Ext.Bar, {
1081 initComponent : function(){
1082 // call superclass initComponent
1083 Ext.Container.superclass.initComponent.call(this);
1092 initComponent : function(){
1094 * this is double processing, however it allows people to be able to do
1100 * MyClass.superclass.initComponent.call(this);
1103 this.on(this.listeners);
1104 delete this.listeners;
1106 this.enableBubble(this.bubbleEvents);
1110 * <p>Render this Component into the passed HTML element.</p>
1111 * <p><b>If you are using a {@link Ext.Container Container} object to house this Component, then
1112 * do not use the render method.</b></p>
1113 * <p>A Container's child Components are rendered by that Container's
1114 * {@link Ext.Container#layout layout} manager when the Container is first rendered.</p>
1115 * <p>Certain layout managers allow dynamic addition of child components. Those that do
1116 * include {@link Ext.layout.CardLayout}, {@link Ext.layout.AnchorLayout},
1117 * {@link Ext.layout.FormLayout}, {@link Ext.layout.TableLayout}.</p>
1118 * <p>If the Container is already rendered when a new child Component is added, you may need to call
1119 * the Container's {@link Ext.Container#doLayout doLayout} to refresh the view which causes any
1120 * unrendered child Components to be rendered. This is required so that you can add multiple
1121 * child components if needed while only refreshing the layout once.</p>
1122 * <p>When creating complex UIs, it is important to remember that sizing and positioning
1123 * of child items is the responsibility of the Container's {@link Ext.Container#layout layout} manager.
1124 * If you expect child items to be sized in response to user interactions, you must
1125 * configure the Container with a layout manager which creates and manages the type of layout you
1127 * <p><b>Omitting the Container's {@link Ext.Container#layout layout} config means that a basic
1128 * layout manager is used which does nothing but render child components sequentially into the
1129 * Container. No sizing or positioning will be performed in this situation.</b></p>
1130 * @param {Element/HTMLElement/String} container (optional) The element this Component should be
1131 * rendered into. If it is being created from existing markup, this should be omitted.
1132 * @param {String/Number} position (optional) The element ID or DOM node index within the container <b>before</b>
1133 * which this component will be inserted (defaults to appending to the end of the container)
1135 render : function(container, position){
1136 if(!this.rendered && this.fireEvent('beforerender', this) !== false){
1137 if(!container && this.el){
1138 this.el = Ext.get(this.el);
1139 container = this.el.dom.parentNode;
1140 this.allowDomMove = false;
1142 this.container = Ext.get(container);
1144 this.container.addClass(this.ctCls);
1146 this.rendered = true;
1147 if(position !== undefined){
1148 if(Ext.isNumber(position)){
1149 position = this.container.dom.childNodes[position];
1151 position = Ext.getDom(position);
1154 this.onRender(this.container, position || null);
1156 this.el.removeClass(['x-hidden','x-hide-' + this.hideMode]);
1159 this.el.addClass(this.cls);
1163 this.el.applyStyles(this.style);
1167 this.el.addClassOnOver(this.overCls);
1169 this.fireEvent('render', this);
1172 // Populate content of the component with html, contentEl or
1174 var contentTarget = this.getContentTarget();
1176 contentTarget.update(Ext.DomHelper.markup(this.html));
1179 if (this.contentEl){
1180 var ce = Ext.getDom(this.contentEl);
1181 Ext.fly(ce).removeClass(['x-hidden', 'x-hide-display']);
1182 contentTarget.appendChild(ce);
1185 if (!this.tpl.compile) {
1186 this.tpl = new Ext.XTemplate(this.tpl);
1189 this.tpl[this.tplWriteMode](contentTarget, this.data);
1193 this.afterRender(this.container);
1197 // call this so we don't fire initial hide events.
1201 // pass silent so the event doesn't fire the first time.
1205 if(this.stateful !== false){
1206 this.initStateEvents();
1208 this.fireEvent('afterrender', this);
1215 * Update the content area of a component.
1216 * @param {Mixed} htmlOrData
1217 * If this component has been configured with a template via the tpl config
1218 * then it will use this argument as data to populate the template.
1219 * If this component was not configured with a template, the components
1220 * content area will be updated via Ext.Element update
1221 * @param {Boolean} loadScripts
1222 * (optional) Only legitimate when using the html configuration. Defaults to false
1223 * @param {Function} callback
1224 * (optional) Only legitimate when using the html configuration. Callback to execute when scripts have finished loading
1226 update: function(htmlOrData, loadScripts, cb) {
1227 var contentTarget = this.getContentTarget();
1228 if (this.tpl && typeof htmlOrData !== "string") {
1229 this.tpl[this.tplWriteMode](contentTarget, htmlOrData || {});
1231 var html = Ext.isObject(htmlOrData) ? Ext.DomHelper.markup(htmlOrData) : htmlOrData;
1232 contentTarget.update(html, loadScripts, cb);
1239 * Method to manage awareness of when components are added to their
1240 * respective Container, firing an added event.
1241 * References are established at add time rather than at render time.
1242 * @param {Ext.Container} container Container which holds the component
1243 * @param {number} pos Position at which the component was added
1245 onAdded : function(container, pos) {
1246 this.ownerCt = container;
1248 this.fireEvent('added', this, container, pos);
1253 * Method to manage awareness of when components are removed from their
1254 * respective Container, firing an removed event. References are properly
1255 * cleaned up after removing a component from its owning container.
1257 onRemoved : function() {
1259 this.fireEvent('removed', this, this.ownerCt);
1260 delete this.ownerCt;
1265 * Method to establish a reference to a component.
1267 initRef : function() {
1270 * <p>A path specification, relative to the Component's <code>{@link #ownerCt}</code>
1271 * specifying into which ancestor Container to place a named reference to this Component.</p>
1272 * <p>The ancestor axis can be traversed by using '/' characters in the path.
1273 * For example, to put a reference to a Toolbar Button into <i>the Panel which owns the Toolbar</i>:</p><pre><code>
1274 var myGrid = new Ext.grid.EditorGridPanel({
1275 title: 'My EditorGridPanel',
1277 colModel: myColModel,
1280 handler: saveChanges,
1282 ref: '../saveButton'
1285 afteredit: function() {
1286 // The button reference is in the GridPanel
1287 myGrid.saveButton.enable();
1292 * <p>In the code above, if the <code>ref</code> had been <code>'saveButton'</code>
1293 * the reference would have been placed into the Toolbar. Each '/' in the <code>ref</code>
1294 * moves up one level from the Component's <code>{@link #ownerCt}</code>.</p>
1295 * <p>Also see the <code>{@link #added}</code> and <code>{@link #removed}</code> events.</p>
1297 if(this.ref && !this.refOwner){
1298 var levels = this.ref.split('/'),
1299 last = levels.length,
1303 while(t && i < last){
1308 t[this.refName = levels[--i]] = this;
1310 * @type Ext.Container
1311 * @property refOwner
1312 * The ancestor Container into which the {@link #ref} reference was inserted if this Component
1313 * is a child of a Container, and has been configured with a <code>ref</code>.
1320 removeRef : function() {
1321 if (this.refOwner && this.refName) {
1322 delete this.refOwner[this.refName];
1323 delete this.refOwner;
1328 initState : function(){
1329 if(Ext.state.Manager){
1330 var id = this.getStateId();
1332 var state = Ext.state.Manager.get(id);
1334 if(this.fireEvent('beforestaterestore', this, state) !== false){
1335 this.applyState(Ext.apply({}, state));
1336 this.fireEvent('staterestore', this, state);
1344 getStateId : function(){
1345 return this.stateId || ((/^(ext-comp-|ext-gen)/).test(String(this.id)) ? null : this.id);
1349 initStateEvents : function(){
1350 if(this.stateEvents){
1351 for(var i = 0, e; e = this.stateEvents[i]; i++){
1352 this.on(e, this.saveState, this, {delay:100});
1358 applyState : function(state){
1360 Ext.apply(this, state);
1365 getState : function(){
1370 saveState : function(){
1371 if(Ext.state.Manager && this.stateful !== false){
1372 var id = this.getStateId();
1374 var state = this.getState();
1375 if(this.fireEvent('beforestatesave', this, state) !== false){
1376 Ext.state.Manager.set(id, state);
1377 this.fireEvent('statesave', this, state);
1384 * Apply this component to existing markup that is valid. With this function, no call to render() is required.
1385 * @param {String/HTMLElement} el
1387 applyToMarkup : function(el){
1388 this.allowDomMove = false;
1389 this.el = Ext.get(el);
1390 this.render(this.el.dom.parentNode);
1394 * Adds a CSS class to the component's underlying element.
1395 * @param {string} cls The CSS class name to add
1396 * @return {Ext.Component} this
1398 addClass : function(cls){
1400 this.el.addClass(cls);
1402 this.cls = this.cls ? this.cls + ' ' + cls : cls;
1408 * Removes a CSS class from the component's underlying element.
1409 * @param {string} cls The CSS class name to remove
1410 * @return {Ext.Component} this
1412 removeClass : function(cls){
1414 this.el.removeClass(cls);
1416 this.cls = this.cls.split(' ').remove(cls).join(' ');
1422 // default function is not really useful
1423 onRender : function(ct, position){
1424 if(!this.el && this.autoEl){
1425 if(Ext.isString(this.autoEl)){
1426 this.el = document.createElement(this.autoEl);
1428 var div = document.createElement('div');
1429 Ext.DomHelper.overwrite(div, this.autoEl);
1430 this.el = div.firstChild;
1433 this.el.id = this.getId();
1437 this.el = Ext.get(this.el);
1438 if(this.allowDomMove !== false){
1439 ct.dom.insertBefore(this.el.dom, position);
1441 Ext.removeNode(div);
1449 getAutoCreate : function(){
1450 var cfg = Ext.isObject(this.autoCreate) ?
1451 this.autoCreate : Ext.apply({}, this.defaultAutoCreate);
1452 if(this.id && !cfg.id){
1459 afterRender : Ext.emptyFn,
1462 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
1463 * removing the component from its {@link Ext.Container} (if applicable) and unregistering it from
1464 * {@link Ext.ComponentMgr}. Destruction is generally handled automatically by the framework and this method
1465 * should usually not need to be called directly.
1468 destroy : function(){
1469 if(!this.isDestroyed){
1470 if(this.fireEvent('beforedestroy', this) !== false){
1471 this.destroying = true;
1472 this.beforeDestroy();
1473 if(this.ownerCt && this.ownerCt.remove){
1474 this.ownerCt.remove(this, false);
1478 if(this.actionMode == 'container' || this.removeMode == 'container'){
1479 this.container.remove();
1482 // Stop any buffered tasks
1483 if(this.focusTask && this.focusTask.cancel){
1484 this.focusTask.cancel();
1487 Ext.ComponentMgr.unregister(this);
1488 this.fireEvent('destroy', this);
1489 this.purgeListeners();
1490 this.destroying = false;
1491 this.isDestroyed = true;
1496 deleteMembers : function(){
1497 var args = arguments;
1498 for(var i = 0, len = args.length; i < len; ++i){
1499 delete this[args[i]];
1504 beforeDestroy : Ext.emptyFn,
1507 onDestroy : Ext.emptyFn,
1510 * <p>Returns the {@link Ext.Element} which encapsulates this Component.</p>
1511 * <p>This will <i>usually</i> be a <DIV> element created by the class's onRender method, but
1512 * that may be overridden using the {@link #autoEl} config.</p>
1513 * <br><p><b>Note</b>: this element will not be available until this Component has been rendered.</p><br>
1514 * <p>To add listeners for <b>DOM events</b> to this Component (as opposed to listeners
1515 * for this Component's own Observable events), see the {@link #listeners} config for a suggestion,
1516 * or use a render listener directly:</p><pre><code>
1518 title: 'The Clickable Panel',
1520 render: function(p) {
1521 // Append the Panel to the click handler's argument list.
1522 p.getEl().on('click', handlePanelClick.createDelegate(null, [p], true));
1524 single: true // Remove the listener after first invocation
1528 * @return {Ext.Element} The Element which encapsulates this Component.
1535 getContentTarget : function(){
1540 * Returns the <code>id</code> of this component or automatically generates and
1541 * returns an <code>id</code> if an <code>id</code> is not defined yet:<pre><code>
1542 * 'ext-comp-' + (++Ext.Component.AUTO_ID)
1544 * @return {String} id
1547 return this.id || (this.id = 'ext-comp-' + (++Ext.Component.AUTO_ID));
1551 * Returns the <code>{@link #itemId}</code> of this component. If an
1552 * <code>{@link #itemId}</code> was not assigned through configuration the
1553 * <code>id</code> is returned using <code>{@link #getId}</code>.
1556 getItemId : function(){
1557 return this.itemId || this.getId();
1561 * Try to focus this component.
1562 * @param {Boolean} selectText (optional) If applicable, true to also select the text in this component
1563 * @param {Boolean/Number} delay (optional) Delay the focus this number of milliseconds (true for 10 milliseconds)
1564 * @return {Ext.Component} this
1566 focus : function(selectText, delay){
1568 this.focusTask = new Ext.util.DelayedTask(this.focus, this, [selectText, false]);
1569 this.focusTask.delay(Ext.isNumber(delay) ? delay : 10);
1572 if(this.rendered && !this.isDestroyed){
1574 if(selectText === true){
1575 this.el.dom.select();
1590 * Disable this component and fire the 'disable' event.
1591 * @return {Ext.Component} this
1593 disable : function(/* private */ silent){
1597 this.disabled = true;
1598 if(silent !== true){
1599 this.fireEvent('disable', this);
1605 onDisable : function(){
1606 this.getActionEl().addClass(this.disabledClass);
1607 this.el.dom.disabled = true;
1611 * Enable this component and fire the 'enable' event.
1612 * @return {Ext.Component} this
1614 enable : function(){
1618 this.disabled = false;
1619 this.fireEvent('enable', this);
1624 onEnable : function(){
1625 this.getActionEl().removeClass(this.disabledClass);
1626 this.el.dom.disabled = false;
1630 * Convenience function for setting disabled/enabled by boolean.
1631 * @param {Boolean} disabled
1632 * @return {Ext.Component} this
1634 setDisabled : function(disabled){
1635 return this[disabled ? 'disable' : 'enable']();
1639 * Show this component. Listen to the '{@link #beforeshow}' event and return
1640 * <tt>false</tt> to cancel showing the component. Fires the '{@link #show}'
1641 * event after showing the component.
1642 * @return {Ext.Component} this
1645 if(this.fireEvent('beforeshow', this) !== false){
1646 this.hidden = false;
1647 if(this.autoRender){
1648 this.render(Ext.isBoolean(this.autoRender) ? Ext.getBody() : this.autoRender);
1653 this.fireEvent('show', this);
1659 onShow : function(){
1660 this.getVisibilityEl().removeClass('x-hide-' + this.hideMode);
1664 * Hide this component. Listen to the '{@link #beforehide}' event and return
1665 * <tt>false</tt> to cancel hiding the component. Fires the '{@link #hide}'
1666 * event after hiding the component. Note this method is called internally if
1667 * the component is configured to be <code>{@link #hidden}</code>.
1668 * @return {Ext.Component} this
1671 if(this.fireEvent('beforehide', this) !== false){
1673 this.fireEvent('hide', this);
1687 onHide : function(){
1688 this.getVisibilityEl().addClass('x-hide-' + this.hideMode);
1692 getVisibilityEl : function(){
1693 return this.hideParent ? this.container : this.getActionEl();
1697 * Convenience function to hide or show this component by boolean.
1698 * @param {Boolean} visible True to show, false to hide
1699 * @return {Ext.Component} this
1701 setVisible : function(visible){
1702 return this[visible ? 'show' : 'hide']();
1706 * Returns true if this component is visible.
1707 * @return {Boolean} True if this component is visible, false otherwise.
1709 isVisible : function(){
1710 return this.rendered && this.getVisibilityEl().isVisible();
1714 * Clone the current component using the original config values passed into this instance by default.
1715 * @param {Object} overrides A new config containing any properties to override in the cloned version.
1716 * An id property can be passed on this object, otherwise one will be generated to avoid duplicates.
1717 * @return {Ext.Component} clone The cloned copy of this component
1719 cloneConfig : function(overrides){
1720 overrides = overrides || {};
1721 var id = overrides.id || Ext.id();
1722 var cfg = Ext.applyIf(overrides, this.initialConfig);
1723 cfg.id = id; // prevent dup id
1724 return new this.constructor(cfg);
1728 * Gets the xtype for this component as registered with {@link Ext.ComponentMgr}. For a list of all
1729 * available xtypes, see the {@link Ext.Component} header. Example usage:
1731 var t = new Ext.form.TextField();
1732 alert(t.getXType()); // alerts 'textfield'
1734 * @return {String} The xtype
1736 getXType : function(){
1737 return this.constructor.xtype;
1741 * <p>Tests whether or not this Component is of a specific xtype. This can test whether this Component is descended
1742 * from the xtype (default) or whether it is directly of the xtype specified (shallow = true).</p>
1743 * <p><b>If using your own subclasses, be aware that a Component must register its own xtype
1744 * to participate in determination of inherited xtypes.</b></p>
1745 * <p>For a list of all available xtypes, see the {@link Ext.Component} header.</p>
1746 * <p>Example usage:</p>
1748 var t = new Ext.form.TextField();
1749 var isText = t.isXType('textfield'); // true
1750 var isBoxSubclass = t.isXType('box'); // true, descended from BoxComponent
1751 var isBoxInstance = t.isXType('box', true); // false, not a direct BoxComponent instance
1753 * @param {String/Ext.Component/Class} xtype The xtype to check for this Component. Note that the the component can either be an instance
1754 * or a component class:
1756 var c = new Ext.Component();
1757 console.log(c.isXType(c));
1758 console.log(c.isXType(Ext.Component));
1760 * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
1761 * the default), or true to check whether this Component is directly of the specified xtype.
1762 * @return {Boolean} True if this component descends from the specified xtype, false otherwise.
1764 isXType : function(xtype, shallow){
1765 //assume a string by default
1766 if (Ext.isFunction(xtype)){
1767 xtype = xtype.xtype; //handle being passed the class, e.g. Ext.Component
1768 }else if (Ext.isObject(xtype)){
1769 xtype = xtype.constructor.xtype; //handle being passed an instance
1772 return !shallow ? ('/' + this.getXTypes() + '/').indexOf('/' + xtype + '/') != -1 : this.constructor.xtype == xtype;
1776 * <p>Returns this Component's xtype hierarchy as a slash-delimited string. For a list of all
1777 * available xtypes, see the {@link Ext.Component} header.</p>
1778 * <p><b>If using your own subclasses, be aware that a Component must register its own xtype
1779 * to participate in determination of inherited xtypes.</b></p>
1780 * <p>Example usage:</p>
1782 var t = new Ext.form.TextField();
1783 alert(t.getXTypes()); // alerts 'component/box/field/textfield'
1785 * @return {String} The xtype hierarchy string
1787 getXTypes : function(){
1788 var tc = this.constructor;
1790 var c = [], sc = this;
1791 while(sc && sc.constructor.xtype){
1792 c.unshift(sc.constructor.xtype);
1793 sc = sc.constructor.superclass;
1796 tc.xtypes = c.join('/');
1802 * Find a container above this component at any level by a custom function. If the passed function returns
1803 * true, the container will be returned.
1804 * @param {Function} fn The custom function to call with the arguments (container, this component).
1805 * @return {Ext.Container} The first Container for which the custom function returns true
1807 findParentBy : function(fn) {
1808 for (var p = this.ownerCt; (p != null) && !fn(p, this); p = p.ownerCt);
1813 * Find a container above this component at any level by xtype or class
1814 * @param {String/Ext.Component/Class} xtype The xtype to check for this Component. Note that the the component can either be an instance
1815 * or a component class:
1816 * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
1817 * the default), or true to check whether this Component is directly of the specified xtype.
1818 * @return {Ext.Container} The first Container which matches the given xtype or class
1820 findParentByType : function(xtype, shallow){
1821 return this.findParentBy(function(c){
1822 return c.isXType(xtype, shallow);
1827 * Bubbles up the component/container heirarchy, calling the specified function with each component. The scope (<i>this</i>) of
1828 * function call will be the scope provided or the current component. The arguments to the function
1829 * will be the args provided or the current component. If the function returns false at any point,
1830 * the bubble is stopped.
1831 * @param {Function} fn The function to call
1832 * @param {Object} scope (optional) The scope of the function (defaults to current node)
1833 * @param {Array} args (optional) The args to call the function with (default to passing the current component)
1834 * @return {Ext.Component} this
1836 bubble : function(fn, scope, args){
1839 if(fn.apply(scope || p, args || [p]) === false){
1848 getPositionEl : function(){
1849 return this.positionEl || this.el;
1853 purgeListeners : function(){
1854 Ext.Component.superclass.purgeListeners.call(this);
1856 this.on('beforedestroy', this.clearMons, this, {single: true});
1861 clearMons : function(){
1862 Ext.each(this.mons, function(m){
1863 m.item.un(m.ename, m.fn, m.scope);
1869 createMons: function(){
1872 this.on('beforedestroy', this.clearMons, this, {single: true});
1877 * <p>Adds listeners to any Observable object (or Elements) which are automatically removed when this Component
1878 * is destroyed. Usage:</p><code><pre>
1879 myGridPanel.mon(myGridPanel.getSelectionModel(), 'selectionchange', handleSelectionChange, null, {buffer: 50});
1881 * <p>or:</p><code><pre>
1882 myGridPanel.mon(myGridPanel.getSelectionModel(), {
1883 selectionchange: handleSelectionChange,
1887 * @param {Observable|Element} item The item to which to add a listener/listeners.
1888 * @param {Object|String} ename The event name, or an object containing event name properties.
1889 * @param {Function} fn Optional. If the <code>ename</code> parameter was an event name, this
1890 * is the handler function.
1891 * @param {Object} scope Optional. If the <code>ename</code> parameter was an event name, this
1892 * is the scope (<code>this</code> reference) in which the handler function is executed.
1893 * @param {Object} opt Optional. If the <code>ename</code> parameter was an event name, this
1894 * is the {@link Ext.util.Observable#addListener addListener} options.
1896 mon : function(item, ename, fn, scope, opt){
1898 if(Ext.isObject(ename)){
1899 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
1906 if(Ext.isFunction(o[e])){
1909 item: item, ename: e, fn: o[e], scope: o.scope
1911 item.on(e, o[e], o.scope, o);
1913 // individual options
1915 item: item, ename: e, fn: o[e], scope: o.scope
1924 item: item, ename: ename, fn: fn, scope: scope
1926 item.on(ename, fn, scope, opt);
1930 * Removes listeners that were added by the {@link #mon} method.
1931 * @param {Observable|Element} item The item from which to remove a listener/listeners.
1932 * @param {Object|String} ename The event name, or an object containing event name properties.
1933 * @param {Function} fn Optional. If the <code>ename</code> parameter was an event name, this
1934 * is the handler function.
1935 * @param {Object} scope Optional. If the <code>ename</code> parameter was an event name, this
1936 * is the scope (<code>this</code> reference) in which the handler function is executed.
1938 mun : function(item, ename, fn, scope){
1941 for(var i = 0, len = this.mons.length; i < len; ++i){
1943 if(item === mon.item && ename == mon.ename && fn === mon.fn && scope === mon.scope){
1944 this.mons.splice(i, 1);
1945 item.un(ename, fn, scope);
1954 * Returns the next component in the owning container
1955 * @return Ext.Component
1957 nextSibling : function(){
1959 var index = this.ownerCt.items.indexOf(this);
1960 if(index != -1 && index+1 < this.ownerCt.items.getCount()){
1961 return this.ownerCt.items.itemAt(index+1);
1968 * Returns the previous component in the owning container
1969 * @return Ext.Component
1971 previousSibling : function(){
1973 var index = this.ownerCt.items.indexOf(this);
1975 return this.ownerCt.items.itemAt(index-1);
1982 * Provides the link for Observable's fireEvent method to bubble up the ownership hierarchy.
1983 * @return {Ext.Container} the Container which owns this Component.
1985 getBubbleTarget : function(){
1986 return this.ownerCt;
1990 Ext.reg('component', Ext.Component);
1993 * <p>An Action is a piece of reusable functionality that can be abstracted out of any particular component so that it
1994 * can be usefully shared among multiple components. Actions let you share handlers, configuration options and UI
1995 * updates across any components that support the Action interface (primarily {@link Ext.Toolbar}, {@link Ext.Button}
1996 * and {@link Ext.menu.Menu} components).</p>
1997 * <p>Aside from supporting the config object interface, any component that needs to use Actions must also support
1998 * the following method list, as these will be called as needed by the Action class: setText(string), setIconCls(string),
1999 * setDisabled(boolean), setVisible(boolean) and setHandler(function).</p>
2000 * Example usage:<br>
2002 // Define the shared action. Each component below will have the same
2003 // display text and icon, and will display the same message on click.
2004 var action = new Ext.Action({
2005 {@link #text}: 'Do something',
2006 {@link #handler}: function(){
2007 Ext.Msg.alert('Click', 'You did something.');
2009 {@link #iconCls}: 'do-something',
2010 {@link #itemId}: 'myAction'
2013 var panel = new Ext.Panel({
2018 // Add the action directly to a toolbar as a menu button
2021 text: 'Action Menu',
2022 // Add the action to a menu as a text item
2027 // Add the action to the panel body as a standard button
2028 new Ext.Button(action)
2030 renderTo: Ext.getBody()
2033 // Change the text for all components using the action
2034 action.setText('Something else');
2036 // Reference an action through a container using the itemId
2037 var btn = panel.getComponent('myAction');
2038 var aRef = btn.baseAction;
2039 aRef.setText('New text');
2042 * @param {Object} config The configuration options
2044 Ext.Action = Ext.extend(Object, {
2046 * @cfg {String} text The text to set for all components using this action (defaults to '').
2049 * @cfg {String} iconCls
2050 * The CSS class selector that specifies a background image to be used as the header icon for
2051 * all components using this action (defaults to '').
2052 * <p>An example of specifying a custom icon class would be something like:
2054 // specify the property in the config for the class:
2056 iconCls: 'do-something'
2058 // css class that specifies background image to be used as the icon image:
2059 .do-something { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
2063 * @cfg {Boolean} disabled True to disable all components using this action, false to enable them (defaults to false).
2066 * @cfg {Boolean} hidden True to hide all components using this action, false to show them (defaults to false).
2069 * @cfg {Function} handler The function that will be invoked by each component tied to this action
2070 * when the component's primary event is triggered (defaults to undefined).
2073 * @cfg {String} itemId
2074 * See {@link Ext.Component}.{@link Ext.Component#itemId itemId}.
2077 * @cfg {Object} scope The scope (<tt><b>this</b></tt> reference) in which the
2078 * <code>{@link #handler}</code> is executed. Defaults to this Button.
2081 constructor : function(config){
2082 this.initialConfig = config;
2083 this.itemId = config.itemId = (config.itemId || config.id || Ext.id());
2091 * Sets the text to be displayed by all components using this action.
2092 * @param {String} text The text to display
2094 setText : function(text){
2095 this.initialConfig.text = text;
2096 this.callEach('setText', [text]);
2100 * Gets the text currently displayed by all components using this action.
2102 getText : function(){
2103 return this.initialConfig.text;
2107 * Sets the icon CSS class for all components using this action. The class should supply
2108 * a background image that will be used as the icon image.
2109 * @param {String} cls The CSS class supplying the icon image
2111 setIconClass : function(cls){
2112 this.initialConfig.iconCls = cls;
2113 this.callEach('setIconClass', [cls]);
2117 * Gets the icon CSS class currently used by all components using this action.
2119 getIconClass : function(){
2120 return this.initialConfig.iconCls;
2124 * Sets the disabled state of all components using this action. Shortcut method
2125 * for {@link #enable} and {@link #disable}.
2126 * @param {Boolean} disabled True to disable the component, false to enable it
2128 setDisabled : function(v){
2129 this.initialConfig.disabled = v;
2130 this.callEach('setDisabled', [v]);
2134 * Enables all components using this action.
2136 enable : function(){
2137 this.setDisabled(false);
2141 * Disables all components using this action.
2143 disable : function(){
2144 this.setDisabled(true);
2148 * Returns true if the components using this action are currently disabled, else returns false.
2150 isDisabled : function(){
2151 return this.initialConfig.disabled;
2155 * Sets the hidden state of all components using this action. Shortcut method
2156 * for <code>{@link #hide}</code> and <code>{@link #show}</code>.
2157 * @param {Boolean} hidden True to hide the component, false to show it
2159 setHidden : function(v){
2160 this.initialConfig.hidden = v;
2161 this.callEach('setVisible', [!v]);
2165 * Shows all components using this action.
2168 this.setHidden(false);
2172 * Hides all components using this action.
2175 this.setHidden(true);
2179 * Returns true if the components using this action are currently hidden, else returns false.
2181 isHidden : function(){
2182 return this.initialConfig.hidden;
2186 * Sets the function that will be called by each Component using this action when its primary event is triggered.
2187 * @param {Function} fn The function that will be invoked by the action's components. The function
2188 * will be called with no arguments.
2189 * @param {Object} scope The scope (<code>this</code> reference) in which the function is executed. Defaults to the Component firing the event.
2191 setHandler : function(fn, scope){
2192 this.initialConfig.handler = fn;
2193 this.initialConfig.scope = scope;
2194 this.callEach('setHandler', [fn, scope]);
2198 * Executes the specified function once for each Component currently tied to this action. The function passed
2199 * in should accept a single argument that will be an object that supports the basic Action config/method interface.
2200 * @param {Function} fn The function to execute for each component
2201 * @param {Object} scope The scope (<code>this</code> reference) in which the function is executed. Defaults to the Component.
2203 each : function(fn, scope){
2204 Ext.each(this.items, fn, scope);
2208 callEach : function(fnName, args){
2209 var cs = this.items;
2210 for(var i = 0, len = cs.length; i < len; i++){
2211 cs[i][fnName].apply(cs[i], args);
2216 addComponent : function(comp){
2217 this.items.push(comp);
2218 comp.on('destroy', this.removeComponent, this);
2222 removeComponent : function(comp){
2223 this.items.remove(comp);
2227 * Executes this action manually using the handler function specified in the original config object
2228 * or the handler function set with <code>{@link #setHandler}</code>. Any arguments passed to this
2229 * function will be passed on to the handler function.
2230 * @param {Mixed} arg1 (optional) Variable number of arguments passed to the handler function
2231 * @param {Mixed} arg2 (optional)
2232 * @param {Mixed} etc... (optional)
2234 execute : function(){
2235 this.initialConfig.handler.apply(this.initialConfig.scope || window, arguments);
2240 * @extends Ext.Element
2241 * An extended {@link Ext.Element} object that supports a shadow and shim, constrain to viewport and
2242 * automatic maintaining of shadow/shim positions.
2243 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
2244 * @cfg {String/Boolean} shadow True to automatically create an {@link Ext.Shadow}, or a string indicating the
2245 * shadow's display {@link Ext.Shadow#mode}. False to disable the shadow. (defaults to false)
2246 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: 'div', cls: 'x-layer'}).
2247 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
2248 * @cfg {String} cls CSS class to add to the element
2249 * @cfg {Number} zindex Starting z-index (defaults to 11000)
2250 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 4)
2251 * @cfg {Boolean} useDisplay
2252 * Defaults to use css offsets to hide the Layer. Specify <tt>true</tt>
2253 * to use css style <tt>'display:none;'</tt> to hide the Layer.
2255 * @param {Object} config An object with config options.
2256 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
2259 Ext.Layer = function(config, existingEl){
2260 config = config || {};
2261 var dh = Ext.DomHelper,
2262 cp = config.parentEl, pel = cp ? Ext.getDom(cp) : document.body;
2265 this.dom = Ext.getDom(existingEl);
2268 var o = config.dh || {tag: 'div', cls: 'x-layer'};
2269 this.dom = dh.append(pel, o);
2272 this.addClass(config.cls);
2274 this.constrain = config.constrain !== false;
2275 this.setVisibilityMode(Ext.Element.VISIBILITY);
2277 this.id = this.dom.id = config.id;
2279 this.id = Ext.id(this.dom);
2281 this.zindex = config.zindex || this.getZIndex();
2282 this.position('absolute', this.zindex);
2284 this.shadowOffset = config.shadowOffset || 4;
2285 this.shadow = new Ext.Shadow({
2286 offset : this.shadowOffset,
2287 mode : config.shadow
2290 this.shadowOffset = 0;
2292 this.useShim = config.shim !== false && Ext.useShims;
2293 this.useDisplay = config.useDisplay;
2297 var supr = Ext.Element.prototype;
2299 // shims are shared among layer to keep from having 100 iframes
2302 Ext.extend(Ext.Layer, Ext.Element, {
2304 getZIndex : function(){
2305 return this.zindex || parseInt((this.getShim() || this).getStyle('z-index'), 10) || 11000;
2308 getShim : function(){
2315 var shim = shims.shift();
2317 shim = this.createShim();
2318 shim.enableDisplayMode('block');
2319 shim.dom.style.display = 'none';
2320 shim.dom.style.visibility = 'visible';
2322 var pn = this.dom.parentNode;
2323 if(shim.dom.parentNode != pn){
2324 pn.insertBefore(shim.dom, this.dom);
2326 shim.setStyle('z-index', this.getZIndex()-2);
2331 hideShim : function(){
2333 this.shim.setDisplayed(false);
2334 shims.push(this.shim);
2339 disableShadow : function(){
2341 this.shadowDisabled = true;
2343 this.lastShadowOffset = this.shadowOffset;
2344 this.shadowOffset = 0;
2348 enableShadow : function(show){
2350 this.shadowDisabled = false;
2351 this.shadowOffset = this.lastShadowOffset;
2352 delete this.lastShadowOffset;
2360 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
2361 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
2362 sync : function(doShow){
2363 var shadow = this.shadow;
2364 if(!this.updating && this.isVisible() && (shadow || this.useShim)){
2365 var shim = this.getShim(),
2366 w = this.getWidth(),
2367 h = this.getHeight(),
2368 l = this.getLeft(true),
2369 t = this.getTop(true);
2371 if(shadow && !this.shadowDisabled){
2372 if(doShow && !shadow.isVisible()){
2375 shadow.realign(l, t, w, h);
2381 // fit the shim behind the shadow, so it is shimmed too
2382 var shadowAdj = shadow.el.getXY(), shimStyle = shim.dom.style,
2383 shadowSize = shadow.el.getSize();
2384 shimStyle.left = (shadowAdj[0])+'px';
2385 shimStyle.top = (shadowAdj[1])+'px';
2386 shimStyle.width = (shadowSize.width)+'px';
2387 shimStyle.height = (shadowSize.height)+'px';
2394 shim.setLeftTop(l, t);
2400 destroy : function(){
2405 this.removeAllListeners();
2406 Ext.removeNode(this.dom);
2410 remove : function(){
2415 beginUpdate : function(){
2416 this.updating = true;
2420 endUpdate : function(){
2421 this.updating = false;
2426 hideUnders : function(negOffset){
2434 constrainXY : function(){
2436 var vw = Ext.lib.Dom.getViewWidth(),
2437 vh = Ext.lib.Dom.getViewHeight();
2438 var s = Ext.getDoc().getScroll();
2440 var xy = this.getXY();
2441 var x = xy[0], y = xy[1];
2442 var so = this.shadowOffset;
2443 var w = this.dom.offsetWidth+so, h = this.dom.offsetHeight+so;
2444 // only move it if it needs it
2446 // first validate right/bottom
2447 if((x + w) > vw+s.left){
2451 if((y + h) > vh+s.top){
2455 // then make sure top/left isn't negative
2466 var ay = this.avoidY;
2467 if(y <= ay && (y+h) >= ay){
2473 supr.setXY.call(this, xy);
2480 getConstrainOffset : function(){
2481 return this.shadowOffset;
2484 isVisible : function(){
2485 return this.visible;
2489 showAction : function(){
2490 this.visible = true; // track visibility to prevent getStyle calls
2491 if(this.useDisplay === true){
2492 this.setDisplayed('');
2493 }else if(this.lastXY){
2494 supr.setXY.call(this, this.lastXY);
2495 }else if(this.lastLT){
2496 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
2501 hideAction : function(){
2502 this.visible = false;
2503 if(this.useDisplay === true){
2504 this.setDisplayed(false);
2506 this.setLeftTop(-10000,-10000);
2510 // overridden Element method
2511 setVisible : function(v, a, d, c, e){
2516 var cb = function(){
2521 }.createDelegate(this);
2522 supr.setVisible.call(this, true, true, d, cb, e);
2525 this.hideUnders(true);
2534 }.createDelegate(this);
2536 supr.setVisible.call(this, v, a, d, cb, e);
2546 storeXY : function(xy){
2551 storeLeftTop : function(left, top){
2553 this.lastLT = [left, top];
2557 beforeFx : function(){
2558 this.beforeAction();
2559 return Ext.Layer.superclass.beforeFx.apply(this, arguments);
2563 afterFx : function(){
2564 Ext.Layer.superclass.afterFx.apply(this, arguments);
2565 this.sync(this.isVisible());
2569 beforeAction : function(){
2570 if(!this.updating && this.shadow){
2575 // overridden Element method
2576 setLeft : function(left){
2577 this.storeLeftTop(left, this.getTop(true));
2578 supr.setLeft.apply(this, arguments);
2583 setTop : function(top){
2584 this.storeLeftTop(this.getLeft(true), top);
2585 supr.setTop.apply(this, arguments);
2590 setLeftTop : function(left, top){
2591 this.storeLeftTop(left, top);
2592 supr.setLeftTop.apply(this, arguments);
2597 setXY : function(xy, a, d, c, e){
2599 this.beforeAction();
2601 var cb = this.createCB(c);
2602 supr.setXY.call(this, xy, a, d, cb, e);
2610 createCB : function(c){
2621 // overridden Element method
2622 setX : function(x, a, d, c, e){
2623 this.setXY([x, this.getY()], a, d, c, e);
2627 // overridden Element method
2628 setY : function(y, a, d, c, e){
2629 this.setXY([this.getX(), y], a, d, c, e);
2633 // overridden Element method
2634 setSize : function(w, h, a, d, c, e){
2635 this.beforeAction();
2636 var cb = this.createCB(c);
2637 supr.setSize.call(this, w, h, a, d, cb, e);
2644 // overridden Element method
2645 setWidth : function(w, a, d, c, e){
2646 this.beforeAction();
2647 var cb = this.createCB(c);
2648 supr.setWidth.call(this, w, a, d, cb, e);
2655 // overridden Element method
2656 setHeight : function(h, a, d, c, e){
2657 this.beforeAction();
2658 var cb = this.createCB(c);
2659 supr.setHeight.call(this, h, a, d, cb, e);
2666 // overridden Element method
2667 setBounds : function(x, y, w, h, a, d, c, e){
2668 this.beforeAction();
2669 var cb = this.createCB(c);
2671 this.storeXY([x, y]);
2672 supr.setXY.call(this, [x, y]);
2673 supr.setSize.call(this, w, h, a, d, cb, e);
2676 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
2682 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
2683 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
2684 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
2685 * @param {Number} zindex The new z-index to set
2686 * @return {this} The Layer
2688 setZIndex : function(zindex){
2689 this.zindex = zindex;
2690 this.setStyle('z-index', zindex + 2);
2692 this.shadow.setZIndex(zindex + 1);
2695 this.shim.setStyle('z-index', zindex);
2703 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
2704 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
2705 * functionality that can also provide the same shadow effect, see the {@link Ext.Layer} class.
2707 * Create a new Shadow
2708 * @param {Object} config The config object
2710 Ext.Shadow = function(config) {
2711 Ext.apply(this, config);
2712 if (typeof this.mode != "string") {
2713 this.mode = this.defaultMode;
2715 var o = this.offset,
2719 rad = Math.floor(this.offset / 2);
2720 switch (this.mode.toLowerCase()) {
2721 // all this hideous nonsense calculates the various offsets for shadows
2727 a.l -= this.offset + rad;
2728 a.t -= this.offset + rad;
2739 a.l -= (this.offset - rad);
2740 a.t -= this.offset + rad;
2742 a.w -= (this.offset - rad) * 2;
2748 a.w = a.h = (o * 2);
2753 a.l -= (this.offset - rad);
2754 a.t -= (this.offset - rad);
2756 a.w -= (this.offset + rad + 1);
2757 a.h -= (this.offset + rad);
2766 Ext.Shadow.prototype = {
2768 * @cfg {String} mode
2769 * The shadow display mode. Supports the following options:<div class="mdetail-params"><ul>
2770 * <li><b><tt>sides</tt></b> : Shadow displays on both sides and bottom only</li>
2771 * <li><b><tt>frame</tt></b> : Shadow displays equally on all four sides</li>
2772 * <li><b><tt>drop</tt></b> : Traditional bottom-right drop shadow</li>
2776 * @cfg {String} offset
2777 * The number of pixels to offset the shadow from the element (defaults to <tt>4</tt>)
2782 defaultMode: "drop",
2785 * Displays the shadow under the target element
2786 * @param {Mixed} targetEl The id or element under which the shadow should display
2788 show: function(target) {
2789 target = Ext.get(target);
2791 this.el = Ext.Shadow.Pool.pull();
2792 if (this.el.dom.nextSibling != target.dom) {
2793 this.el.insertBefore(target);
2796 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10) - 1);
2798 this.el.dom.style.filter = "progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius=" + (this.offset) + ")";
2801 target.getLeft(true),
2802 target.getTop(true),
2806 this.el.dom.style.display = "block";
2810 * Returns true if the shadow is visible, else false
2812 isVisible: function() {
2813 return this.el ? true: false;
2817 * Direct alignment when values are already available. Show must be called at least once before
2818 * calling this method to ensure it is initialized.
2819 * @param {Number} left The target element left position
2820 * @param {Number} top The target element top position
2821 * @param {Number} width The target element width
2822 * @param {Number} height The target element height
2824 realign: function(l, t, w, h) {
2828 var a = this.adjusts,
2838 s.left = (l + a.l) + "px";
2839 s.top = (t + a.t) + "px";
2840 if (s.width != sws || s.height != shs) {
2845 sww = Math.max(0, (sw - 12)) + "px";
2846 cn[0].childNodes[1].style.width = sww;
2847 cn[1].childNodes[1].style.width = sww;
2848 cn[2].childNodes[1].style.width = sww;
2849 cn[1].style.height = Math.max(0, (sh - 12)) + "px";
2859 this.el.dom.style.display = "none";
2860 Ext.Shadow.Pool.push(this.el);
2866 * Adjust the z-index of this shadow
2867 * @param {Number} zindex The new z-index
2869 setZIndex: function(z) {
2872 this.el.setStyle("z-index", z);
2877 // Private utility class that manages the internal Shadow cache
2878 Ext.Shadow.Pool = function() {
2881 '<div class="x-ie-shadow"></div>':
2882 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
2887 sh = Ext.get(Ext.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
2888 sh.autoBoxAdjust = false;
2893 push: function(sh) {
2898 * @class Ext.BoxComponent
2899 * @extends Ext.Component
2900 * <p>Base class for any {@link Ext.Component Component} that is to be sized as a box, using width and height.</p>
2901 * <p>BoxComponent provides automatic box model adjustments for sizing and positioning and will work correctly
2902 * within the Component rendering model.</p>
2903 * <p>A BoxComponent may be created as a custom Component which encapsulates any HTML element, either a pre-existing
2904 * element, or one that is created to your specifications at render time. Usually, to participate in layouts,
2905 * a Component will need to be a <b>Box</b>Component in order to have its width and height managed.</p>
2906 * <p>To use a pre-existing element as a BoxComponent, configure it so that you preset the <b>el</b> property to the
2907 * element to reference:<pre><code>
2908 var pageHeader = new Ext.BoxComponent({
2911 * This may then be {@link Ext.Container#add added} to a {@link Ext.Container Container} as a child item.</p>
2912 * <p>To create a BoxComponent based around a HTML element to be created at render time, use the
2913 * {@link Ext.Component#autoEl autoEl} config option which takes the form of a
2914 * {@link Ext.DomHelper DomHelper} specification:<pre><code>
2915 var myImage = new Ext.BoxComponent({
2918 src: '/images/my-image.jpg'
2920 });</code></pre></p>
2922 * @param {Ext.Element/String/Object} config The configuration options.
2925 Ext.BoxComponent = Ext.extend(Ext.Component, {
2927 // Configs below are used for all Components when rendered by BoxLayout.
2929 * @cfg {Number} flex
2930 * <p><b>Note</b>: this config is only used when this Component is rendered
2931 * by a Container which has been configured to use a <b>{@link Ext.layout.BoxLayout BoxLayout}.</b>
2932 * Each child Component with a <code>flex</code> property will be flexed either vertically (by a VBoxLayout)
2933 * or horizontally (by an HBoxLayout) according to the item's <b>relative</b> <code>flex</code> value
2934 * compared to the sum of all Components with <code>flex</flex> value specified. Any child items that have
2935 * either a <code>flex = 0</code> or <code>flex = undefined</code> will not be 'flexed' (the initial size will not be changed).
2937 // Configs below are used for all Components when rendered by AnchorLayout.
2939 * @cfg {String} anchor <p><b>Note</b>: this config is only used when this Component is rendered
2940 * by a Container which has been configured to use an <b>{@link Ext.layout.AnchorLayout AnchorLayout} (or subclass thereof).</b>
2941 * based layout manager, for example:<div class="mdetail-params"><ul>
2942 * <li>{@link Ext.form.FormPanel}</li>
2943 * <li>specifying <code>layout: 'anchor' // or 'form', or 'absolute'</code></li>
2945 * <p>See {@link Ext.layout.AnchorLayout}.{@link Ext.layout.AnchorLayout#anchor anchor} also.</p>
2947 // tabTip config is used when a BoxComponent is a child of a TabPanel
2949 * @cfg {String} tabTip
2950 * <p><b>Note</b>: this config is only used when this BoxComponent is a child item of a TabPanel.</p>
2951 * A string to be used as innerHTML (html tags are accepted) to show in a tooltip when mousing over
2952 * the associated tab selector element. {@link Ext.QuickTips}.init()
2953 * must be called in order for the tips to render.
2955 // Configs below are used for all Components when rendered by BorderLayout.
2957 * @cfg {String} region <p><b>Note</b>: this config is only used when this BoxComponent is rendered
2958 * by a Container which has been configured to use the <b>{@link Ext.layout.BorderLayout BorderLayout}</b>
2959 * layout manager (e.g. specifying <tt>layout:'border'</tt>).</p><br>
2960 * <p>See {@link Ext.layout.BorderLayout} also.</p>
2962 // margins config is used when a BoxComponent is rendered by BorderLayout or BoxLayout.
2964 * @cfg {Object} margins <p><b>Note</b>: this config is only used when this BoxComponent is rendered
2965 * by a Container which has been configured to use the <b>{@link Ext.layout.BorderLayout BorderLayout}</b>
2966 * or one of the two <b>{@link Ext.layout.BoxLayout BoxLayout} subclasses.</b></p>
2967 * <p>An object containing margins to apply to this BoxComponent in the
2968 * format:</p><pre><code>
2971 right: (right margin),
2972 bottom: (bottom margin),
2975 * <p>May also be a string containing space-separated, numeric margin values. The order of the
2976 * sides associated with each value matches the way CSS processes margin values:</p>
2977 * <p><div class="mdetail-params"><ul>
2978 * <li>If there is only one value, it applies to all sides.</li>
2979 * <li>If there are two values, the top and bottom borders are set to the first value and the
2980 * right and left are set to the second.</li>
2981 * <li>If there are three values, the top is set to the first value, the left and right are set
2982 * to the second, and the bottom is set to the third.</li>
2983 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
2985 * <p>Defaults to:</p><pre><code>
2986 * {top:0, right:0, bottom:0, left:0}
2991 * The local x (left) coordinate for this component if contained within a positioning container.
2995 * The local y (top) coordinate for this component if contained within a positioning container.
2998 * @cfg {Number} pageX
2999 * The page level x coordinate for this component if contained within a positioning container.
3002 * @cfg {Number} pageY
3003 * The page level y coordinate for this component if contained within a positioning container.
3006 * @cfg {Number} height
3007 * The height of this component in pixels (defaults to auto).
3008 * <b>Note</b> to express this dimension as a percentage or offset see {@link Ext.Component#anchor}.
3011 * @cfg {Number} width
3012 * The width of this component in pixels (defaults to auto).
3013 * <b>Note</b> to express this dimension as a percentage or offset see {@link Ext.Component#anchor}.
3016 * @cfg {Number} boxMinHeight
3017 * <p>The minimum value in pixels which this BoxComponent will set its height to.</p>
3018 * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
3021 * @cfg {Number} boxMinWidth
3022 * <p>The minimum value in pixels which this BoxComponent will set its width to.</p>
3023 * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
3026 * @cfg {Number} boxMaxHeight
3027 * <p>The maximum value in pixels which this BoxComponent will set its height to.</p>
3028 * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
3031 * @cfg {Number} boxMaxWidth
3032 * <p>The maximum value in pixels which this BoxComponent will set its width to.</p>
3033 * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
3036 * @cfg {Boolean} autoHeight
3037 * <p>True to use height:'auto', false to use fixed height (or allow it to be managed by its parent
3038 * Container's {@link Ext.Container#layout layout manager}. Defaults to false.</p>
3039 * <p><b>Note</b>: Although many components inherit this config option, not all will
3040 * function as expected with a height of 'auto'. Setting autoHeight:true means that the
3041 * browser will manage height based on the element's contents, and that Ext will not manage it at all.</p>
3042 * <p>If the <i>browser</i> is managing the height, be aware that resizes performed by the browser in response
3043 * to changes within the structure of the Component cannot be detected. Therefore changes to the height might
3044 * result in elements needing to be synchronized with the new height. Example:</p><pre><code>
3045 var w = new Ext.Window({
3050 title: 'Collapse Me',
3055 beforecollapse: function() {
3058 beforeexpand: function() {
3061 collapse: function() {
3064 expand: function() {
3073 * @cfg {Boolean} autoWidth
3074 * <p>True to use width:'auto', false to use fixed width (or allow it to be managed by its parent
3075 * Container's {@link Ext.Container#layout layout manager}. Defaults to false.</p>
3076 * <p><b>Note</b>: Although many components inherit this config option, not all will
3077 * function as expected with a width of 'auto'. Setting autoWidth:true means that the
3078 * browser will manage width based on the element's contents, and that Ext will not manage it at all.</p>
3079 * <p>If the <i>browser</i> is managing the width, be aware that resizes performed by the browser in response
3080 * to changes within the structure of the Component cannot be detected. Therefore changes to the width might
3081 * result in elements needing to be synchronized with the new width. For example, where the target element is:</p><pre><code>
3082 <div id='grid-container' style='margin-left:25%;width:50%'></div>
3084 * A Panel rendered into that target element must listen for browser window resize in order to relay its
3085 * child items when the browser changes its width:<pre><code>
3086 var myPanel = new Ext.Panel({
3087 renderTo: 'grid-container',
3088 monitorResize: true, // relay on browser resize
3110 * @cfg {Boolean} autoScroll
3111 * <code>true</code> to use overflow:'auto' on the components layout element and show scroll bars automatically when
3112 * necessary, <code>false</code> to clip any overflowing content (defaults to <code>false</code>).
3115 /* // private internal config
3116 * {Boolean} deferHeight
3117 * True to defer height calculations to an external component, false to allow this component to set its own
3118 * height (defaults to false).
3122 initComponent : function(){
3123 Ext.BoxComponent.superclass.initComponent.call(this);
3127 * Fires after the component is resized.
3128 * @param {Ext.Component} this
3129 * @param {Number} adjWidth The box-adjusted width that was set
3130 * @param {Number} adjHeight The box-adjusted height that was set
3131 * @param {Number} rawWidth The width that was originally specified
3132 * @param {Number} rawHeight The height that was originally specified
3137 * Fires after the component is moved.
3138 * @param {Ext.Component} this
3139 * @param {Number} x The new x position
3140 * @param {Number} y The new y position
3146 // private, set in afterRender to signify that the component has been rendered
3148 // private, used to defer height settings to subclasses
3152 * Sets the width and height of this BoxComponent. This method fires the {@link #resize} event. This method can accept
3153 * either width and height as separate arguments, or you can pass a size object like <code>{width:10, height:20}</code>.
3154 * @param {Mixed} width The new width to set. This may be one of:<div class="mdetail-params"><ul>
3155 * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li>
3156 * <li>A String used to set the CSS width style.</li>
3157 * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>
3158 * <li><code>undefined</code> to leave the width unchanged.</li>
3160 * @param {Mixed} height The new height to set (not required if a size object is passed as the first arg).
3161 * This may be one of:<div class="mdetail-params"><ul>
3162 * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li>
3163 * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
3164 * <li><code>undefined</code> to leave the height unchanged.</li>
3166 * @return {Ext.BoxComponent} this
3168 setSize : function(w, h){
3170 // support for standard size objects
3171 if(typeof w == 'object'){
3175 if (Ext.isDefined(w) && Ext.isDefined(this.boxMinWidth) && (w < this.boxMinWidth)) {
3176 w = this.boxMinWidth;
3178 if (Ext.isDefined(h) && Ext.isDefined(this.boxMinHeight) && (h < this.boxMinHeight)) {
3179 h = this.boxMinHeight;
3181 if (Ext.isDefined(w) && Ext.isDefined(this.boxMaxWidth) && (w > this.boxMaxWidth)) {
3182 w = this.boxMaxWidth;
3184 if (Ext.isDefined(h) && Ext.isDefined(this.boxMaxHeight) && (h > this.boxMaxHeight)) {
3185 h = this.boxMaxHeight;
3194 // prevent recalcs when not needed
3195 if(this.cacheSizes !== false && this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
3198 this.lastSize = {width: w, height: h};
3199 var adj = this.adjustSize(w, h),
3203 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
3204 rz = this.getResizeEl();
3205 if(!this.deferHeight && aw !== undefined && ah !== undefined){
3207 }else if(!this.deferHeight && ah !== undefined){
3209 }else if(aw !== undefined){
3212 this.onResize(aw, ah, w, h);
3213 this.fireEvent('resize', this, aw, ah, w, h);
3219 * Sets the width of the component. This method fires the {@link #resize} event.
3220 * @param {Mixed} width The new width to set. This may be one of:<div class="mdetail-params"><ul>
3221 * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit defaultUnit}s (by default, pixels).</li>
3222 * <li>A String used to set the CSS width style.</li>
3224 * @return {Ext.BoxComponent} this
3226 setWidth : function(width){
3227 return this.setSize(width);
3231 * Sets the height of the component. This method fires the {@link #resize} event.
3232 * @param {Mixed} height The new height to set. This may be one of:<div class="mdetail-params"><ul>
3233 * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit defaultUnit}s (by default, pixels).</li>
3234 * <li>A String used to set the CSS height style.</li>
3235 * <li><i>undefined</i> to leave the height unchanged.</li>
3237 * @return {Ext.BoxComponent} this
3239 setHeight : function(height){
3240 return this.setSize(undefined, height);
3244 * Gets the current size of the component's underlying element.
3245 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
3247 getSize : function(){
3248 return this.getResizeEl().getSize();
3252 * Gets the current width of the component's underlying element.
3255 getWidth : function(){
3256 return this.getResizeEl().getWidth();
3260 * Gets the current height of the component's underlying element.
3263 getHeight : function(){
3264 return this.getResizeEl().getHeight();
3268 * Gets the current size of the component's underlying element, including space taken by its margins.
3269 * @return {Object} An object containing the element's size {width: (element width + left/right margins), height: (element height + top/bottom margins)}
3271 getOuterSize : function(){
3272 var el = this.getResizeEl();
3273 return {width: el.getWidth() + el.getMargins('lr'),
3274 height: el.getHeight() + el.getMargins('tb')};
3278 * Gets the current XY position of the component's underlying element.
3279 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
3280 * @return {Array} The XY position of the element (e.g., [100, 200])
3282 getPosition : function(local){
3283 var el = this.getPositionEl();
3285 return [el.getLeft(true), el.getTop(true)];
3287 return this.xy || el.getXY();
3291 * Gets the current box measurements of the component's underlying element.
3292 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
3293 * @return {Object} box An object in the format {x, y, width, height}
3295 getBox : function(local){
3296 var pos = this.getPosition(local);
3297 var s = this.getSize();
3304 * Sets the current box measurements of the component's underlying element.
3305 * @param {Object} box An object in the format {x, y, width, height}
3306 * @return {Ext.BoxComponent} this
3308 updateBox : function(box){
3309 this.setSize(box.width, box.height);
3310 this.setPagePosition(box.x, box.y);
3315 * <p>Returns the outermost Element of this Component which defines the Components overall size.</p>
3316 * <p><i>Usually</i> this will return the same Element as <code>{@link #getEl}</code>,
3317 * but in some cases, a Component may have some more wrapping Elements around its main
3318 * active Element.</p>
3319 * <p>An example is a ComboBox. It is encased in a <i>wrapping</i> Element which
3320 * contains both the <code><input></code> Element (which is what would be returned
3321 * by its <code>{@link #getEl}</code> method, <i>and</i> the trigger button Element.
3322 * This Element is returned as the <code>resizeEl</code>.
3323 * @return {Ext.Element} The Element which is to be resized by size managing layouts.
3325 getResizeEl : function(){
3326 return this.resizeEl || this.el;
3330 * Sets the overflow on the content element of the component.
3331 * @param {Boolean} scroll True to allow the Component to auto scroll.
3332 * @return {Ext.BoxComponent} this
3334 setAutoScroll : function(scroll){
3336 this.getContentTarget().setOverflow(scroll ? 'auto' : '');
3338 this.autoScroll = scroll;
3343 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
3344 * This method fires the {@link #move} event.
3345 * @param {Number} left The new left
3346 * @param {Number} top The new top
3347 * @return {Ext.BoxComponent} this
3349 setPosition : function(x, y){
3350 if(x && typeof x[1] == 'number'){
3359 var adj = this.adjustPosition(x, y);
3360 var ax = adj.x, ay = adj.y;
3362 var el = this.getPositionEl();
3363 if(ax !== undefined || ay !== undefined){
3364 if(ax !== undefined && ay !== undefined){
3365 el.setLeftTop(ax, ay);
3366 }else if(ax !== undefined){
3368 }else if(ay !== undefined){
3371 this.onPosition(ax, ay);
3372 this.fireEvent('move', this, ax, ay);
3378 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
3379 * This method fires the {@link #move} event.
3380 * @param {Number} x The new x position
3381 * @param {Number} y The new y position
3382 * @return {Ext.BoxComponent} this
3384 setPagePosition : function(x, y){
3385 if(x && typeof x[1] == 'number'){
3394 if(x === undefined || y === undefined){ // cannot translate undefined points
3397 var p = this.getPositionEl().translatePoints(x, y);
3398 this.setPosition(p.left, p.top);
3403 afterRender : function(){
3404 Ext.BoxComponent.superclass.afterRender.call(this);
3406 this.resizeEl = Ext.get(this.resizeEl);
3408 if(this.positionEl){
3409 this.positionEl = Ext.get(this.positionEl);
3411 this.boxReady = true;
3412 Ext.isDefined(this.autoScroll) && this.setAutoScroll(this.autoScroll);
3413 this.setSize(this.width, this.height);
3414 if(this.x || this.y){
3415 this.setPosition(this.x, this.y);
3416 }else if(this.pageX || this.pageY){
3417 this.setPagePosition(this.pageX, this.pageY);
3422 * Force the component's size to recalculate based on the underlying element's current height and width.
3423 * @return {Ext.BoxComponent} this
3425 syncSize : function(){
3426 delete this.lastSize;
3427 this.setSize(this.autoWidth ? undefined : this.getResizeEl().getWidth(), this.autoHeight ? undefined : this.getResizeEl().getHeight());
3432 * Called after the component is resized, this method is empty by default but can be implemented by any
3433 * subclass that needs to perform custom logic after a resize occurs.
3434 * @param {Number} adjWidth The box-adjusted width that was set
3435 * @param {Number} adjHeight The box-adjusted height that was set
3436 * @param {Number} rawWidth The width that was originally specified
3437 * @param {Number} rawHeight The height that was originally specified
3439 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
3443 * Called after the component is moved, this method is empty by default but can be implemented by any
3444 * subclass that needs to perform custom logic after a move occurs.
3445 * @param {Number} x The new x position
3446 * @param {Number} y The new y position
3448 onPosition : function(x, y){
3453 adjustSize : function(w, h){
3457 if(this.autoHeight){
3460 return {width : w, height: h};
3464 adjustPosition : function(x, y){
3465 return {x : x, y: y};
3468 Ext.reg('box', Ext.BoxComponent);
3473 * @extends Ext.BoxComponent
3474 * <p>Used to provide a sizable space in a layout.</p>
3476 * @param {Object} config
3478 Ext.Spacer = Ext.extend(Ext.BoxComponent, {
3481 Ext.reg('spacer', Ext.Spacer);/**
3482 * @class Ext.SplitBar
3483 * @extends Ext.util.Observable
3484 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
3488 var split = new Ext.SplitBar("elementToDrag", "elementToSize",
3489 Ext.SplitBar.HORIZONTAL, Ext.SplitBar.LEFT);
3490 split.setAdapter(new Ext.SplitBar.AbsoluteLayoutAdapter("container"));
3491 split.minSize = 100;
3492 split.maxSize = 600;
3493 split.animate = true;
3494 split.on('moved', splitterMoved);
3497 * Create a new SplitBar
3498 * @param {Mixed} dragElement The element to be dragged and act as the SplitBar.
3499 * @param {Mixed} resizingElement The element to be resized based on where the SplitBar element is dragged
3500 * @param {Number} orientation (optional) Either Ext.SplitBar.HORIZONTAL or Ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
3501 * @param {Number} placement (optional) Either Ext.SplitBar.LEFT or Ext.SplitBar.RIGHT for horizontal or
3502 Ext.SplitBar.TOP or Ext.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
3503 position of the SplitBar).
3505 Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
3508 this.el = Ext.get(dragElement, true);
3509 this.el.dom.unselectable = "on";
3511 this.resizingEl = Ext.get(resizingElement, true);
3515 * The orientation of the split. Either Ext.SplitBar.HORIZONTAL or Ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
3516 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
3519 this.orientation = orientation || Ext.SplitBar.HORIZONTAL;
3522 * The increment, in pixels by which to move this SplitBar. When <i>undefined</i>, the SplitBar moves smoothly.
3524 * @property tickSize
3527 * The minimum size of the resizing element. (Defaults to 0)
3533 * The maximum size of the resizing element. (Defaults to 2000)
3536 this.maxSize = 2000;
3539 * Whether to animate the transition to the new size
3542 this.animate = false;
3545 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
3548 this.useShim = false;
3555 this.proxy = Ext.SplitBar.createProxy(this.orientation);
3557 this.proxy = Ext.get(existingProxy).dom;
3560 this.dd = new Ext.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
3563 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
3566 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
3569 this.dragSpecs = {};
3572 * @private The adapter to use to positon and resize elements
3574 this.adapter = new Ext.SplitBar.BasicLayoutAdapter();
3575 this.adapter.init(this);
3577 if(this.orientation == Ext.SplitBar.HORIZONTAL){
3579 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Ext.SplitBar.LEFT : Ext.SplitBar.RIGHT);
3580 this.el.addClass("x-splitbar-h");
3583 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Ext.SplitBar.TOP : Ext.SplitBar.BOTTOM);
3584 this.el.addClass("x-splitbar-v");
3590 * Fires when the splitter is moved (alias for {@link #moved})
3591 * @param {Ext.SplitBar} this
3592 * @param {Number} newSize the new width or height
3597 * Fires when the splitter is moved
3598 * @param {Ext.SplitBar} this
3599 * @param {Number} newSize the new width or height
3603 * @event beforeresize
3604 * Fires before the splitter is dragged
3605 * @param {Ext.SplitBar} this
3612 Ext.SplitBar.superclass.constructor.call(this);
3615 Ext.extend(Ext.SplitBar, Ext.util.Observable, {
3616 onStartProxyDrag : function(x, y){
3617 this.fireEvent("beforeresize", this);
3618 this.overlay = Ext.DomHelper.append(document.body, {cls: "x-drag-overlay", html: " "}, true);
3619 this.overlay.unselectable();
3620 this.overlay.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
3621 this.overlay.show();
3622 Ext.get(this.proxy).setDisplayed("block");
3623 var size = this.adapter.getElementSize(this);
3624 this.activeMinSize = this.getMinimumSize();
3625 this.activeMaxSize = this.getMaximumSize();
3626 var c1 = size - this.activeMinSize;
3627 var c2 = Math.max(this.activeMaxSize - size, 0);
3628 if(this.orientation == Ext.SplitBar.HORIZONTAL){
3629 this.dd.resetConstraints();
3630 this.dd.setXConstraint(
3631 this.placement == Ext.SplitBar.LEFT ? c1 : c2,
3632 this.placement == Ext.SplitBar.LEFT ? c2 : c1,
3635 this.dd.setYConstraint(0, 0);
3637 this.dd.resetConstraints();
3638 this.dd.setXConstraint(0, 0);
3639 this.dd.setYConstraint(
3640 this.placement == Ext.SplitBar.TOP ? c1 : c2,
3641 this.placement == Ext.SplitBar.TOP ? c2 : c1,
3645 this.dragSpecs.startSize = size;
3646 this.dragSpecs.startPoint = [x, y];
3647 Ext.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
3651 * @private Called after the drag operation by the DDProxy
3653 onEndProxyDrag : function(e){
3654 Ext.get(this.proxy).setDisplayed(false);
3655 var endPoint = Ext.lib.Event.getXY(e);
3657 Ext.destroy(this.overlay);
3658 delete this.overlay;
3661 if(this.orientation == Ext.SplitBar.HORIZONTAL){
3662 newSize = this.dragSpecs.startSize +
3663 (this.placement == Ext.SplitBar.LEFT ?
3664 endPoint[0] - this.dragSpecs.startPoint[0] :
3665 this.dragSpecs.startPoint[0] - endPoint[0]
3668 newSize = this.dragSpecs.startSize +
3669 (this.placement == Ext.SplitBar.TOP ?
3670 endPoint[1] - this.dragSpecs.startPoint[1] :
3671 this.dragSpecs.startPoint[1] - endPoint[1]
3674 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
3675 if(newSize != this.dragSpecs.startSize){
3676 if(this.fireEvent('beforeapply', this, newSize) !== false){
3677 this.adapter.setElementSize(this, newSize);
3678 this.fireEvent("moved", this, newSize);
3679 this.fireEvent("resize", this, newSize);
3685 * Get the adapter this SplitBar uses
3686 * @return The adapter object
3688 getAdapter : function(){
3689 return this.adapter;
3693 * Set the adapter this SplitBar uses
3694 * @param {Object} adapter A SplitBar adapter object
3696 setAdapter : function(adapter){
3697 this.adapter = adapter;
3698 this.adapter.init(this);
3702 * Gets the minimum size for the resizing element
3703 * @return {Number} The minimum size
3705 getMinimumSize : function(){
3706 return this.minSize;
3710 * Sets the minimum size for the resizing element
3711 * @param {Number} minSize The minimum size
3713 setMinimumSize : function(minSize){
3714 this.minSize = minSize;
3718 * Gets the maximum size for the resizing element
3719 * @return {Number} The maximum size
3721 getMaximumSize : function(){
3722 return this.maxSize;
3726 * Sets the maximum size for the resizing element
3727 * @param {Number} maxSize The maximum size
3729 setMaximumSize : function(maxSize){
3730 this.maxSize = maxSize;
3734 * Sets the initialize size for the resizing element
3735 * @param {Number} size The initial size
3737 setCurrentSize : function(size){
3738 var oldAnimate = this.animate;
3739 this.animate = false;
3740 this.adapter.setElementSize(this, size);
3741 this.animate = oldAnimate;
3745 * Destroy this splitbar.
3746 * @param {Boolean} removeEl True to remove the element
3748 destroy : function(removeEl){
3749 Ext.destroy(this.shim, Ext.get(this.proxy));
3754 this.purgeListeners();
3759 * @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.
3761 Ext.SplitBar.createProxy = function(dir){
3762 var proxy = new Ext.Element(document.createElement("div"));
3763 document.body.appendChild(proxy.dom);
3764 proxy.unselectable();
3765 var cls = 'x-splitbar-proxy';
3766 proxy.addClass(cls + ' ' + (dir == Ext.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
3771 * @class Ext.SplitBar.BasicLayoutAdapter
3772 * Default Adapter. It assumes the splitter and resizing element are not positioned
3773 * elements and only gets/sets the width of the element. Generally used for table based layouts.
3775 Ext.SplitBar.BasicLayoutAdapter = function(){
3778 Ext.SplitBar.BasicLayoutAdapter.prototype = {
3779 // do nothing for now
3784 * Called before drag operations to get the current size of the resizing element.
3785 * @param {Ext.SplitBar} s The SplitBar using this adapter
3787 getElementSize : function(s){
3788 if(s.orientation == Ext.SplitBar.HORIZONTAL){
3789 return s.resizingEl.getWidth();
3791 return s.resizingEl.getHeight();
3796 * Called after drag operations to set the size of the resizing element.
3797 * @param {Ext.SplitBar} s The SplitBar using this adapter
3798 * @param {Number} newSize The new size to set
3799 * @param {Function} onComplete A function to be invoked when resizing is complete
3801 setElementSize : function(s, newSize, onComplete){
3802 if(s.orientation == Ext.SplitBar.HORIZONTAL){
3804 s.resizingEl.setWidth(newSize);
3806 onComplete(s, newSize);
3809 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
3814 s.resizingEl.setHeight(newSize);
3816 onComplete(s, newSize);
3819 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
3826 *@class Ext.SplitBar.AbsoluteLayoutAdapter
3827 * @extends Ext.SplitBar.BasicLayoutAdapter
3828 * Adapter that moves the splitter element to align with the resized sizing element.
3829 * Used with an absolute positioned SplitBar.
3830 * @param {Mixed} container The container that wraps around the absolute positioned content. If it's
3831 * document.body, make sure you assign an id to the body element.
3833 Ext.SplitBar.AbsoluteLayoutAdapter = function(container){
3834 this.basic = new Ext.SplitBar.BasicLayoutAdapter();
3835 this.container = Ext.get(container);
3838 Ext.SplitBar.AbsoluteLayoutAdapter.prototype = {
3843 getElementSize : function(s){
3844 return this.basic.getElementSize(s);
3847 setElementSize : function(s, newSize, onComplete){
3848 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
3851 moveSplitter : function(s){
3852 var yes = Ext.SplitBar;
3853 switch(s.placement){
3855 s.el.setX(s.resizingEl.getRight());
3858 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
3861 s.el.setY(s.resizingEl.getBottom());
3864 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
3871 * Orientation constant - Create a vertical SplitBar
3875 Ext.SplitBar.VERTICAL = 1;
3878 * Orientation constant - Create a horizontal SplitBar
3882 Ext.SplitBar.HORIZONTAL = 2;
3885 * Placement constant - The resizing element is to the left of the splitter element
3889 Ext.SplitBar.LEFT = 1;
3892 * Placement constant - The resizing element is to the right of the splitter element
3896 Ext.SplitBar.RIGHT = 2;
3899 * Placement constant - The resizing element is positioned above the splitter element
3903 Ext.SplitBar.TOP = 3;
3906 * Placement constant - The resizing element is positioned under splitter element
3910 Ext.SplitBar.BOTTOM = 4;
3912 * @class Ext.Container
3913 * @extends Ext.BoxComponent
3914 * <p>Base class for any {@link Ext.BoxComponent} that may contain other Components. Containers handle the
3915 * basic behavior of containing items, namely adding, inserting and removing items.</p>
3917 * <p>The most commonly used Container classes are {@link Ext.Panel}, {@link Ext.Window} and {@link Ext.TabPanel}.
3918 * If you do not need the capabilities offered by the aforementioned classes you can create a lightweight
3919 * Container to be encapsulated by an HTML element to your specifications by using the
3920 * <code><b>{@link Ext.Component#autoEl autoEl}</b></code> config option. This is a useful technique when creating
3921 * embedded {@link Ext.layout.ColumnLayout column} layouts inside {@link Ext.form.FormPanel FormPanels}
3924 * <p>The code below illustrates both how to explicitly create a Container, and how to implicitly
3925 * create one using the <b><code>'container'</code></b> xtype:<pre><code>
3926 // explicitly create a Container
3927 var embeddedColumns = new Ext.Container({
3928 autoEl: 'div', // This is the default
3931 // implicitly create Container by specifying xtype
3933 autoEl: 'div', // This is the default.
3940 // The two items below will be Ext.Containers, each encapsulated by a <DIV> element.
3945 fieldLabel: 'Start date'
3951 fieldLabel: 'End date'
3954 });</code></pre></p>
3956 * <p><u><b>Layout</b></u></p>
3957 * <p>Container classes delegate the rendering of child Components to a layout
3958 * manager class which must be configured into the Container using the
3959 * <code><b>{@link #layout}</b></code> configuration property.</p>
3960 * <p>When either specifying child <code>{@link #items}</code> of a Container,
3961 * or dynamically {@link #add adding} Components to a Container, remember to
3962 * consider how you wish the Container to arrange those child elements, and
3963 * whether those child elements need to be sized using one of Ext's built-in
3964 * <b><code>{@link #layout}</code></b> schemes. By default, Containers use the
3965 * {@link Ext.layout.ContainerLayout ContainerLayout} scheme which only
3966 * renders child components, appending them one after the other inside the
3967 * Container, and <b>does not apply any sizing</b> at all.</p>
3968 * <p>A common mistake is when a developer neglects to specify a
3969 * <b><code>{@link #layout}</code></b> (e.g. widgets like GridPanels or
3970 * TreePanels are added to Containers for which no <code><b>{@link #layout}</b></code>
3971 * has been specified). If a Container is left to use the default
3972 * {@link Ext.layout.ContainerLayout ContainerLayout} scheme, none of its
3973 * child components will be resized, or changed in any way when the Container
3975 * <p>Certain layout managers allow dynamic addition of child components.
3976 * Those that do include {@link Ext.layout.CardLayout},
3977 * {@link Ext.layout.AnchorLayout}, {@link Ext.layout.FormLayout}, and
3978 * {@link Ext.layout.TableLayout}. For example:<pre><code>
3979 // Create the GridPanel.
3980 var myNewGrid = new Ext.grid.GridPanel({
3982 columns: myColumnModel,
3983 title: 'Results', // the title becomes the title of the tab
3986 myTabPanel.add(myNewGrid); // {@link Ext.TabPanel} implicitly uses {@link Ext.layout.CardLayout CardLayout}
3987 myTabPanel.{@link Ext.TabPanel#setActiveTab setActiveTab}(myNewGrid);
3989 * <p>The example above adds a newly created GridPanel to a TabPanel. Note that
3990 * a TabPanel uses {@link Ext.layout.CardLayout} as its layout manager which
3991 * means all its child items are sized to {@link Ext.layout.FitLayout fit}
3992 * exactly into its client area.
3993 * <p><b><u>Overnesting is a common problem</u></b>.
3994 * An example of overnesting occurs when a GridPanel is added to a TabPanel
3995 * by wrapping the GridPanel <i>inside</i> a wrapping Panel (that has no
3996 * <code><b>{@link #layout}</b></code> specified) and then add that wrapping Panel
3997 * to the TabPanel. The point to realize is that a GridPanel <b>is</b> a
3998 * Component which can be added directly to a Container. If the wrapping Panel
3999 * has no <code><b>{@link #layout}</b></code> configuration, then the overnested
4000 * GridPanel will not be sized as expected.<p>
4002 * <p><u><b>Adding via remote configuration</b></u></p>
4004 * <p>A server side script can be used to add Components which are generated dynamically on the server.
4005 * An example of adding a GridPanel to a TabPanel where the GridPanel is generated by the server
4006 * based on certain parameters:
4008 // execute an Ajax request to invoke server side script:
4010 url: 'gen-invoice-grid.php',
4011 // send additional parameters to instruct server script
4013 startDate: Ext.getCmp('start-date').getValue(),
4014 endDate: Ext.getCmp('end-date').getValue()
4016 // process the response object to add it to the TabPanel:
4017 success: function(xhr) {
4018 var newComponent = eval(xhr.responseText); // see discussion below
4019 myTabPanel.add(newComponent); // add the component to the TabPanel
4020 myTabPanel.setActiveTab(newComponent);
4022 failure: function() {
4023 Ext.Msg.alert("Grid create failed", "Server communication failure");
4027 * <p>The server script needs to return an executable Javascript statement which, when processed
4028 * using <code>eval()</code>, will return either a config object with an {@link Ext.Component#xtype xtype},
4029 * or an instantiated Component. The server might return this for example:</p><pre><code>
4031 function formatDate(value){
4032 return value ? value.dateFormat('M d, Y') : '';
4035 var store = new Ext.data.Store({
4036 url: 'get-invoice-data.php',
4038 startDate: '01/01/2008',
4039 endDate: '01/31/2008'
4041 reader: new Ext.data.JsonReader({
4042 record: 'transaction',
4044 totalRecords: 'total'
4048 {name: 'date', type: 'date', dateFormat: 'm/d/Y'},
4049 {name: 'value', type: 'float'}
4053 var grid = new Ext.grid.GridPanel({
4054 title: 'Invoice Report',
4055 bbar: new Ext.PagingToolbar(store),
4058 {header: "Customer", width: 250, dataIndex: 'customer', sortable: true},
4059 {header: "Invoice Number", width: 120, dataIndex: 'invNo', sortable: true},
4060 {header: "Invoice Date", width: 100, dataIndex: 'date', renderer: formatDate, sortable: true},
4061 {header: "Value", width: 120, dataIndex: 'value', renderer: 'usMoney', sortable: true}
4065 return grid; // return instantiated component
4068 * <p>When the above code fragment is passed through the <code>eval</code> function in the success handler
4069 * of the Ajax request, the code is executed by the Javascript processor, and the anonymous function
4070 * runs, and returns the instantiated grid component.</p>
4071 * <p>Note: since the code above is <i>generated</i> by a server script, the <code>baseParams</code> for
4072 * the Store, the metadata to allow generation of the Record layout, and the ColumnModel
4073 * can all be generated into the code since these are all known on the server.</p>
4077 Ext.Container = Ext.extend(Ext.BoxComponent, {
4079 * @cfg {Boolean} monitorResize
4080 * True to automatically monitor window resize events to handle anything that is sensitive to the current size
4081 * of the viewport. This value is typically managed by the chosen <code>{@link #layout}</code> and should not need
4082 * to be set manually.
4085 * @cfg {String/Object} layout
4086 * <p><b>*Important</b>: In order for child items to be correctly sized and
4087 * positioned, typically a layout manager <b>must</b> be specified through
4088 * the <code>layout</code> configuration option.</p>
4089 * <br><p>The sizing and positioning of child {@link items} is the responsibility of
4090 * the Container's layout manager which creates and manages the type of layout
4091 * you have in mind. For example:</p><pre><code>
4093 width:300, height: 300,
4094 layout: 'fit', // explicitly set layout manager: override the default (layout:'auto')
4096 title: 'Panel inside a Window'
4100 * <p>If the {@link #layout} configuration is not explicitly specified for
4101 * a general purpose container (e.g. Container or Panel) the
4102 * {@link Ext.layout.ContainerLayout default layout manager} will be used
4103 * which does nothing but render child components sequentially into the
4104 * Container (no sizing or positioning will be performed in this situation).
4105 * Some container classes implicitly specify a default layout
4106 * (e.g. FormPanel specifies <code>layout:'form'</code>). Other specific
4107 * purpose classes internally specify/manage their internal layout (e.g.
4108 * GridPanel, TabPanel, TreePanel, Toolbar, Menu, etc.).</p>
4109 * <br><p><b><code>layout</code></b> may be specified as either as an Object or
4110 * as a String:</p><div><ul class="mdetail-params">
4112 * <li><u>Specify as an Object</u></li>
4113 * <div><ul class="mdetail-params">
4114 * <li>Example usage:</li>
4123 * <li><code><b>type</b></code></li>
4124 * <br/><p>The layout type to be used for this container. If not specified,
4125 * a default {@link Ext.layout.ContainerLayout} will be created and used.</p>
4126 * <br/><p>Valid layout <code>type</code> values are:</p>
4127 * <div class="sub-desc"><ul class="mdetail-params">
4128 * <li><code><b>{@link Ext.layout.AbsoluteLayout absolute}</b></code></li>
4129 * <li><code><b>{@link Ext.layout.AccordionLayout accordion}</b></code></li>
4130 * <li><code><b>{@link Ext.layout.AnchorLayout anchor}</b></code></li>
4131 * <li><code><b>{@link Ext.layout.ContainerLayout auto}</b></code> <b>Default</b></li>
4132 * <li><code><b>{@link Ext.layout.BorderLayout border}</b></code></li>
4133 * <li><code><b>{@link Ext.layout.CardLayout card}</b></code></li>
4134 * <li><code><b>{@link Ext.layout.ColumnLayout column}</b></code></li>
4135 * <li><code><b>{@link Ext.layout.FitLayout fit}</b></code></li>
4136 * <li><code><b>{@link Ext.layout.FormLayout form}</b></code></li>
4137 * <li><code><b>{@link Ext.layout.HBoxLayout hbox}</b></code></li>
4138 * <li><code><b>{@link Ext.layout.MenuLayout menu}</b></code></li>
4139 * <li><code><b>{@link Ext.layout.TableLayout table}</b></code></li>
4140 * <li><code><b>{@link Ext.layout.ToolbarLayout toolbar}</b></code></li>
4141 * <li><code><b>{@link Ext.layout.VBoxLayout vbox}</b></code></li>
4144 * <li>Layout specific configuration properties</li>
4145 * <br/><p>Additional layout specific configuration properties may also be
4146 * specified. For complete details regarding the valid config options for
4147 * each layout type, see the layout class corresponding to the <code>type</code>
4152 * <li><u>Specify as a String</u></li>
4153 * <div><ul class="mdetail-params">
4154 * <li>Example usage:</li>
4162 * <li><code><b>layout</b></code></li>
4163 * <br/><p>The layout <code>type</code> to be used for this container (see list
4164 * of valid layout type values above).</p><br/>
4165 * <li><code><b>{@link #layoutConfig}</b></code></li>
4166 * <br/><p>Additional layout specific configuration properties. For complete
4167 * details regarding the valid config options for each layout type, see the
4168 * layout class corresponding to the <code>layout</code> specified.</p>
4169 * </ul></div></ul></div>
4172 * @cfg {Object} layoutConfig
4173 * This is a config object containing properties specific to the chosen
4174 * <b><code>{@link #layout}</code></b> if <b><code>{@link #layout}</code></b>
4175 * has been specified as a <i>string</i>.</p>
4178 * @cfg {Boolean/Number} bufferResize
4179 * When set to true (50 milliseconds) or a number of milliseconds, the layout assigned for this container will buffer
4180 * the frequency it calculates and does a re-layout of components. This is useful for heavy containers or containers
4181 * with a large quantity of sub-components for which frequent layout calls would be expensive. Defaults to <code>50</code>.
4186 * @cfg {String/Number} activeItem
4187 * A string component id or the numeric index of the component that should be initially activated within the
4188 * container's layout on render. For example, activeItem: 'item-1' or activeItem: 0 (index 0 = the first
4189 * item in the container's collection). activeItem only applies to layout styles that can display
4190 * items one at a time (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout} and
4191 * {@link Ext.layout.FitLayout}). Related to {@link Ext.layout.ContainerLayout#activeItem}.
4194 * @cfg {Object/Array} items
4195 * <pre><b>** IMPORTANT</b>: be sure to <b>{@link #layout specify a <code>layout</code>} if needed ! **</b></pre>
4196 * <p>A single item, or an array of child Components to be added to this container,
4199 // specifying a single item
4201 layout: 'fit', // specify a layout!
4203 // specifying multiple items
4204 items: [{...}, {...}],
4205 layout: 'anchor', // specify a layout!
4207 * <p>Each item may be:</p>
4208 * <div><ul class="mdetail-params">
4209 * <li>any type of object based on {@link Ext.Component}</li>
4210 * <li>a fully instanciated object or</li>
4211 * <li>an object literal that:</li>
4212 * <div><ul class="mdetail-params">
4213 * <li>has a specified <code>{@link Ext.Component#xtype xtype}</code></li>
4214 * <li>the {@link Ext.Component#xtype} specified is associated with the Component
4215 * desired and should be chosen from one of the available xtypes as listed
4216 * in {@link Ext.Component}.</li>
4217 * <li>If an <code>{@link Ext.Component#xtype xtype}</code> is not explicitly
4218 * specified, the {@link #defaultType} for that Container is used.</li>
4219 * <li>will be "lazily instanciated", avoiding the overhead of constructing a fully
4220 * instanciated Component object</li>
4221 * </ul></div></ul></div>
4222 * <p><b>Notes</b>:</p>
4223 * <div><ul class="mdetail-params">
4224 * <li>Ext uses lazy rendering. Child Components will only be rendered
4225 * should it become necessary. Items are automatically laid out when they are first
4226 * shown (no sizing is done while hidden), or in response to a {@link #doLayout} call.</li>
4227 * <li>Do not specify <code>{@link Ext.Panel#contentEl contentEl}</code>/
4228 * <code>{@link Ext.Panel#html html}</code> with <code>items</code>.</li>
4232 * @cfg {Object|Function} defaults
4233 * <p>This option is a means of applying default settings to all added items whether added through the {@link #items}
4234 * config or via the {@link #add} or {@link #insert} methods.</p>
4235 * <p>If an added item is a config object, and <b>not</b> an instantiated Component, then the default properties are
4236 * unconditionally applied. If the added item <b>is</b> an instantiated Component, then the default properties are
4237 * applied conditionally so as not to override existing properties in the item.</p>
4238 * <p>If the defaults option is specified as a function, then the function will be called using this Container as the
4239 * scope (<code>this</code> reference) and passing the added item as the first parameter. Any resulting object
4240 * from that call is then applied to the item as default properties.</p>
4241 * <p>For example, to automatically apply padding to the body of each of a set of
4242 * contained {@link Ext.Panel} items, you could pass: <code>defaults: {bodyStyle:'padding:15px'}</code>.</p>
4243 * <p>Usage:</p><pre><code>
4244 defaults: { // defaults are applied to items, not the container
4249 xtype: 'panel', // defaults <b>do not</b> have precedence over
4250 id: 'panel1', // options in config objects, so the defaults
4251 autoScroll: false // will not be applied here, panel1 will be autoScroll:false
4253 new Ext.Panel({ // defaults <b>do</b> have precedence over options
4254 id: 'panel2', // options in components, so the defaults
4255 autoScroll: false // will be applied here, panel2 will be autoScroll:true.
4262 /** @cfg {Boolean} autoDestroy
4263 * If true the container will automatically destroy any contained component that is removed from it, else
4264 * destruction must be handled manually (defaults to true).
4268 /** @cfg {Boolean} forceLayout
4269 * If true the container will force a layout initially even if hidden or collapsed. This option
4270 * is useful for forcing forms to render in collapsed or hidden containers. (defaults to false).
4274 /** @cfg {Boolean} hideBorders
4275 * True to hide the borders of each contained component, false to defer to the component's existing
4276 * border settings (defaults to false).
4278 /** @cfg {String} defaultType
4279 * <p>The default {@link Ext.Component xtype} of child Components to create in this Container when
4280 * a child item is specified as a raw configuration object, rather than as an instantiated Component.</p>
4281 * <p>Defaults to <code>'panel'</code>, except {@link Ext.menu.Menu} which defaults to <code>'menuitem'</code>,
4282 * and {@link Ext.Toolbar} and {@link Ext.ButtonGroup} which default to <code>'button'</code>.</p>
4284 defaultType : 'panel',
4286 /** @cfg {String} resizeEvent
4287 * The event to listen to for resizing in layouts. Defaults to <code>'resize'</code>.
4289 resizeEvent: 'resize',
4292 * @cfg {Array} bubbleEvents
4293 * <p>An array of events that, when fired, should be bubbled to any parent container.
4294 * See {@link Ext.util.Observable#enableBubble}.
4295 * Defaults to <code>['add', 'remove']</code>.
4297 bubbleEvents: ['add', 'remove'],
4300 initComponent : function(){
4301 Ext.Container.superclass.initComponent.call(this);
4305 * @event afterlayout
4306 * Fires when the components in this container are arranged by the associated layout manager.
4307 * @param {Ext.Container} this
4308 * @param {ContainerLayout} layout The ContainerLayout implementation for this container
4313 * Fires before any {@link Ext.Component} is added or inserted into the container.
4314 * A handler can return false to cancel the add.
4315 * @param {Ext.Container} this
4316 * @param {Ext.Component} component The component being added
4317 * @param {Number} index The index at which the component will be added to the container's items collection
4321 * @event beforeremove
4322 * Fires before any {@link Ext.Component} is removed from the container. A handler can return
4323 * false to cancel the remove.
4324 * @param {Ext.Container} this
4325 * @param {Ext.Component} component The component being removed
4331 * Fires after any {@link Ext.Component} is added or inserted into the container.
4332 * @param {Ext.Container} this
4333 * @param {Ext.Component} component The component that was added
4334 * @param {Number} index The index at which the component was added to the container's items collection
4340 * Fires after any {@link Ext.Component} is removed from the container.
4341 * @param {Ext.Container} this
4342 * @param {Ext.Component} component The component that was removed
4348 * The collection of components in this container as a {@link Ext.util.MixedCollection}
4349 * @type MixedCollection
4352 var items = this.items;
4360 initItems : function(){
4362 this.items = new Ext.util.MixedCollection(false, this.getComponentId);
4363 this.getLayout(); // initialize the layout
4368 setLayout : function(layout){
4369 if(this.layout && this.layout != layout){
4370 this.layout.setContainer(null);
4372 this.layout = layout;
4374 layout.setContainer(this);
4377 afterRender: function(){
4378 // Render this Container, this should be done before setLayout is called which
4379 // will hook onResize
4380 Ext.Container.superclass.afterRender.call(this);
4382 this.layout = 'auto';
4384 if(Ext.isObject(this.layout) && !this.layout.layout){
4385 this.layoutConfig = this.layout;
4386 this.layout = this.layoutConfig.type;
4388 if(Ext.isString(this.layout)){
4389 this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig);
4391 this.setLayout(this.layout);
4393 // If a CardLayout, the active item set
4394 if(this.activeItem !== undefined && this.layout.setActiveItem){
4395 var item = this.activeItem;
4396 delete this.activeItem;
4397 this.layout.setActiveItem(item);
4400 // If we have no ownerCt, render and size all children
4402 this.doLayout(false, true);
4405 // This is a manually configured flag set by users in conjunction with renderTo.
4406 // Not to be confused with the flag by the same name used in Layouts.
4407 if(this.monitorResize === true){
4408 Ext.EventManager.onWindowResize(this.doLayout, this, [false]);
4413 * <p>Returns the Element to be used to contain the child Components of this Container.</p>
4414 * <p>An implementation is provided which returns the Container's {@link #getEl Element}, but
4415 * if there is a more complex structure to a Container, this may be overridden to return
4416 * the element into which the {@link #layout layout} renders child Components.</p>
4417 * @return {Ext.Element} The Element to render child Components into.
4419 getLayoutTarget : function(){
4423 // private - used as the key lookup function for the items collection
4424 getComponentId : function(comp){
4425 return comp.getItemId();
4429 * <p>Adds {@link Ext.Component Component}(s) to this Container.</p>
4430 * <br><p><b>Description</b></u> :
4431 * <div><ul class="mdetail-params">
4432 * <li>Fires the {@link #beforeadd} event before adding</li>
4433 * <li>The Container's {@link #defaults default config values} will be applied
4434 * accordingly (see <code>{@link #defaults}</code> for details).</li>
4435 * <li>Fires the {@link #add} event after the component has been added.</li>
4437 * <br><p><b>Notes</b></u> :
4438 * <div><ul class="mdetail-params">
4439 * <li>If the Container is <i>already rendered</i> when <code>add</code>
4440 * is called, you may need to call {@link #doLayout} to refresh the view which causes
4441 * any unrendered child Components to be rendered. This is required so that you can
4442 * <code>add</code> multiple child components if needed while only refreshing the layout
4443 * once. For example:<pre><code>
4444 var tb = new {@link Ext.Toolbar}();
4445 tb.render(document.body); // toolbar is rendered
4446 tb.add({text:'Button 1'}); // add multiple items ({@link #defaultType} for {@link Ext.Toolbar Toolbar} is 'button')
4447 tb.add({text:'Button 2'});
4448 tb.{@link #doLayout}(); // refresh the layout
4449 * </code></pre></li>
4450 * <li><i>Warning:</i> Containers directly managed by the BorderLayout layout manager
4451 * may not be removed or added. See the Notes for {@link Ext.layout.BorderLayout BorderLayout}
4452 * for more details.</li>
4454 * @param {...Object/Array} component
4455 * <p>Either one or more Components to add or an Array of Components to add. See
4456 * <code>{@link #items}</code> for additional information.</p>
4457 * @return {Ext.Component/Array} The Components that were added.
4459 add : function(comp){
4461 var args = arguments.length > 1;
4462 if(args || Ext.isArray(comp)){
4464 Ext.each(args ? arguments : comp, function(c){
4465 result.push(this.add(c));
4469 var c = this.lookupComponent(this.applyDefaults(comp));
4470 var index = this.items.length;
4471 if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){
4474 c.onAdded(this, index);
4476 this.fireEvent('add', this, c, index);
4481 onAdd : function(c){
4482 // Empty template method
4486 onAdded : function(container, pos) {
4487 //overridden here so we can cascade down, not worth creating a template method.
4488 this.ownerCt = container;
4490 //initialize references for child items
4491 this.cascade(function(c){
4494 this.fireEvent('added', this, container, pos);
4498 * Inserts a Component into this Container at a specified index. Fires the
4499 * {@link #beforeadd} event before inserting, then fires the {@link #add} event after the
4500 * Component has been inserted.
4501 * @param {Number} index The index at which the Component will be inserted
4502 * into the Container's items collection
4503 * @param {Ext.Component} component The child Component to insert.<br><br>
4504 * Ext uses lazy rendering, and will only render the inserted Component should
4505 * it become necessary.<br><br>
4506 * A Component config object may be passed in order to avoid the overhead of
4507 * constructing a real Component object if lazy rendering might mean that the
4508 * inserted Component will not be rendered immediately. To take advantage of
4509 * this 'lazy instantiation', set the {@link Ext.Component#xtype} config
4510 * property to the registered type of the Component wanted.<br><br>
4511 * For a list of all available xtypes, see {@link Ext.Component}.
4512 * @return {Ext.Component} component The Component (or config object) that was
4513 * inserted with the Container's default config values applied.
4515 insert : function(index, comp) {
4516 var args = arguments,
4517 length = args.length,
4524 for (i = length - 1; i >= 1; --i) {
4525 result.push(this.insert(index, args[i]));
4530 c = this.lookupComponent(this.applyDefaults(comp));
4531 index = Math.min(index, this.items.length);
4533 if (this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false) {
4534 if (c.ownerCt == this) {
4535 this.items.remove(c);
4537 this.items.insert(index, c);
4538 c.onAdded(this, index);
4540 this.fireEvent('add', this, c, index);
4547 applyDefaults : function(c){
4548 var d = this.defaults;
4550 if(Ext.isFunction(d)){
4551 d = d.call(this, c);
4553 if(Ext.isString(c)){
4554 c = Ext.ComponentMgr.get(c);
4556 }else if(!c.events){
4566 onBeforeAdd : function(item){
4568 item.ownerCt.remove(item, false);
4570 if(this.hideBorders === true){
4571 item.border = (item.border === true);
4576 * Removes a component from this container. Fires the {@link #beforeremove} event before removing, then fires
4577 * the {@link #remove} event after the component has been removed.
4578 * @param {Component/String} component The component reference or id to remove.
4579 * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
4580 * Defaults to the value of this Container's {@link #autoDestroy} config.
4581 * @return {Ext.Component} component The Component that was removed.
4583 remove : function(comp, autoDestroy){
4585 var c = this.getComponent(comp);
4586 if(c && this.fireEvent('beforeremove', this, c) !== false){
4587 this.doRemove(c, autoDestroy);
4588 this.fireEvent('remove', this, c);
4593 onRemove: function(c){
4594 // Empty template method
4598 doRemove: function(c, autoDestroy){
4599 var l = this.layout,
4600 hasLayout = l && this.rendered;
4605 this.items.remove(c);
4608 if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){
4617 * Removes all components from this container.
4618 * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
4619 * Defaults to the value of this Container's {@link #autoDestroy} config.
4620 * @return {Array} Array of the destroyed components
4622 removeAll: function(autoDestroy){
4624 var item, rem = [], items = [];
4625 this.items.each(function(i){
4628 for (var i = 0, len = rem.length; i < len; ++i){
4630 this.remove(item, autoDestroy);
4631 if(item.ownerCt !== this){
4639 * Examines this container's <code>{@link #items}</code> <b>property</b>
4640 * and gets a direct child component of this container.
4641 * @param {String/Number} comp This parameter may be any of the following:
4642 * <div><ul class="mdetail-params">
4643 * <li>a <b><code>String</code></b> : representing the <code>{@link Ext.Component#itemId itemId}</code>
4644 * or <code>{@link Ext.Component#id id}</code> of the child component </li>
4645 * <li>a <b><code>Number</code></b> : representing the position of the child component
4646 * within the <code>{@link #items}</code> <b>property</b></li>
4648 * <p>For additional information see {@link Ext.util.MixedCollection#get}.
4649 * @return Ext.Component The component (if found).
4651 getComponent : function(comp){
4652 if(Ext.isObject(comp)){
4653 comp = comp.getItemId();
4655 return this.items.get(comp);
4659 lookupComponent : function(comp){
4660 if(Ext.isString(comp)){
4661 return Ext.ComponentMgr.get(comp);
4662 }else if(!comp.events){
4663 return this.createComponent(comp);
4669 createComponent : function(config, defaultType){
4670 if (config.render) {
4673 // add in ownerCt at creation time but then immediately
4674 // remove so that onBeforeAdd can handle it
4675 var c = Ext.create(Ext.apply({
4677 }, config), defaultType || this.defaultType);
4678 delete c.initialConfig.ownerCt;
4685 * We can only lay out if there is a view area in which to layout.
4686 * display:none on the layout target, *or any of its parent elements* will mean it has no view area.
4688 canLayout : function() {
4689 var el = this.getVisibilityEl();
4690 return el && el.dom && !el.isStyle("display", "none");
4694 * Force this container's layout to be recalculated. A call to this function is required after adding a new component
4695 * to an already rendered container, or possibly after changing sizing/position properties of child components.
4696 * @param {Boolean} shallow (optional) True to only calc the layout of this component, and let child components auto
4697 * calc layouts as required (defaults to false, which calls doLayout recursively for each subcontainer)
4698 * @param {Boolean} force (optional) True to force a layout to occur, even if the item is hidden.
4699 * @return {Ext.Container} this
4702 doLayout : function(shallow, force){
4703 var rendered = this.rendered,
4704 forceLayout = force || this.forceLayout;
4706 if(this.collapsed || !this.canLayout()){
4707 this.deferLayout = this.deferLayout || !shallow;
4711 shallow = shallow && !this.deferLayout;
4713 delete this.deferLayout;
4715 if(rendered && this.layout){
4716 this.layout.layout();
4718 if(shallow !== true && this.items){
4719 var cs = this.items.items;
4720 for(var i = 0, len = cs.length; i < len; i++){
4723 c.doLayout(false, forceLayout);
4728 this.onLayout(shallow, forceLayout);
4730 // Initial layout completed
4731 this.hasLayout = true;
4732 delete this.forceLayout;
4735 onLayout : Ext.emptyFn,
4738 shouldBufferLayout: function(){
4740 * Returns true if the container should buffer a layout.
4741 * This is true only if the container has previously been laid out
4742 * and has a parent container that is pending a layout.
4744 var hl = this.hasLayout;
4746 // Only ever buffer if we've laid out the first time and we have one pending.
4747 return hl ? !this.hasLayoutPending() : false;
4749 // Never buffer initial layout
4754 hasLayoutPending: function(){
4755 // Traverse hierarchy to see if any parent container has a pending layout.
4756 var pending = false;
4757 this.ownerCt.bubble(function(c){
4758 if(c.layoutPending){
4766 onShow : function(){
4767 // removes css classes that were added to hide
4768 Ext.Container.superclass.onShow.call(this);
4769 // If we were sized during the time we were hidden, layout.
4770 if(Ext.isDefined(this.deferLayout)){
4771 delete this.deferLayout;
4772 this.doLayout(true);
4777 * Returns the layout currently in use by the container. If the container does not currently have a layout
4778 * set, a default {@link Ext.layout.ContainerLayout} will be created and set as the container's layout.
4779 * @return {ContainerLayout} layout The container's layout
4781 getLayout : function(){
4783 var layout = new Ext.layout.AutoLayout(this.layoutConfig);
4784 this.setLayout(layout);
4790 beforeDestroy : function(){
4793 while(c = this.items.first()){
4794 this.doRemove(c, true);
4797 if(this.monitorResize){
4798 Ext.EventManager.removeResizeListener(this.doLayout, this);
4800 Ext.destroy(this.layout);
4801 Ext.Container.superclass.beforeDestroy.call(this);
4805 * Cascades down the component/container heirarchy from this component (called first), calling the specified function with
4806 * each component. The scope (<i>this</i>) of
4807 * function call will be the scope provided or the current component. The arguments to the function
4808 * will be the args provided or the current component. If the function returns false at any point,
4809 * the cascade is stopped on that branch.
4810 * @param {Function} fn The function to call
4811 * @param {Object} scope (optional) The scope of the function (defaults to current component)
4812 * @param {Array} args (optional) The args to call the function with (defaults to passing the current component)
4813 * @return {Ext.Container} this
4815 cascade : function(fn, scope, args){
4816 if(fn.apply(scope || this, args || [this]) !== false){
4818 var cs = this.items.items;
4819 for(var i = 0, len = cs.length; i < len; i++){
4821 cs[i].cascade(fn, scope, args);
4823 fn.apply(scope || cs[i], args || [cs[i]]);
4832 * Find a component under this container at any level by id
4833 * @param {String} id
4834 * @deprecated Fairly useless method, since you can just use Ext.getCmp. Should be removed for 4.0
4835 * If you need to test if an id belongs to a container, you can use getCmp and findParent*.
4836 * @return Ext.Component
4838 findById : function(id){
4841 this.cascade(function(c){
4842 if(ct != c && c.id === id){
4851 * Find a component under this container at any level by xtype or class
4852 * @param {String/Class} xtype The xtype string for a component, or the class of the component directly
4853 * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
4854 * the default), or true to check whether this Component is directly of the specified xtype.
4855 * @return {Array} Array of Ext.Components
4857 findByType : function(xtype, shallow){
4858 return this.findBy(function(c){
4859 return c.isXType(xtype, shallow);
4864 * Find a component under this container at any level by property
4865 * @param {String} prop
4866 * @param {String} value
4867 * @return {Array} Array of Ext.Components
4869 find : function(prop, value){
4870 return this.findBy(function(c){
4871 return c[prop] === value;
4876 * Find a component under this container at any level by a custom function. If the passed function returns
4877 * true, the component will be included in the results. The passed function is called with the arguments (component, this container).
4878 * @param {Function} fn The function to call
4879 * @param {Object} scope (optional)
4880 * @return {Array} Array of Ext.Components
4882 findBy : function(fn, scope){
4883 var m = [], ct = this;
4884 this.cascade(function(c){
4885 if(ct != c && fn.call(scope || c, c, ct) === true){
4893 * Get a component contained by this container (alias for items.get(key))
4894 * @param {String/Number} key The index or id of the component
4895 * @deprecated Should be removed in 4.0, since getComponent does the same thing.
4896 * @return {Ext.Component} Ext.Component
4898 get : function(key){
4899 return this.getComponent(key);
4903 Ext.Container.LAYOUTS = {};
4904 Ext.reg('container', Ext.Container);
4906 * @class Ext.layout.ContainerLayout
4907 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
4908 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
4910 Ext.layout.ContainerLayout = Ext.extend(Object, {
4912 * @cfg {String} extraCls
4913 * <p>An optional extra CSS class that will be added to the container. This can be useful for adding
4914 * customized styles to the container or any of its children using standard CSS rules. See
4915 * {@link Ext.Component}.{@link Ext.Component#ctCls ctCls} also.</p>
4916 * <p><b>Note</b>: <tt>extraCls</tt> defaults to <tt>''</tt> except for the following classes
4917 * which assign a value by default:
4918 * <div class="mdetail-params"><ul>
4919 * <li>{@link Ext.layout.AbsoluteLayout Absolute Layout} : <tt>'x-abs-layout-item'</tt></li>
4920 * <li>{@link Ext.layout.Box Box Layout} : <tt>'x-box-item'</tt></li>
4921 * <li>{@link Ext.layout.ColumnLayout Column Layout} : <tt>'x-column'</tt></li>
4923 * To configure the above Classes with an extra CSS class append to the default. For example,
4924 * for ColumnLayout:<pre><code>
4925 * extraCls: 'x-column custom-class'
4930 * @cfg {Boolean} renderHidden
4931 * True to hide each contained item on render (defaults to false).
4935 * A reference to the {@link Ext.Component} that is active. For example, <pre><code>
4936 * if(myPanel.layout.activeItem.id == 'item-1') { ... }
4938 * <tt>activeItem</tt> only applies to layout styles that can display items one at a time
4939 * (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout}
4940 * and {@link Ext.layout.FitLayout}). Read-only. Related to {@link Ext.Container#activeItem}.
4941 * @type {Ext.Component}
4942 * @property activeItem
4946 monitorResize:false,
4950 constructor : function(config){
4951 this.id = Ext.id(null, 'ext-layout-');
4952 Ext.apply(this, config);
4957 /* Workaround for how IE measures autoWidth elements. It prefers bottom-up measurements
4958 whereas other browser prefer top-down. We will hide all target child elements before we measure and
4959 put them back to get an accurate measurement.
4961 IEMeasureHack : function(target, viewFlag) {
4962 var tChildren = target.dom.childNodes, tLen = tChildren.length, c, d = [], e, i, ret;
4963 for (i = 0 ; i < tLen ; i++) {
4967 d[i] = e.getStyle('display');
4968 e.setStyle({display: 'none'});
4971 ret = target ? target.getViewSize(viewFlag) : {};
4972 for (i = 0 ; i < tLen ; i++) {
4976 e.setStyle({display: d[i]});
4982 // Placeholder for the derived layouts
4983 getLayoutTargetSize : Ext.EmptyFn,
4986 layout : function(){
4987 var ct = this.container, target = ct.getLayoutTarget();
4988 if(!(this.hasLayout || Ext.isEmpty(this.targetCls))){
4989 target.addClass(this.targetCls);
4991 this.onLayout(ct, target);
4992 ct.fireEvent('afterlayout', ct, this);
4996 onLayout : function(ct, target){
4997 this.renderAll(ct, target);
5001 isValidParent : function(c, target){
5002 return target && c.getPositionEl().dom.parentNode == (target.dom || target);
5006 renderAll : function(ct, target){
5007 var items = ct.items.items, i, c, len = items.length;
5008 for(i = 0; i < len; i++) {
5010 if(c && (!c.rendered || !this.isValidParent(c, target))){
5011 this.renderItem(c, i, target);
5018 * Renders the given Component into the target Element. If the Component is already rendered,
5019 * it is moved to the provided target instead.
5020 * @param {Ext.Component} c The Component to render
5021 * @param {Number} position The position within the target to render the item to
5022 * @param {Ext.Element} target The target Element
5024 renderItem : function(c, position, target){
5027 c.render(target, position);
5028 this.configureItem(c);
5029 } else if (!this.isValidParent(c, target)) {
5030 if (Ext.isNumber(position)) {
5031 position = target.dom.childNodes[position];
5034 target.dom.insertBefore(c.getPositionEl().dom, position || null);
5035 c.container = target;
5036 this.configureItem(c);
5042 // Get all rendered items to lay out.
5043 getRenderedItems: function(ct){
5044 var t = ct.getLayoutTarget(), cti = ct.items.items, len = cti.length, i, c, items = [];
5045 for (i = 0; i < len; i++) {
5046 if((c = cti[i]).rendered && this.isValidParent(c, t) && c.shouldLayout !== false){
5055 * Applies extraCls and hides the item if renderHidden is true
5057 configureItem: function(c){
5058 if (this.extraCls) {
5059 var t = c.getPositionEl ? c.getPositionEl() : c;
5060 t.addClass(this.extraCls);
5063 // If we are forcing a layout, do so *before* we hide so elements have height/width
5064 if (c.doLayout && this.forceLayout) {
5067 if (this.renderHidden && c != this.activeItem) {
5072 onRemove: function(c){
5073 if(this.activeItem == c){
5074 delete this.activeItem;
5076 if(c.rendered && this.extraCls){
5077 var t = c.getPositionEl ? c.getPositionEl() : c;
5078 t.removeClass(this.extraCls);
5082 afterRemove: function(c){
5083 if(c.removeRestore){
5084 c.removeMode = 'container';
5085 delete c.removeRestore;
5090 onResize: function(){
5091 var ct = this.container,
5096 if(b = ct.bufferResize && ct.shouldBufferLayout()){
5097 if(!this.resizeTask){
5098 this.resizeTask = new Ext.util.DelayedTask(this.runLayout, this);
5099 this.resizeBuffer = Ext.isNumber(b) ? b : 50;
5101 ct.layoutPending = true;
5102 this.resizeTask.delay(this.resizeBuffer);
5108 runLayout: function(){
5109 var ct = this.container;
5112 delete ct.layoutPending;
5116 setContainer : function(ct){
5118 * This monitorResize flag will be renamed soon as to avoid confusion
5119 * with the Container version which hooks onWindowResize to doLayout
5121 * monitorResize flag in this context attaches the resize event between
5122 * a container and it's layout
5124 if(this.monitorResize && ct != this.container){
5125 var old = this.container;
5127 old.un(old.resizeEvent, this.onResize, this);
5130 ct.on(ct.resizeEvent, this.onResize, this);
5133 this.container = ct;
5137 * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
5138 * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
5139 * @param {Number|String} v The encoded margins
5140 * @return {Object} An object with margin sizes for top, right, bottom and left
5142 parseMargins : function(v){
5143 if (Ext.isNumber(v)) {
5146 var ms = v.split(' '),
5150 ms[1] = ms[2] = ms[3] = ms[0];
5151 } else if(len == 2) {
5154 } else if(len == 3) {
5159 top :parseInt(ms[0], 10) || 0,
5160 right :parseInt(ms[1], 10) || 0,
5161 bottom:parseInt(ms[2], 10) || 0,
5162 left :parseInt(ms[3], 10) || 0
5167 * The {@link Ext.Template Ext.Template} used by Field rendering layout classes (such as
5168 * {@link Ext.layout.FormLayout}) to create the DOM structure of a fully wrapped,
5169 * labeled and styled form Field. A default Template is supplied, but this may be
5170 * overriden to create custom field structures. The template processes values returned from
5171 * {@link Ext.layout.FormLayout#getTemplateArgs}.
5172 * @property fieldTpl
5173 * @type Ext.Template
5175 fieldTpl: (function() {
5176 var t = new Ext.Template(
5177 '<div class="x-form-item {itemCls}" tabIndex="-1">',
5178 '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{labelSeparator}</label>',
5179 '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
5180 '</div><div class="{clearCls}"></div>',
5183 t.disableFormats = true;
5188 * Destroys this layout. This is a template method that is empty by default, but should be implemented
5189 * by subclasses that require explicit destruction to purge event handlers or remove DOM nodes.
5192 destroy : function(){
5193 // Stop any buffered layout tasks
5194 if(this.resizeTask && this.resizeTask.cancel){
5195 this.resizeTask.cancel();
5197 if(!Ext.isEmpty(this.targetCls)){
5198 var target = this.container.getLayoutTarget();
5200 target.removeClass(this.targetCls);
5205 * @class Ext.layout.AutoLayout
5206 * <p>The AutoLayout is the default layout manager delegated by {@link Ext.Container} to
5207 * render any child Components when no <tt>{@link Ext.Container#layout layout}</tt> is configured into
5208 * a {@link Ext.Container Container}.</tt>. AutoLayout provides only a passthrough of any layout calls
5209 * to any child containers.</p>
5211 Ext.layout.AutoLayout = Ext.extend(Ext.layout.ContainerLayout, {
5214 monitorResize: true,
5216 onLayout : function(ct, target){
5217 Ext.layout.AutoLayout.superclass.onLayout.call(this, ct, target);
5218 var cs = this.getRenderedItems(ct), len = cs.length, i, c;
5219 for(i = 0; i < len; i++){
5222 // Shallow layout children
5229 Ext.Container.LAYOUTS['auto'] = Ext.layout.AutoLayout;
5231 * @class Ext.layout.FitLayout
5232 * @extends Ext.layout.ContainerLayout
5233 * <p>This is a base class for layouts that contain <b>a single item</b> that automatically expands to fill the layout's
5234 * container. This class is intended to be extended or created via the <tt>layout:'fit'</tt> {@link Ext.Container#layout}
5235 * config, and should generally not need to be created directly via the new keyword.</p>
5236 * <p>FitLayout does not have any direct config options (other than inherited ones). To fit a panel to a container
5237 * using FitLayout, simply set layout:'fit' on the container and add a single panel to it. If the container has
5238 * multiple panels, only the first one will be displayed. Example usage:</p>
5240 var p = new Ext.Panel({
5241 title: 'Fit Layout',
5244 title: 'Inner Panel',
5245 html: '<p>This is the inner panel content</p>',
5251 Ext.layout.FitLayout = Ext.extend(Ext.layout.ContainerLayout, {
5257 getLayoutTargetSize : function() {
5258 var target = this.container.getLayoutTarget();
5262 // Style Sized (scrollbars not included)
5263 return target.getStyleSize();
5267 onLayout : function(ct, target){
5268 Ext.layout.FitLayout.superclass.onLayout.call(this, ct, target);
5270 this.setItemSize(this.activeItem || ct.items.itemAt(0), this.getLayoutTargetSize());
5275 setItemSize : function(item, size){
5276 if(item && size.height > 0){ // display none?
5281 Ext.Container.LAYOUTS['fit'] = Ext.layout.FitLayout;/**
5282 * @class Ext.layout.CardLayout
5283 * @extends Ext.layout.FitLayout
5284 * <p>This layout manages multiple child Components, each fitted to the Container, where only a single child Component can be
5285 * visible at any given time. This layout style is most commonly used for wizards, tab implementations, etc.
5286 * This class is intended to be extended or created via the layout:'card' {@link Ext.Container#layout} config,
5287 * and should generally not need to be created directly via the new keyword.</p>
5288 * <p>The CardLayout's focal method is {@link #setActiveItem}. Since only one panel is displayed at a time,
5289 * the only way to move from one Component to the next is by calling setActiveItem, passing the id or index of
5290 * the next panel to display. The layout itself does not provide a user interface for handling this navigation,
5291 * so that functionality must be provided by the developer.</p>
5292 * <p>In the following example, a simplistic wizard setup is demonstrated. A button bar is added
5293 * to the footer of the containing panel to provide navigation buttons. The buttons will be handled by a
5294 * common navigation routine -- for this example, the implementation of that routine has been ommitted since
5295 * it can be any type of custom logic. Note that other uses of a CardLayout (like a tab control) would require a
5296 * completely different implementation. For serious implementations, a better approach would be to extend
5297 * CardLayout to provide the custom functionality needed. Example usage:</p>
5299 var navHandler = function(direction){
5300 // This routine could contain business logic required to manage the navigation steps.
5301 // It would call setActiveItem as needed, manage navigation button state, handle any
5302 // branching logic that might be required, handle alternate actions like cancellation
5303 // or finalization, etc. A complete wizard implementation could get pretty
5304 // sophisticated depending on the complexity required, and should probably be
5305 // done as a subclass of CardLayout in a real-world implementation.
5308 var card = new Ext.Panel({
5309 title: 'Example Wizard',
5311 activeItem: 0, // make sure the active item is set on the container config!
5312 bodyStyle: 'padding:15px',
5314 // applied to each contained panel
5317 // just an example of one possible navigation scheme, using buttons
5322 handler: navHandler.createDelegate(this, [-1]),
5325 '->', // greedy spacer so that the buttons are aligned to each side
5329 handler: navHandler.createDelegate(this, [1])
5332 // the panels (or "cards") within the layout
5335 html: '<h1>Welcome to the Wizard!</h1><p>Step 1 of 3</p>'
5338 html: '<p>Step 2 of 3</p>'
5341 html: '<h1>Congratulations!</h1><p>Step 3 of 3 - Complete</p>'
5346 Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, {
5348 * @cfg {Boolean} deferredRender
5349 * True to render each contained item at the time it becomes active, false to render all contained items
5350 * as soon as the layout is rendered (defaults to false). If there is a significant amount of content or
5351 * a lot of heavy controls being rendered into panels that are not displayed by default, setting this to
5352 * true might improve performance.
5354 deferredRender : false,
5357 * @cfg {Boolean} layoutOnCardChange
5358 * True to force a layout of the active item when the active card is changed. Defaults to false.
5360 layoutOnCardChange : false,
5363 * @cfg {Boolean} renderHidden @hide
5366 renderHidden : true,
5371 * Sets the active (visible) item in the layout.
5372 * @param {String/Number} item The string component id or numeric index of the item to activate
5374 setActiveItem : function(item){
5375 var ai = this.activeItem,
5376 ct = this.container;
5377 item = ct.getComponent(item);
5379 // Is this a valid, different card?
5380 if(item && ai != item){
5382 // Changing cards, hide the current one
5385 if (ai.hidden !== true) {
5388 ai.fireEvent('deactivate', ai);
5391 var layout = item.doLayout && (this.layoutOnCardChange || !item.rendered);
5393 // Change activeItem reference
5394 this.activeItem = item;
5396 // The container is about to get a recursive layout, remove any deferLayout reference
5397 // because it will trigger a redundant layout.
5398 delete item.deferLayout;
5400 // Show the new component
5408 item.fireEvent('activate', item);
5413 renderAll : function(ct, target){
5414 if(this.deferredRender){
5415 this.renderItem(this.activeItem, undefined, target);
5417 Ext.layout.CardLayout.superclass.renderAll.call(this, ct, target);
5421 Ext.Container.LAYOUTS['card'] = Ext.layout.CardLayout;
5423 * @class Ext.layout.AnchorLayout
5424 * @extends Ext.layout.ContainerLayout
5425 * <p>This is a layout that enables anchoring of contained elements relative to the container's dimensions.
5426 * If the container is resized, all anchored items are automatically rerendered according to their
5427 * <b><tt>{@link #anchor}</tt></b> rules.</p>
5428 * <p>This class is intended to be extended or created via the layout:'anchor' {@link Ext.Container#layout}
5429 * config, and should generally not need to be created directly via the new keyword.</p>
5430 * <p>AnchorLayout does not have any direct config options (other than inherited ones). By default,
5431 * AnchorLayout will calculate anchor measurements based on the size of the container itself. However, the
5432 * container using the AnchorLayout can supply an anchoring-specific config property of <b>anchorSize</b>.
5433 * If anchorSize is specifed, the layout will use it as a virtual container for the purposes of calculating
5434 * anchor measurements based on it instead, allowing the container to be sized independently of the anchoring
5435 * logic if necessary. For example:</p>
5437 var viewport = new Ext.Viewport({
5439 anchorSize: {width:800, height:600},
5459 Ext.layout.AnchorLayout = Ext.extend(Ext.layout.ContainerLayout, {
5461 * @cfg {String} anchor
5462 * <p>This configuation option is to be applied to <b>child <tt>items</tt></b> of a container managed by
5463 * this layout (ie. configured with <tt>layout:'anchor'</tt>).</p><br/>
5465 * <p>This value is what tells the layout how an item should be anchored to the container. <tt>items</tt>
5466 * added to an AnchorLayout accept an anchoring-specific config property of <b>anchor</b> which is a string
5467 * containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%').
5468 * The following types of anchor values are supported:<div class="mdetail-params"><ul>
5470 * <li><b>Percentage</b> : Any value between 1 and 100, expressed as a percentage.<div class="sub-desc">
5471 * The first anchor is the percentage width that the item should take up within the container, and the
5472 * second is the percentage height. For example:<pre><code>
5473 // two values specified
5474 anchor: '100% 50%' // render item complete width of the container and
5475 // 1/2 height of the container
5476 // one value specified
5477 anchor: '100%' // the width value; the height will default to auto
5478 * </code></pre></div></li>
5480 * <li><b>Offsets</b> : Any positive or negative integer value.<div class="sub-desc">
5481 * This is a raw adjustment where the first anchor is the offset from the right edge of the container,
5482 * and the second is the offset from the bottom edge. For example:<pre><code>
5483 // two values specified
5484 anchor: '-50 -100' // render item the complete width of the container
5485 // minus 50 pixels and
5486 // the complete height minus 100 pixels.
5487 // one value specified
5488 anchor: '-50' // anchor value is assumed to be the right offset value
5489 // bottom offset will default to 0
5490 * </code></pre></div></li>
5492 * <li><b>Sides</b> : Valid values are <tt>'right'</tt> (or <tt>'r'</tt>) and <tt>'bottom'</tt>
5493 * (or <tt>'b'</tt>).<div class="sub-desc">
5494 * Either the container must have a fixed size or an anchorSize config value defined at render time in
5495 * order for these to have any effect.</div></li>
5497 * <li><b>Mixed</b> : <div class="sub-desc">
5498 * Anchor values can also be mixed as needed. For example, to render the width offset from the container
5499 * right edge by 50 pixels and 75% of the container's height use:
5502 * </code></pre></div></li>
5509 monitorResize : true,
5514 * @cfg {String} defaultAnchor
5516 * default anchor for all child container items applied if no anchor or specific width is set on the child item. Defaults to '100%'.
5519 defaultAnchor : '100%',
5521 parseAnchorRE : /^(r|right|b|bottom)$/i,
5524 getLayoutTargetSize : function() {
5525 var target = this.container.getLayoutTarget(), ret = {};
5527 ret = target.getViewSize();
5529 // IE in strict mode will return a width of 0 on the 1st pass of getViewSize.
5530 // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly
5532 if (Ext.isIE && Ext.isStrict && ret.width == 0){
5533 ret = target.getStyleSize();
5535 ret.width -= target.getPadding('lr');
5536 ret.height -= target.getPadding('tb');
5542 onLayout : function(container, target) {
5543 Ext.layout.AnchorLayout.superclass.onLayout.call(this, container, target);
5545 var size = this.getLayoutTargetSize(),
5546 containerWidth = size.width,
5547 containerHeight = size.height,
5548 overflow = target.getStyle('overflow'),
5549 components = this.getRenderedItems(container),
5550 len = components.length,
5564 if(containerWidth < 20 && containerHeight < 20){
5568 // find the container anchoring size
5569 if(container.anchorSize) {
5570 if(typeof container.anchorSize == 'number') {
5571 anchorWidth = container.anchorSize;
5573 anchorWidth = container.anchorSize.width;
5574 anchorHeight = container.anchorSize.height;
5577 anchorWidth = container.initialConfig.width;
5578 anchorHeight = container.initialConfig.height;
5581 for(i = 0; i < len; i++) {
5582 component = components[i];
5583 el = component.getPositionEl();
5585 // If a child container item has no anchor and no specific width, set the child to the default anchor size
5586 if (!component.anchor && component.items && !Ext.isNumber(component.width) && !(Ext.isIE6 && Ext.isStrict)){
5587 component.anchor = this.defaultAnchor;
5590 if(component.anchor) {
5591 anchorSpec = component.anchorSpec;
5592 // cache all anchor values
5594 anchorsArray = component.anchor.split(' ');
5595 component.anchorSpec = anchorSpec = {
5596 right: this.parseAnchor(anchorsArray[0], component.initialConfig.width, anchorWidth),
5597 bottom: this.parseAnchor(anchorsArray[1], component.initialConfig.height, anchorHeight)
5600 calcWidth = anchorSpec.right ? this.adjustWidthAnchor(anchorSpec.right(containerWidth) - el.getMargins('lr'), component) : undefined;
5601 calcHeight = anchorSpec.bottom ? this.adjustHeightAnchor(anchorSpec.bottom(containerHeight) - el.getMargins('tb'), component) : undefined;
5603 if(calcWidth || calcHeight) {
5605 component: component,
5606 width: calcWidth || undefined,
5607 height: calcHeight || undefined
5612 for (i = 0, len = boxes.length; i < len; i++) {
5614 box.component.setSize(box.width, box.height);
5617 if (overflow && overflow != 'hidden' && !this.adjustmentPass) {
5618 var newTargetSize = this.getLayoutTargetSize();
5619 if (newTargetSize.width != size.width || newTargetSize.height != size.height){
5620 this.adjustmentPass = true;
5621 this.onLayout(container, target);
5625 delete this.adjustmentPass;
5629 parseAnchor : function(a, start, cstart) {
5630 if (a && a != 'none') {
5633 if (this.parseAnchorRE.test(a)) {
5634 var diff = cstart - start;
5642 } else if(a.indexOf('%') != -1) {
5643 var ratio = parseFloat(a.replace('%', ''))*.01;
5647 return Math.floor(v*ratio);
5650 // simple offset adjustment
5652 a = parseInt(a, 10);
5654 return function(v) {
5667 adjustWidthAnchor : function(value, comp){
5672 adjustHeightAnchor : function(value, comp){
5677 * @property activeItem
5681 Ext.Container.LAYOUTS['anchor'] = Ext.layout.AnchorLayout;
5683 * @class Ext.layout.ColumnLayout
5684 * @extends Ext.layout.ContainerLayout
5685 * <p>This is the layout style of choice for creating structural layouts in a multi-column format where the width of
5686 * each column can be specified as a percentage or fixed width, but the height is allowed to vary based on the content.
5687 * This class is intended to be extended or created via the layout:'column' {@link Ext.Container#layout} config,
5688 * and should generally not need to be created directly via the new keyword.</p>
5689 * <p>ColumnLayout does not have any direct config options (other than inherited ones), but it does support a
5690 * specific config property of <b><tt>columnWidth</tt></b> that can be included in the config of any panel added to it. The
5691 * layout will use the columnWidth (if present) or width of each panel during layout to determine how to size each panel.
5692 * If width or columnWidth is not specified for a given panel, its width will default to the panel's width (or auto).</p>
5693 * <p>The width property is always evaluated as pixels, and must be a number greater than or equal to 1.
5694 * The columnWidth property is always evaluated as a percentage, and must be a decimal value greater than 0 and
5695 * less than 1 (e.g., .25).</p>
5696 * <p>The basic rules for specifying column widths are pretty simple. The logic makes two passes through the
5697 * set of contained panels. During the first layout pass, all panels that either have a fixed width or none
5698 * specified (auto) are skipped, but their widths are subtracted from the overall container width. During the second
5699 * pass, all panels with columnWidths are assigned pixel widths in proportion to their percentages based on
5700 * the total <b>remaining</b> container width. In other words, percentage width panels are designed to fill the space
5701 * left over by all the fixed-width and/or auto-width panels. Because of this, while you can specify any number of columns
5702 * with different percentages, the columnWidths must always add up to 1 (or 100%) when added together, otherwise your
5703 * layout may not render as expected. Example usage:</p>
5705 // All columns are percentages -- they must add up to 1
5706 var p = new Ext.Panel({
5707 title: 'Column Layout - Percentage Only',
5721 // Mix of width and columnWidth -- all columnWidth values must add up
5722 // to 1. The first column will take up exactly 120px, and the last two
5723 // columns will fill the remaining container width.
5724 var p = new Ext.Panel({
5725 title: 'Column Layout - Mixed',
5740 Ext.layout.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, {
5746 extraCls: 'x-column',
5752 targetCls: 'x-column-layout-ct',
5754 isValidParent : function(c, target){
5755 return this.innerCt && c.getPositionEl().dom.parentNode == this.innerCt.dom;
5758 getLayoutTargetSize : function() {
5759 var target = this.container.getLayoutTarget(), ret;
5761 ret = target.getViewSize();
5763 // IE in strict mode will return a width of 0 on the 1st pass of getViewSize.
5764 // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly
5766 if (Ext.isIE && Ext.isStrict && ret.width == 0){
5767 ret = target.getStyleSize();
5770 ret.width -= target.getPadding('lr');
5771 ret.height -= target.getPadding('tb');
5776 renderAll : function(ct, target) {
5778 // the innerCt prevents wrapping and shuffling while
5779 // the container is resizing
5780 this.innerCt = target.createChild({cls:'x-column-inner'});
5781 this.innerCt.createChild({cls:'x-clear'});
5783 Ext.layout.ColumnLayout.superclass.renderAll.call(this, ct, this.innerCt);
5787 onLayout : function(ct, target){
5788 var cs = ct.items.items,
5795 this.renderAll(ct, target);
5797 var size = this.getLayoutTargetSize();
5799 if(size.width < 1 && size.height < 1){ // display none?
5803 var w = size.width - this.scrollOffset,
5807 this.innerCt.setWidth(w);
5809 // some columns can be percentages while others are fixed
5810 // so we need to make 2 passes
5812 for(i = 0; i < len; i++){
5814 m = c.getPositionEl().getMargins('lr');
5817 pw -= (c.getWidth() + m);
5821 pw = pw < 0 ? 0 : pw;
5823 for(i = 0; i < len; i++){
5827 c.setSize(Math.floor(c.columnWidth * pw) - m);
5831 // Browsers differ as to when they account for scrollbars. We need to re-measure to see if the scrollbar
5832 // spaces were accounted for properly. If not, re-layout.
5834 if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) {
5835 var ts = this.getLayoutTargetSize();
5836 if (ts.width != size.width){
5837 this.adjustmentPass = true;
5838 this.onLayout(ct, target);
5842 delete this.adjustmentPass;
5846 * @property activeItem
5851 Ext.Container.LAYOUTS['column'] = Ext.layout.ColumnLayout;
5853 * @class Ext.layout.BorderLayout
5854 * @extends Ext.layout.ContainerLayout
5855 * <p>This is a multi-pane, application-oriented UI layout style that supports multiple
5856 * nested panels, automatic {@link Ext.layout.BorderLayout.Region#split split} bars between
5857 * {@link Ext.layout.BorderLayout.Region#BorderLayout.Region regions} and built-in
5858 * {@link Ext.layout.BorderLayout.Region#collapsible expanding and collapsing} of regions.</p>
5859 * <p>This class is intended to be extended or created via the <tt>layout:'border'</tt>
5860 * {@link Ext.Container#layout} config, and should generally not need to be created directly
5861 * via the new keyword.</p>
5862 * <p>BorderLayout does not have any direct config options (other than inherited ones).
5863 * All configuration options available for customizing the BorderLayout are at the
5864 * {@link Ext.layout.BorderLayout.Region} and {@link Ext.layout.BorderLayout.SplitRegion}
5866 * <p>Example usage:</p>
5868 var myBorderPanel = new Ext.Panel({
5869 {@link Ext.Component#renderTo renderTo}: document.body,
5870 {@link Ext.BoxComponent#width width}: 700,
5871 {@link Ext.BoxComponent#height height}: 500,
5872 {@link Ext.Panel#title title}: 'Border Layout',
5873 {@link Ext.Container#layout layout}: 'border',
5874 {@link Ext.Container#items items}: [{
5875 {@link Ext.Panel#title title}: 'South Region is resizable',
5876 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'south', // position for region
5877 {@link Ext.BoxComponent#height height}: 100,
5878 {@link Ext.layout.BorderLayout.Region#split split}: true, // enable resizing
5879 {@link Ext.SplitBar#minSize minSize}: 75, // defaults to {@link Ext.layout.BorderLayout.Region#minHeight 50}
5880 {@link Ext.SplitBar#maxSize maxSize}: 150,
5881 {@link Ext.layout.BorderLayout.Region#margins margins}: '0 5 5 5'
5883 // xtype: 'panel' implied by default
5884 {@link Ext.Panel#title title}: 'West Region is collapsible',
5885 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}:'west',
5886 {@link Ext.layout.BorderLayout.Region#margins margins}: '5 0 0 5',
5887 {@link Ext.BoxComponent#width width}: 200,
5888 {@link Ext.layout.BorderLayout.Region#collapsible collapsible}: true, // make collapsible
5889 {@link Ext.layout.BorderLayout.Region#cmargins cmargins}: '5 5 0 5', // adjust top margin when collapsed
5890 {@link Ext.Component#id id}: 'west-region-container',
5891 {@link Ext.Container#layout layout}: 'fit',
5892 {@link Ext.Panel#unstyled unstyled}: true
5894 {@link Ext.Panel#title title}: 'Center Region',
5895 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'center', // center region is required, no width/height specified
5896 {@link Ext.Component#xtype xtype}: 'container',
5897 {@link Ext.Container#layout layout}: 'fit',
5898 {@link Ext.layout.BorderLayout.Region#margins margins}: '5 5 0 0'
5902 * <p><b><u>Notes</u></b>:</p><div class="mdetail-params"><ul>
5903 * <li>Any container using the BorderLayout <b>must</b> have a child item with <tt>region:'center'</tt>.
5904 * The child item in the center region will always be resized to fill the remaining space not used by
5905 * the other regions in the layout.</li>
5906 * <li>Any child items with a region of <tt>west</tt> or <tt>east</tt> must have <tt>width</tt> defined
5907 * (an integer representing the number of pixels that the region should take up).</li>
5908 * <li>Any child items with a region of <tt>north</tt> or <tt>south</tt> must have <tt>height</tt> defined.</li>
5909 * <li>The regions of a BorderLayout are <b>fixed at render time</b> and thereafter, its child Components may not be removed or added</b>. To add/remove
5910 * Components within a BorderLayout, have them wrapped by an additional Container which is directly
5911 * managed by the BorderLayout. If the region is to be collapsible, the Container used directly
5912 * by the BorderLayout manager should be a Panel. In the following example a Container (an Ext.Panel)
5913 * is added to the west region:
5914 * <div style="margin-left:16px"><pre><code>
5915 wrc = {@link Ext#getCmp Ext.getCmp}('west-region-container');
5916 wrc.{@link Ext.Panel#removeAll removeAll}();
5917 wrc.{@link Ext.Container#add add}({
5918 title: 'Added Panel',
5919 html: 'Some content'
5921 wrc.{@link Ext.Container#doLayout doLayout}();
5922 * </code></pre></div>
5924 * <li> To reference a {@link Ext.layout.BorderLayout.Region Region}:
5925 * <div style="margin-left:16px"><pre><code>
5926 wr = myBorderPanel.layout.west;
5927 * </code></pre></div>
5931 Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {
5939 targetCls: 'x-border-layout-ct',
5941 getLayoutTargetSize : function() {
5942 var target = this.container.getLayoutTarget();
5943 return target ? target.getViewSize() : {};
5947 onLayout : function(ct, target){
5948 var collapsed, i, c, pos, items = ct.items.items, len = items.length;
5951 for(i = 0; i < len; i++) {
5957 c.collapsed = false;
5959 c.render(target, i);
5960 c.getPositionEl().addClass('x-border-panel');
5962 this[pos] = pos != 'center' && c.split ?
5963 new Ext.layout.BorderLayout.SplitRegion(this, c.initialConfig, pos) :
5964 new Ext.layout.BorderLayout.Region(this, c.initialConfig, pos);
5965 this[pos].render(target, c);
5967 this.rendered = true;
5970 var size = this.getLayoutTargetSize();
5971 if(size.width < 20 || size.height < 20){ // display none?
5973 this.restoreCollapsed = collapsed;
5976 }else if(this.restoreCollapsed){
5977 collapsed = this.restoreCollapsed;
5978 delete this.restoreCollapsed;
5981 var w = size.width, h = size.height,
5982 centerW = w, centerH = h, centerY = 0, centerX = 0,
5983 n = this.north, s = this.south, west = this.west, e = this.east, c = this.center,
5984 b, m, totalWidth, totalHeight;
5985 if(!c && Ext.layout.BorderLayout.WARN !== false){
5986 throw 'No center region defined in BorderLayout ' + ct.id;
5989 if(n && n.isVisible()){
5992 b.width = w - (m.left+m.right);
5995 centerY = b.height + b.y + m.bottom;
5999 if(s && s.isVisible()){
6002 b.width = w - (m.left+m.right);
6004 totalHeight = (b.height + m.top + m.bottom);
6005 b.y = h - totalHeight + m.top;
6006 centerH -= totalHeight;
6009 if(west && west.isVisible()){
6011 m = west.getMargins();
6012 b.height = centerH - (m.top+m.bottom);
6014 b.y = centerY + m.top;
6015 totalWidth = (b.width + m.left + m.right);
6016 centerX += totalWidth;
6017 centerW -= totalWidth;
6018 west.applyLayout(b);
6020 if(e && e.isVisible()){
6023 b.height = centerH - (m.top+m.bottom);
6024 totalWidth = (b.width + m.left + m.right);
6025 b.x = w - totalWidth + m.left;
6026 b.y = centerY + m.top;
6027 centerW -= totalWidth;
6033 x: centerX + m.left,
6035 width: centerW - (m.left+m.right),
6036 height: centerH - (m.top+m.bottom)
6038 c.applyLayout(centerBox);
6041 for(i = 0, len = collapsed.length; i < len; i++){
6042 collapsed[i].collapse(false);
6045 if(Ext.isIE && Ext.isStrict){ // workaround IE strict repainting issue
6048 // Putting a border layout into an overflowed container is NOT correct and will make a second layout pass necessary.
6049 if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) {
6050 var ts = this.getLayoutTargetSize();
6051 if (ts.width != size.width || ts.height != size.height){
6052 this.adjustmentPass = true;
6053 this.onLayout(ct, target);
6056 delete this.adjustmentPass;
6059 destroy: function() {
6060 var r = ['north', 'south', 'east', 'west'], i, region;
6061 for (i = 0; i < r.length; i++) {
6062 region = this[r[i]];
6066 }else if (region.split){
6067 region.split.destroy(true);
6071 Ext.layout.BorderLayout.superclass.destroy.call(this);
6075 * @property activeItem
6081 * @class Ext.layout.BorderLayout.Region
6082 * <p>This is a region of a {@link Ext.layout.BorderLayout BorderLayout} that acts as a subcontainer
6083 * within the layout. Each region has its own {@link Ext.layout.ContainerLayout layout} that is
6084 * independent of other regions and the containing BorderLayout, and can be any of the
6085 * {@link Ext.layout.ContainerLayout valid Ext layout types}.</p>
6086 * <p>Region size is managed automatically and cannot be changed by the user -- for
6087 * {@link #split resizable regions}, see {@link Ext.layout.BorderLayout.SplitRegion}.</p>
6089 * Create a new Region.
6090 * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region.
6091 * @param {Object} config The configuration options
6092 * @param {String} position The region position. Valid values are: <tt>north</tt>, <tt>south</tt>,
6093 * <tt>east</tt>, <tt>west</tt> and <tt>center</tt>. Every {@link Ext.layout.BorderLayout BorderLayout}
6094 * <b>must have a center region</b> for the primary content -- all other regions are optional.
6096 Ext.layout.BorderLayout.Region = function(layout, config, pos){
6097 Ext.apply(this, config);
6098 this.layout = layout;
6099 this.position = pos;
6101 if(typeof this.margins == 'string'){
6102 this.margins = this.layout.parseMargins(this.margins);
6104 this.margins = Ext.applyIf(this.margins || {}, this.defaultMargins);
6105 if(this.collapsible){
6106 if(typeof this.cmargins == 'string'){
6107 this.cmargins = this.layout.parseMargins(this.cmargins);
6109 if(this.collapseMode == 'mini' && !this.cmargins){
6110 this.cmargins = {left:0,top:0,right:0,bottom:0};
6112 this.cmargins = Ext.applyIf(this.cmargins || {},
6113 pos == 'north' || pos == 'south' ? this.defaultNSCMargins : this.defaultEWCMargins);
6118 Ext.layout.BorderLayout.Region.prototype = {
6120 * @cfg {Boolean} animFloat
6121 * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated
6122 * panel that will close again once the user mouses out of that panel (or clicks out if
6123 * <tt>{@link #autoHide} = false</tt>). Setting <tt>{@link #animFloat} = false</tt> will
6124 * prevent the open and close of these floated panels from being animated (defaults to <tt>true</tt>).
6127 * @cfg {Boolean} autoHide
6128 * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated
6129 * panel. If <tt>autoHide = true</tt>, the panel will automatically hide after the user mouses
6130 * out of the panel. If <tt>autoHide = false</tt>, the panel will continue to display until the
6131 * user clicks outside of the panel (defaults to <tt>true</tt>).
6134 * @cfg {String} collapseMode
6135 * <tt>collapseMode</tt> supports two configuration values:<div class="mdetail-params"><ul>
6136 * <li><b><tt>undefined</tt></b> (default)<div class="sub-desc">By default, {@link #collapsible}
6137 * regions are collapsed by clicking the expand/collapse tool button that renders into the region's
6138 * title bar.</div></li>
6139 * <li><b><tt>'mini'</tt></b><div class="sub-desc">Optionally, when <tt>collapseMode</tt> is set to
6140 * <tt>'mini'</tt> the region's split bar will also display a small collapse button in the center of
6141 * the bar. In <tt>'mini'</tt> mode the region will collapse to a thinner bar than in normal mode.
6144 * <p><b>Note</b>: if a collapsible region does not have a title bar, then set <tt>collapseMode =
6145 * 'mini'</tt> and <tt>{@link #split} = true</tt> in order for the region to be {@link #collapsible}
6146 * by the user as the expand/collapse tool button (that would go in the title bar) will not be rendered.</p>
6147 * <p>See also <tt>{@link #cmargins}</tt>.</p>
6150 * @cfg {Object} margins
6151 * An object containing margins to apply to the region when in the expanded state in the
6152 * format:<pre><code>
6155 right: (right margin),
6156 bottom: (bottom margin),
6159 * <p>May also be a string containing space-separated, numeric margin values. The order of the
6160 * sides associated with each value matches the way CSS processes margin values:</p>
6161 * <p><div class="mdetail-params"><ul>
6162 * <li>If there is only one value, it applies to all sides.</li>
6163 * <li>If there are two values, the top and bottom borders are set to the first value and the
6164 * right and left are set to the second.</li>
6165 * <li>If there are three values, the top is set to the first value, the left and right are set
6166 * to the second, and the bottom is set to the third.</li>
6167 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
6169 * <p>Defaults to:</p><pre><code>
6170 * {top:0, right:0, bottom:0, left:0}
6174 * @cfg {Object} cmargins
6175 * An object containing margins to apply to the region when in the collapsed state in the
6176 * format:<pre><code>
6179 right: (right margin),
6180 bottom: (bottom margin),
6183 * <p>May also be a string containing space-separated, numeric margin values. The order of the
6184 * sides associated with each value matches the way CSS processes margin values.</p>
6186 * <li>If there is only one value, it applies to all sides.</li>
6187 * <li>If there are two values, the top and bottom borders are set to the first value and the
6188 * right and left are set to the second.</li>
6189 * <li>If there are three values, the top is set to the first value, the left and right are set
6190 * to the second, and the bottom is set to the third.</li>
6191 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
6195 * @cfg {Boolean} collapsible
6196 * <p><tt>true</tt> to allow the user to collapse this region (defaults to <tt>false</tt>). If
6197 * <tt>true</tt>, an expand/collapse tool button will automatically be rendered into the title
6198 * bar of the region, otherwise the button will not be shown.</p>
6199 * <p><b>Note</b>: that a title bar is required to display the collapse/expand toggle button -- if
6200 * no <tt>title</tt> is specified for the region's panel, the region will only be collapsible if
6201 * <tt>{@link #collapseMode} = 'mini'</tt> and <tt>{@link #split} = true</tt>.
6203 collapsible : false,
6205 * @cfg {Boolean} split
6206 * <p><tt>true</tt> to create a {@link Ext.layout.BorderLayout.SplitRegion SplitRegion} and
6207 * display a 5px wide {@link Ext.SplitBar} between this region and its neighbor, allowing the user to
6208 * resize the regions dynamically. Defaults to <tt>false</tt> creating a
6209 * {@link Ext.layout.BorderLayout.Region Region}.</p><br>
6210 * <p><b>Notes</b>:</p><div class="mdetail-params"><ul>
6211 * <li>this configuration option is ignored if <tt>region='center'</tt></li>
6212 * <li>when <tt>split == true</tt>, it is common to specify a
6213 * <tt>{@link Ext.SplitBar#minSize minSize}</tt> and <tt>{@link Ext.SplitBar#maxSize maxSize}</tt>
6214 * for the {@link Ext.BoxComponent BoxComponent} representing the region. These are not native
6215 * configs of {@link Ext.BoxComponent BoxComponent}, and are used only by this class.</li>
6216 * <li>if <tt>{@link #collapseMode} = 'mini'</tt> requires <tt>split = true</tt> to reserve space
6217 * for the collapse tool</tt></li>
6222 * @cfg {Boolean} floatable
6223 * <tt>true</tt> to allow clicking a collapsed region's bar to display the region's panel floated
6224 * above the layout, <tt>false</tt> to force the user to fully expand a collapsed region by
6225 * clicking the expand button to see it again (defaults to <tt>true</tt>).
6229 * @cfg {Number} minWidth
6230 * <p>The minimum allowable width in pixels for this region (defaults to <tt>50</tt>).
6231 * <tt>maxWidth</tt> may also be specified.</p><br>
6232 * <p><b>Note</b>: setting the <tt>{@link Ext.SplitBar#minSize minSize}</tt> /
6233 * <tt>{@link Ext.SplitBar#maxSize maxSize}</tt> supersedes any specified
6234 * <tt>minWidth</tt> / <tt>maxWidth</tt>.</p>
6238 * @cfg {Number} minHeight
6239 * The minimum allowable height in pixels for this region (defaults to <tt>50</tt>)
6240 * <tt>maxHeight</tt> may also be specified.</p><br>
6241 * <p><b>Note</b>: setting the <tt>{@link Ext.SplitBar#minSize minSize}</tt> /
6242 * <tt>{@link Ext.SplitBar#maxSize maxSize}</tt> supersedes any specified
6243 * <tt>minHeight</tt> / <tt>maxHeight</tt>.</p>
6248 defaultMargins : {left:0,top:0,right:0,bottom:0},
6250 defaultNSCMargins : {left:5,top:5,right:5,bottom:5},
6252 defaultEWCMargins : {left:5,top:0,right:5,bottom:0},
6253 floatingZIndex: 100,
6256 * True if this region is collapsed. Read-only.
6260 isCollapsed : false,
6263 * This region's panel. Read-only.
6268 * This region's layout. Read-only.
6273 * This region's layout position (north, south, east, west or center). Read-only.
6275 * @property position
6279 render : function(ct, p){
6281 p.el.enableDisplayMode();
6285 var gs = p.getState, ps = this.position;
6286 p.getState = function(){
6287 return Ext.apply(gs.call(p) || {}, this.state);
6288 }.createDelegate(this);
6291 p.allowQueuedExpand = false;
6293 beforecollapse: this.beforeCollapse,
6294 collapse: this.onCollapse,
6295 beforeexpand: this.beforeExpand,
6296 expand: this.onExpand,
6301 if(this.collapsible || this.floatable){
6302 p.collapseEl = 'el';
6303 p.slideAnchor = this.getSlideAnchor();
6305 if(p.tools && p.tools.toggle){
6306 p.tools.toggle.addClass('x-tool-collapse-'+ps);
6307 p.tools.toggle.addClassOnOver('x-tool-collapse-'+ps+'-over');
6313 getCollapsedEl : function(){
6314 if(!this.collapsedEl){
6315 if(!this.toolTemplate){
6316 var tt = new Ext.Template(
6317 '<div class="x-tool x-tool-{id}"> </div>'
6319 tt.disableFormats = true;
6321 Ext.layout.BorderLayout.Region.prototype.toolTemplate = tt;
6323 this.collapsedEl = this.targetEl.createChild({
6324 cls: "x-layout-collapsed x-layout-collapsed-"+this.position,
6325 id: this.panel.id + '-xcollapsed'
6327 this.collapsedEl.enableDisplayMode('block');
6329 if(this.collapseMode == 'mini'){
6330 this.collapsedEl.addClass('x-layout-cmini-'+this.position);
6331 this.miniCollapsedEl = this.collapsedEl.createChild({
6332 cls: "x-layout-mini x-layout-mini-"+this.position, html: " "
6334 this.miniCollapsedEl.addClassOnOver('x-layout-mini-over');
6335 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
6336 this.collapsedEl.on('click', this.onExpandClick, this, {stopEvent:true});
6338 if(this.collapsible !== false && !this.hideCollapseTool) {
6339 var t = this.expandToolEl = this.toolTemplate.append(
6340 this.collapsedEl.dom,
6341 {id:'expand-'+this.position}, true);
6342 t.addClassOnOver('x-tool-expand-'+this.position+'-over');
6343 t.on('click', this.onExpandClick, this, {stopEvent:true});
6345 if(this.floatable !== false || this.titleCollapse){
6346 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
6347 this.collapsedEl.on("click", this[this.floatable ? 'collapseClick' : 'onExpandClick'], this);
6351 return this.collapsedEl;
6355 onExpandClick : function(e){
6357 this.panel.expand(false);
6359 this.panel.expand();
6364 onCollapseClick : function(e){
6365 this.panel.collapse();
6369 beforeCollapse : function(p, animate){
6370 this.lastAnim = animate;
6372 this.splitEl.hide();
6374 this.getCollapsedEl().show();
6375 var el = this.panel.getEl();
6376 this.originalZIndex = el.getStyle('z-index');
6377 el.setStyle('z-index', 100);
6378 this.isCollapsed = true;
6379 this.layout.layout();
6383 onCollapse : function(animate){
6384 this.panel.el.setStyle('z-index', 1);
6385 if(this.lastAnim === false || this.panel.animCollapse === false){
6386 this.getCollapsedEl().dom.style.visibility = 'visible';
6388 this.getCollapsedEl().slideIn(this.panel.slideAnchor, {duration:.2});
6390 this.state.collapsed = true;
6391 this.panel.saveState();
6395 beforeExpand : function(animate){
6397 this.afterSlideIn();
6399 var c = this.getCollapsedEl();
6401 if(this.position == 'east' || this.position == 'west'){
6402 this.panel.setSize(undefined, c.getHeight());
6404 this.panel.setSize(c.getWidth(), undefined);
6407 c.dom.style.visibility = 'hidden';
6408 this.panel.el.setStyle('z-index', this.floatingZIndex);
6412 onExpand : function(){
6413 this.isCollapsed = false;
6415 this.splitEl.show();
6417 this.layout.layout();
6418 this.panel.el.setStyle('z-index', this.originalZIndex);
6419 this.state.collapsed = false;
6420 this.panel.saveState();
6424 collapseClick : function(e){
6426 e.stopPropagation();
6429 e.stopPropagation();
6435 onHide : function(){
6436 if(this.isCollapsed){
6437 this.getCollapsedEl().hide();
6438 }else if(this.splitEl){
6439 this.splitEl.hide();
6444 onShow : function(){
6445 if(this.isCollapsed){
6446 this.getCollapsedEl().show();
6447 }else if(this.splitEl){
6448 this.splitEl.show();
6453 * True if this region is currently visible, else false.
6456 isVisible : function(){
6457 return !this.panel.hidden;
6461 * Returns the current margins for this region. If the region is collapsed, the
6462 * {@link #cmargins} (collapsed margins) value will be returned, otherwise the
6463 * {@link #margins} value will be returned.
6464 * @return {Object} An object containing the element's margins: <tt>{left: (left
6465 * margin), top: (top margin), right: (right margin), bottom: (bottom margin)}</tt>
6467 getMargins : function(){
6468 return this.isCollapsed && this.cmargins ? this.cmargins : this.margins;
6472 * Returns the current size of this region. If the region is collapsed, the size of the
6473 * collapsedEl will be returned, otherwise the size of the region's panel will be returned.
6474 * @return {Object} An object containing the element's size: <tt>{width: (element width),
6475 * height: (element height)}</tt>
6477 getSize : function(){
6478 return this.isCollapsed ? this.getCollapsedEl().getSize() : this.panel.getSize();
6482 * Sets the specified panel as the container element for this region.
6483 * @param {Ext.Panel} panel The new panel
6485 setPanel : function(panel){
6490 * Returns the minimum allowable width for this region.
6491 * @return {Number} The minimum width
6493 getMinWidth: function(){
6494 return this.minWidth;
6498 * Returns the minimum allowable height for this region.
6499 * @return {Number} The minimum height
6501 getMinHeight: function(){
6502 return this.minHeight;
6506 applyLayoutCollapsed : function(box){
6507 var ce = this.getCollapsedEl();
6508 ce.setLeftTop(box.x, box.y);
6509 ce.setSize(box.width, box.height);
6513 applyLayout : function(box){
6514 if(this.isCollapsed){
6515 this.applyLayoutCollapsed(box);
6517 this.panel.setPosition(box.x, box.y);
6518 this.panel.setSize(box.width, box.height);
6523 beforeSlide: function(){
6524 this.panel.beforeEffect();
6528 afterSlide : function(){
6529 this.panel.afterEffect();
6533 initAutoHide : function(){
6534 if(this.autoHide !== false){
6535 if(!this.autoHideHd){
6536 this.autoHideSlideTask = new Ext.util.DelayedTask(this.slideIn, this);
6538 "mouseout": function(e){
6539 if(!e.within(this.el, true)){
6540 this.autoHideSlideTask.delay(500);
6543 "mouseover" : function(e){
6544 this.autoHideSlideTask.cancel();
6549 this.el.on(this.autoHideHd);
6550 this.collapsedEl.on(this.autoHideHd);
6555 clearAutoHide : function(){
6556 if(this.autoHide !== false){
6557 this.el.un("mouseout", this.autoHideHd.mouseout);
6558 this.el.un("mouseover", this.autoHideHd.mouseover);
6559 this.collapsedEl.un("mouseout", this.autoHideHd.mouseout);
6560 this.collapsedEl.un("mouseover", this.autoHideHd.mouseover);
6565 clearMonitor : function(){
6566 Ext.getDoc().un("click", this.slideInIf, this);
6570 * If this Region is {@link #floatable}, this method slides this Region into full visibility <i>over the top
6571 * of the center Region</i> where it floats until either {@link #slideIn} is called, or other regions of the layout
6572 * are clicked, or the mouse exits the Region.
6574 slideOut : function(){
6575 if(this.isSlid || this.el.hasActiveFx()){
6579 var ts = this.panel.tools, dh, pc;
6580 if(ts && ts.toggle){
6585 // Temporarily clear the collapsed flag so we can onResize the panel on the slide
6586 pc = this.panel.collapsed;
6587 this.panel.collapsed = false;
6589 if(this.position == 'east' || this.position == 'west'){
6590 // Temporarily clear the deferHeight flag so we can size the height on the slide
6591 dh = this.panel.deferHeight;
6592 this.panel.deferHeight = false;
6594 this.panel.setSize(undefined, this.collapsedEl.getHeight());
6596 // Put the deferHeight flag back after setSize
6597 this.panel.deferHeight = dh;
6599 this.panel.setSize(this.collapsedEl.getWidth(), undefined);
6602 // Put the collapsed flag back after onResize
6603 this.panel.collapsed = pc;
6605 this.restoreLT = [this.el.dom.style.left, this.el.dom.style.top];
6606 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
6607 this.el.setStyle("z-index", this.floatingZIndex+2);
6608 this.panel.el.replaceClass('x-panel-collapsed', 'x-panel-floating');
6609 if(this.animFloat !== false){
6611 this.el.slideIn(this.getSlideAnchor(), {
6612 callback: function(){
6614 this.initAutoHide();
6615 Ext.getDoc().on("click", this.slideInIf, this);
6621 this.initAutoHide();
6622 Ext.getDoc().on("click", this.slideInIf, this);
6627 afterSlideIn : function(){
6628 this.clearAutoHide();
6629 this.isSlid = false;
6630 this.clearMonitor();
6631 this.el.setStyle("z-index", "");
6632 this.panel.el.replaceClass('x-panel-floating', 'x-panel-collapsed');
6633 this.el.dom.style.left = this.restoreLT[0];
6634 this.el.dom.style.top = this.restoreLT[1];
6636 var ts = this.panel.tools;
6637 if(ts && ts.toggle){
6643 * If this Region is {@link #floatable}, and this Region has been slid into floating visibility, then this method slides
6644 * this region back into its collapsed state.
6646 slideIn : function(cb){
6647 if(!this.isSlid || this.el.hasActiveFx()){
6651 this.isSlid = false;
6652 if(this.animFloat !== false){
6654 this.el.slideOut(this.getSlideAnchor(), {
6655 callback: function(){
6658 this.afterSlideIn();
6666 this.afterSlideIn();
6671 slideInIf : function(e){
6672 if(!e.within(this.el)){
6702 getAnchor : function(){
6703 return this.anchors[this.position];
6707 getCollapseAnchor : function(){
6708 return this.canchors[this.position];
6712 getSlideAnchor : function(){
6713 return this.sanchors[this.position];
6717 getAlignAdj : function(){
6718 var cm = this.cmargins;
6719 switch(this.position){
6736 getExpandAdj : function(){
6737 var c = this.collapsedEl, cm = this.cmargins;
6738 switch(this.position){
6740 return [-(cm.right+c.getWidth()+cm.left), 0];
6743 return [cm.right+c.getWidth()+cm.left, 0];
6746 return [0, -(cm.top+cm.bottom+c.getHeight())];
6749 return [0, cm.top+cm.bottom+c.getHeight()];
6754 destroy : function(){
6755 if (this.autoHideSlideTask && this.autoHideSlideTask.cancel){
6756 this.autoHideSlideTask.cancel();
6758 Ext.destroyMembers(this, 'miniCollapsedEl', 'collapsedEl', 'expandToolEl');
6763 * @class Ext.layout.BorderLayout.SplitRegion
6764 * @extends Ext.layout.BorderLayout.Region
6765 * <p>This is a specialized type of {@link Ext.layout.BorderLayout.Region BorderLayout region} that
6766 * has a built-in {@link Ext.SplitBar} for user resizing of regions. The movement of the split bar
6767 * is configurable to move either {@link #tickSize smooth or incrementally}.</p>
6769 * Create a new SplitRegion.
6770 * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region.
6771 * @param {Object} config The configuration options
6772 * @param {String} position The region position. Valid values are: north, south, east, west and center. Every
6773 * BorderLayout must have a center region for the primary content -- all other regions are optional.
6775 Ext.layout.BorderLayout.SplitRegion = function(layout, config, pos){
6776 Ext.layout.BorderLayout.SplitRegion.superclass.constructor.call(this, layout, config, pos);
6778 this.applyLayout = this.applyFns[pos];
6781 Ext.extend(Ext.layout.BorderLayout.SplitRegion, Ext.layout.BorderLayout.Region, {
6783 * @cfg {Number} tickSize
6784 * The increment, in pixels by which to move this Region's {@link Ext.SplitBar SplitBar}.
6785 * By default, the {@link Ext.SplitBar SplitBar} moves smoothly.
6788 * @cfg {String} splitTip
6789 * The tooltip to display when the user hovers over a
6790 * {@link Ext.layout.BorderLayout.Region#collapsible non-collapsible} region's split bar
6791 * (defaults to <tt>"Drag to resize."</tt>). Only applies if
6792 * <tt>{@link #useSplitTips} = true</tt>.
6794 splitTip : "Drag to resize.",
6796 * @cfg {String} collapsibleSplitTip
6797 * The tooltip to display when the user hovers over a
6798 * {@link Ext.layout.BorderLayout.Region#collapsible collapsible} region's split bar
6799 * (defaults to "Drag to resize. Double click to hide."). Only applies if
6800 * <tt>{@link #useSplitTips} = true</tt>.
6802 collapsibleSplitTip : "Drag to resize. Double click to hide.",
6804 * @cfg {Boolean} useSplitTips
6805 * <tt>true</tt> to display a tooltip when the user hovers over a region's split bar
6806 * (defaults to <tt>false</tt>). The tooltip text will be the value of either
6807 * <tt>{@link #splitTip}</tt> or <tt>{@link #collapsibleSplitTip}</tt> as appropriate.
6809 useSplitTips : false,
6814 orientation: Ext.SplitBar.VERTICAL,
6815 placement: Ext.SplitBar.TOP,
6816 maxFn : 'getVMaxSize',
6817 minProp: 'minHeight',
6818 maxProp: 'maxHeight'
6821 orientation: Ext.SplitBar.VERTICAL,
6822 placement: Ext.SplitBar.BOTTOM,
6823 maxFn : 'getVMaxSize',
6824 minProp: 'minHeight',
6825 maxProp: 'maxHeight'
6828 orientation: Ext.SplitBar.HORIZONTAL,
6829 placement: Ext.SplitBar.RIGHT,
6830 maxFn : 'getHMaxSize',
6831 minProp: 'minWidth',
6835 orientation: Ext.SplitBar.HORIZONTAL,
6836 placement: Ext.SplitBar.LEFT,
6837 maxFn : 'getHMaxSize',
6838 minProp: 'minWidth',
6845 west : function(box){
6846 if(this.isCollapsed){
6847 return this.applyLayoutCollapsed(box);
6849 var sd = this.splitEl.dom, s = sd.style;
6850 this.panel.setPosition(box.x, box.y);
6851 var sw = sd.offsetWidth;
6852 s.left = (box.x+box.width-sw)+'px';
6853 s.top = (box.y)+'px';
6854 s.height = Math.max(0, box.height)+'px';
6855 this.panel.setSize(box.width-sw, box.height);
6857 east : function(box){
6858 if(this.isCollapsed){
6859 return this.applyLayoutCollapsed(box);
6861 var sd = this.splitEl.dom, s = sd.style;
6862 var sw = sd.offsetWidth;
6863 this.panel.setPosition(box.x+sw, box.y);
6864 s.left = (box.x)+'px';
6865 s.top = (box.y)+'px';
6866 s.height = Math.max(0, box.height)+'px';
6867 this.panel.setSize(box.width-sw, box.height);
6869 north : function(box){
6870 if(this.isCollapsed){
6871 return this.applyLayoutCollapsed(box);
6873 var sd = this.splitEl.dom, s = sd.style;
6874 var sh = sd.offsetHeight;
6875 this.panel.setPosition(box.x, box.y);
6876 s.left = (box.x)+'px';
6877 s.top = (box.y+box.height-sh)+'px';
6878 s.width = Math.max(0, box.width)+'px';
6879 this.panel.setSize(box.width, box.height-sh);
6881 south : function(box){
6882 if(this.isCollapsed){
6883 return this.applyLayoutCollapsed(box);
6885 var sd = this.splitEl.dom, s = sd.style;
6886 var sh = sd.offsetHeight;
6887 this.panel.setPosition(box.x, box.y+sh);
6888 s.left = (box.x)+'px';
6889 s.top = (box.y)+'px';
6890 s.width = Math.max(0, box.width)+'px';
6891 this.panel.setSize(box.width, box.height-sh);
6896 render : function(ct, p){
6897 Ext.layout.BorderLayout.SplitRegion.superclass.render.call(this, ct, p);
6899 var ps = this.position;
6901 this.splitEl = ct.createChild({
6902 cls: "x-layout-split x-layout-split-"+ps, html: " ",
6903 id: this.panel.id + '-xsplit'
6906 if(this.collapseMode == 'mini'){
6907 this.miniSplitEl = this.splitEl.createChild({
6908 cls: "x-layout-mini x-layout-mini-"+ps, html: " "
6910 this.miniSplitEl.addClassOnOver('x-layout-mini-over');
6911 this.miniSplitEl.on('click', this.onCollapseClick, this, {stopEvent:true});
6914 var s = this.splitSettings[ps];
6916 this.split = new Ext.SplitBar(this.splitEl.dom, p.el, s.orientation);
6917 this.split.tickSize = this.tickSize;
6918 this.split.placement = s.placement;
6919 this.split.getMaximumSize = this[s.maxFn].createDelegate(this);
6920 this.split.minSize = this.minSize || this[s.minProp];
6921 this.split.on("beforeapply", this.onSplitMove, this);
6922 this.split.useShim = this.useShim === true;
6923 this.maxSize = this.maxSize || this[s.maxProp];
6926 this.splitEl.hide();
6929 if(this.useSplitTips){
6930 this.splitEl.dom.title = this.collapsible ? this.collapsibleSplitTip : this.splitTip;
6932 if(this.collapsible){
6933 this.splitEl.on("dblclick", this.onCollapseClick, this);
6937 //docs inherit from superclass
6938 getSize : function(){
6939 if(this.isCollapsed){
6940 return this.collapsedEl.getSize();
6942 var s = this.panel.getSize();
6943 if(this.position == 'north' || this.position == 'south'){
6944 s.height += this.splitEl.dom.offsetHeight;
6946 s.width += this.splitEl.dom.offsetWidth;
6952 getHMaxSize : function(){
6953 var cmax = this.maxSize || 10000;
6954 var center = this.layout.center;
6955 return Math.min(cmax, (this.el.getWidth()+center.el.getWidth())-center.getMinWidth());
6959 getVMaxSize : function(){
6960 var cmax = this.maxSize || 10000;
6961 var center = this.layout.center;
6962 return Math.min(cmax, (this.el.getHeight()+center.el.getHeight())-center.getMinHeight());
6966 onSplitMove : function(split, newSize){
6967 var s = this.panel.getSize();
6968 this.lastSplitSize = newSize;
6969 if(this.position == 'north' || this.position == 'south'){
6970 this.panel.setSize(s.width, newSize);
6971 this.state.height = newSize;
6973 this.panel.setSize(newSize, s.height);
6974 this.state.width = newSize;
6976 this.layout.layout();
6977 this.panel.saveState();
6982 * Returns a reference to the split bar in use by this region.
6983 * @return {Ext.SplitBar} The split bar
6985 getSplitBar : function(){
6990 destroy : function() {
6991 Ext.destroy(this.miniSplitEl, this.split, this.splitEl);
6992 Ext.layout.BorderLayout.SplitRegion.superclass.destroy.call(this);
6996 Ext.Container.LAYOUTS['border'] = Ext.layout.BorderLayout;
6998 * @class Ext.layout.FormLayout
6999 * @extends Ext.layout.AnchorLayout
7000 * <p>This layout manager is specifically designed for rendering and managing child Components of
7001 * {@link Ext.form.FormPanel forms}. It is responsible for rendering the labels of
7002 * {@link Ext.form.Field Field}s.</p>
7004 * <p>This layout manager is used when a Container is configured with the <tt>layout:'form'</tt>
7005 * {@link Ext.Container#layout layout} config option, and should generally not need to be created directly
7006 * via the new keyword. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
7008 * <p>In an application, it will usually be preferrable to use a {@link Ext.form.FormPanel FormPanel}
7009 * (which is configured with FormLayout as its layout class by default) since it also provides built-in
7010 * functionality for {@link Ext.form.BasicForm#doAction loading, validating and submitting} the form.</p>
7012 * <p>A {@link Ext.Container Container} <i>using</i> the FormLayout layout manager (e.g.
7013 * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>) can also accept the following
7014 * layout-specific config properties:<div class="mdetail-params"><ul>
7015 * <li><b><tt>{@link Ext.form.FormPanel#hideLabels hideLabels}</tt></b></li>
7016 * <li><b><tt>{@link Ext.form.FormPanel#labelAlign labelAlign}</tt></b></li>
7017 * <li><b><tt>{@link Ext.form.FormPanel#labelPad labelPad}</tt></b></li>
7018 * <li><b><tt>{@link Ext.form.FormPanel#labelSeparator labelSeparator}</tt></b></li>
7019 * <li><b><tt>{@link Ext.form.FormPanel#labelWidth labelWidth}</tt></b></li>
7022 * <p>Any Component (including Fields) managed by FormLayout accepts the following as a config option:
7023 * <div class="mdetail-params"><ul>
7024 * <li><b><tt>{@link Ext.Component#anchor anchor}</tt></b></li>
7027 * <p>Any Component managed by FormLayout may be rendered as a form field (with an associated label) by
7028 * configuring it with a non-null <b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b>. Components configured
7029 * in this way may be configured with the following options which affect the way the FormLayout renders them:
7030 * <div class="mdetail-params"><ul>
7031 * <li><b><tt>{@link Ext.Component#clearCls clearCls}</tt></b></li>
7032 * <li><b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b></li>
7033 * <li><b><tt>{@link Ext.Component#hideLabel hideLabel}</tt></b></li>
7034 * <li><b><tt>{@link Ext.Component#itemCls itemCls}</tt></b></li>
7035 * <li><b><tt>{@link Ext.Component#labelSeparator labelSeparator}</tt></b></li>
7036 * <li><b><tt>{@link Ext.Component#labelStyle labelStyle}</tt></b></li>
7039 * <p>Example usage:</p>
7041 // Required if showing validation messages
7042 Ext.QuickTips.init();
7044 // While you can create a basic Panel with layout:'form', practically
7045 // you should usually use a FormPanel to also get its form functionality
7046 // since it already creates a FormLayout internally.
7047 var form = new Ext.form.FormPanel({
7048 title: 'Form Layout',
7049 bodyStyle: 'padding:15px',
7051 defaultType: 'textfield',
7053 // applied to each contained item
7058 fieldLabel: 'First Name',
7061 {@link Ext.Component#labelSeparator labelSeparator}: ':' // override labelSeparator layout config
7063 fieldLabel: 'Last Name',
7066 fieldLabel: 'Email',
7071 hideLabel: true, // override hideLabels layout config
7081 {@link #labelSeparator}: '~' // superseded by assignment below
7083 // config options applicable to container when layout='form':
7085 labelAlign: 'left', // or 'right' or 'top'
7086 {@link Ext.form.FormPanel#labelSeparator labelSeparator}: '>>', // takes precedence over layoutConfig value
7087 labelWidth: 65, // defaults to 100
7088 labelPad: 8 // defaults to 5, must specify labelWidth to be honored
7092 Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, {
7095 * @cfg {String} labelSeparator
7096 * See {@link Ext.form.FormPanel}.{@link Ext.form.FormPanel#labelSeparator labelSeparator}. Configuration
7097 * of this property at the <b>container</b> level takes precedence.
7099 labelSeparator : ':',
7102 * Read only. The CSS style specification string added to field labels in this layout if not
7103 * otherwise {@link Ext.Component#labelStyle specified by each contained field}.
7105 * @property labelStyle
7109 * @cfg {Boolean} trackLabels
7110 * True to show/hide the field label when the field is hidden. Defaults to <tt>true</tt>.
7116 onRemove: function(c){
7117 Ext.layout.FormLayout.superclass.onRemove.call(this, c);
7118 if(this.trackLabels){
7119 c.un('show', this.onFieldShow, this);
7120 c.un('hide', this.onFieldHide, this);
7122 // check for itemCt, since we may be removing a fieldset or something similar
7123 var el = c.getPositionEl(),
7124 ct = c.getItemCt && c.getItemCt();
7125 if (c.rendered && ct) {
7130 Ext.destroyMembers(c, 'label', 'itemCt');
7131 if (c.customItemCt) {
7132 Ext.destroyMembers(c, 'getItemCt', 'customItemCt');
7138 setContainer : function(ct){
7139 Ext.layout.FormLayout.superclass.setContainer.call(this, ct);
7141 ct.addClass('x-form-label-'+ct.labelAlign);
7146 labelStyle: 'display:none',
7147 elementStyle: 'padding-left:0;',
7151 this.labelSeparator = Ext.isDefined(ct.labelSeparator) ? ct.labelSeparator : this.labelSeparator;
7152 ct.labelWidth = ct.labelWidth || 100;
7153 if(Ext.isNumber(ct.labelWidth)){
7154 var pad = Ext.isNumber(ct.labelPad) ? ct.labelPad : 5;
7156 labelAdjust: ct.labelWidth + pad,
7157 labelStyle: 'width:' + ct.labelWidth + 'px;',
7158 elementStyle: 'padding-left:' + (ct.labelWidth + pad) + 'px'
7161 if(ct.labelAlign == 'top'){
7163 labelStyle: 'width:auto;',
7165 elementStyle: 'padding-left:0;'
7172 isHide: function(c){
7173 return c.hideLabel || this.container.hideLabels;
7176 onFieldShow: function(c){
7177 c.getItemCt().removeClass('x-hide-' + c.hideMode);
7179 // Composite fields will need to layout after the container is made visible
7180 if (c.isComposite) {
7185 onFieldHide: function(c){
7186 c.getItemCt().addClass('x-hide-' + c.hideMode);
7190 getLabelStyle: function(s){
7191 var ls = '', items = [this.labelStyle, s];
7192 for (var i = 0, len = items.length; i < len; ++i){
7195 if (ls.substr(-1, 1) != ';'){
7204 * @cfg {Ext.Template} fieldTpl
7205 * A {@link Ext.Template#compile compile}d {@link Ext.Template} for rendering
7206 * the fully wrapped, labeled and styled form Field. Defaults to:</p><pre><code>
7208 '<div class="x-form-item {itemCls}" tabIndex="-1">',
7209 '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{labelSeparator}</label>',
7210 '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
7211 '</div><div class="{clearCls}"></div>',
7215 * <p>This may be specified to produce a different DOM structure when rendering form Fields.</p>
7216 * <p>A description of the properties within the template follows:</p><div class="mdetail-params"><ul>
7217 * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper
7218 * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt>
7219 * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt>
7220 * supplied at the container level.</div></li>
7221 * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li>
7222 * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc">
7223 * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the
7224 * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li>
7225 * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this
7226 * field (defaults to <tt>''</tt>)</div></li>
7227 * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after
7228 * the text of the label for this field (defaults to a colon <tt>':'</tt> or the
7229 * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li>
7230 * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li>
7231 * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div
7232 * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li>
7234 * <p>Also see <tt>{@link #getTemplateArgs}</tt></p>
7241 renderItem : function(c, position, target){
7242 if(c && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){
7243 var args = this.getTemplateArgs(c);
7244 if(Ext.isNumber(position)){
7245 position = target.dom.childNodes[position] || null;
7248 c.itemCt = this.fieldTpl.insertBefore(position, args, true);
7250 c.itemCt = this.fieldTpl.append(target, args, true);
7253 // Non form fields don't have getItemCt, apply it here
7254 // This will get cleaned up in onRemove
7256 getItemCt: function(){
7262 c.label = c.getItemCt().child('label.x-form-item-label');
7264 c.render('x-form-el-' + c.id);
7265 }else if(!this.isValidParent(c, target)){
7266 Ext.fly('x-form-el-' + c.id).appendChild(c.getPositionEl());
7268 if(this.trackLabels){
7270 this.onFieldHide(c);
7274 show: this.onFieldShow,
7275 hide: this.onFieldHide
7278 this.configureItem(c);
7280 Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments);
7285 * <p>Provides template arguments for rendering the fully wrapped, labeled and styled form Field.</p>
7286 * <p>This method returns an object hash containing properties used by the layout's {@link #fieldTpl}
7287 * to create a correctly wrapped, labeled and styled form Field. This may be overriden to
7288 * create custom layouts. The properties which must be returned are:</p><div class="mdetail-params"><ul>
7289 * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper
7290 * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt>
7291 * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt>
7292 * supplied at the container level.</div></li>
7293 * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li>
7294 * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc">
7295 * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the
7296 * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li>
7297 * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this
7298 * field (defaults to the field's configured fieldLabel property)</div></li>
7299 * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after
7300 * the text of the label for this field (defaults to a colon <tt>':'</tt> or the
7301 * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li>
7302 * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li>
7303 * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div
7304 * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li>
7306 * @param (Ext.form.Field} field The {@link Ext.form.Field Field} being rendered.
7307 * @return {Object} An object hash containing the properties required to render the Field.
7309 getTemplateArgs: function(field) {
7310 var noLabelSep = !field.fieldLabel || field.hideLabel;
7314 label : field.fieldLabel,
7315 itemCls : (field.itemCls || this.container.itemCls || '') + (field.hideLabel ? ' x-hide-label' : ''),
7316 clearCls : field.clearCls || 'x-form-clear-left',
7317 labelStyle : this.getLabelStyle(field.labelStyle),
7318 elementStyle : this.elementStyle || '',
7319 labelSeparator: noLabelSep ? '' : (Ext.isDefined(field.labelSeparator) ? field.labelSeparator : this.labelSeparator)
7324 adjustWidthAnchor: function(value, c){
7325 if(c.label && !this.isHide(c) && (this.container.labelAlign != 'top')){
7326 var adjust = Ext.isIE6 || (Ext.isIE && !Ext.isStrict);
7327 return value - this.labelAdjust + (adjust ? -3 : 0);
7332 adjustHeightAnchor : function(value, c){
7333 if(c.label && !this.isHide(c) && (this.container.labelAlign == 'top')){
7334 return value - c.label.getHeight();
7340 isValidParent : function(c, target){
7341 return target && this.container.getEl().contains(c.getPositionEl());
7345 * @property activeItem
7350 Ext.Container.LAYOUTS['form'] = Ext.layout.FormLayout;
7352 * @class Ext.layout.AccordionLayout
7353 * @extends Ext.layout.FitLayout
7354 * <p>This is a layout that manages multiple Panels in an expandable accordion style such that only
7355 * <b>one Panel can be expanded at any given time</b>. Each Panel has built-in support for expanding and collapsing.</p>
7356 * <p>Note: Only Ext.Panels <b>and all subclasses of Ext.Panel</b> may be used in an accordion layout Container.</p>
7357 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
7358 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
7359 * <p>Example usage:</p>
7361 var accordion = new Ext.Panel({
7362 title: 'Accordion Layout',
7365 // applied to each contained panel
7366 bodyStyle: 'padding:15px'
7369 // layout-specific configs go here
7370 titleCollapse: false,
7376 html: '<p>Panel content!</p>'
7379 html: '<p>Panel content!</p>'
7382 html: '<p>Panel content!</p>'
7387 Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, {
7389 * @cfg {Boolean} fill
7390 * True to adjust the active item's height to fill the available space in the container, false to use the
7391 * item's current height, or auto height if not explicitly set (defaults to true).
7395 * @cfg {Boolean} autoWidth
7396 * True to set each contained item's width to 'auto', false to use the item's current width (defaults to true).
7397 * Note that some components, in particular the {@link Ext.grid.GridPanel grid}, will not function properly within
7398 * layouts if they have auto width, so in such cases this config should be set to false.
7402 * @cfg {Boolean} titleCollapse
7403 * True to allow expand/collapse of each contained panel by clicking anywhere on the title bar, false to allow
7404 * expand/collapse only when the toggle tool button is clicked (defaults to true). When set to false,
7405 * {@link #hideCollapseTool} should be false also.
7407 titleCollapse : true,
7409 * @cfg {Boolean} hideCollapseTool
7410 * True to hide the contained panels' collapse/expand toggle buttons, false to display them (defaults to false).
7411 * When set to true, {@link #titleCollapse} should be true also.
7413 hideCollapseTool : false,
7415 * @cfg {Boolean} collapseFirst
7416 * True to make sure the collapse/expand toggle button always renders first (to the left of) any other tools
7417 * in the contained panels' title bars, false to render it last (defaults to false).
7419 collapseFirst : false,
7421 * @cfg {Boolean} animate
7422 * True to slide the contained panels open and closed during expand/collapse using animation, false to open and
7423 * close directly with no animation (defaults to false). Note: to defer to the specific config setting of each
7424 * contained panel for this property, set this to undefined at the layout level.
7428 * @cfg {Boolean} sequence
7429 * <b>Experimental</b>. If animate is set to true, this will result in each animation running in sequence.
7433 * @cfg {Boolean} activeOnTop
7434 * True to swap the position of each panel as it is expanded so that it becomes the first item in the container,
7435 * false to keep the panels in the rendered order. <b>This is NOT compatible with "animate:true"</b> (defaults to false).
7437 activeOnTop : false,
7441 renderItem : function(c){
7442 if(this.animate === false){
7443 c.animCollapse = false;
7445 c.collapsible = true;
7449 if(this.titleCollapse){
7450 c.titleCollapse = true;
7452 if(this.hideCollapseTool){
7453 c.hideCollapseTool = true;
7455 if(this.collapseFirst !== undefined){
7456 c.collapseFirst = this.collapseFirst;
7458 if(!this.activeItem && !c.collapsed){
7459 this.setActiveItem(c, true);
7460 }else if(this.activeItem && this.activeItem != c){
7463 Ext.layout.AccordionLayout.superclass.renderItem.apply(this, arguments);
7464 c.header.addClass('x-accordion-hd');
7465 c.on('beforeexpand', this.beforeExpand, this);
7468 onRemove: function(c){
7469 Ext.layout.AccordionLayout.superclass.onRemove.call(this, c);
7471 c.header.removeClass('x-accordion-hd');
7473 c.un('beforeexpand', this.beforeExpand, this);
7477 beforeExpand : function(p, anim){
7478 var ai = this.activeItem;
7481 delete this.activeItem;
7483 ai.collapse({callback:function(){
7484 p.expand(anim || true);
7489 ai.collapse(this.animate);
7493 if(this.activeOnTop){
7494 p.el.dom.parentNode.insertBefore(p.el.dom, p.el.dom.parentNode.firstChild);
7496 // Items have been hidden an possibly rearranged, we need to get the container size again.
7501 setItemSize : function(item, size){
7502 if(this.fill && item){
7503 var hh = 0, i, ct = this.getRenderedItems(this.container), len = ct.length, p;
7504 // Add up all the header heights
7505 for (i = 0; i < len; i++) {
7506 if((p = ct[i]) != item && !p.hidden){
7507 hh += p.header.getHeight();
7510 // Subtract the header heights from the container size
7512 // Call setSize on the container to set the correct height. For Panels, deferedHeight
7513 // will simply store this size for when the expansion is done.
7519 * Sets the active (expanded) item in the layout.
7520 * @param {String/Number} item The string component id or numeric index of the item to activate
7522 setActiveItem : function(item){
7523 this.setActive(item, true);
7527 setActive : function(item, expand){
7528 var ai = this.activeItem;
7529 item = this.container.getComponent(item);
7531 if(item.rendered && item.collapsed && expand){
7535 ai.fireEvent('deactivate', ai);
7537 this.activeItem = item;
7538 item.fireEvent('activate', item);
7543 Ext.Container.LAYOUTS.accordion = Ext.layout.AccordionLayout;
7546 Ext.layout.Accordion = Ext.layout.AccordionLayout;/**
7547 * @class Ext.layout.TableLayout
7548 * @extends Ext.layout.ContainerLayout
7549 * <p>This layout allows you to easily render content into an HTML table. The total number of columns can be
7550 * specified, and rowspan and colspan can be used to create complex layouts within the table.
7551 * This class is intended to be extended or created via the layout:'table' {@link Ext.Container#layout} config,
7552 * and should generally not need to be created directly via the new keyword.</p>
7553 * <p>Note that when creating a layout via config, the layout-specific config properties must be passed in via
7554 * the {@link Ext.Container#layoutConfig} object which will then be applied internally to the layout. In the
7555 * case of TableLayout, the only valid layout config property is {@link #columns}. However, the items added to a
7556 * TableLayout can supply the following table-specific config properties:</p>
7558 * <li><b>rowspan</b> Applied to the table cell containing the item.</li>
7559 * <li><b>colspan</b> Applied to the table cell containing the item.</li>
7560 * <li><b>cellId</b> An id applied to the table cell containing the item.</li>
7561 * <li><b>cellCls</b> A CSS class name added to the table cell containing the item.</li>
7563 * <p>The basic concept of building up a TableLayout is conceptually very similar to building up a standard
7564 * HTML table. You simply add each panel (or "cell") that you want to include along with any span attributes
7565 * specified as the special config properties of rowspan and colspan which work exactly like their HTML counterparts.
7566 * Rather than explicitly creating and nesting rows and columns as you would in HTML, you simply specify the
7567 * total column count in the layoutConfig and start adding panels in their natural order from left to right,
7568 * top to bottom. The layout will automatically figure out, based on the column count, rowspans and colspans,
7569 * how to position each panel within the table. Just like with HTML tables, your rowspans and colspans must add
7570 * up correctly in your overall layout or you'll end up with missing and/or extra cells! Example usage:</p>
7572 // This code will generate a layout table that is 3 columns by 2 rows
7573 // with some spanning included. The basic layout will be:
7574 // +--------+-----------------+
7576 // | |--------+--------|
7578 // +--------+--------+--------+
7579 var table = new Ext.Panel({
7580 title: 'Table Layout',
7583 // applied to each contained panel
7584 bodyStyle:'padding:20px'
7587 // The total column count must be specified here
7591 html: '<p>Cell A content</p>',
7594 html: '<p>Cell B content</p>',
7597 html: '<p>Cell C content</p>',
7598 cellCls: 'highlight'
7600 html: '<p>Cell D content</p>'
7605 Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, {
7607 * @cfg {Number} columns
7608 * The total number of columns to create in the table for this layout. If not specified, all Components added to
7609 * this layout will be rendered into a single row using one column per Component.
7613 monitorResize:false,
7617 targetCls: 'x-table-layout-ct',
7620 * @cfg {Object} tableAttrs
7621 * <p>An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification
7622 * used to create the layout's <tt><table></tt> element. Example:</p><pre><code>
7639 setContainer : function(ct){
7640 Ext.layout.TableLayout.superclass.setContainer.call(this, ct);
7642 this.currentRow = 0;
7643 this.currentColumn = 0;
7648 onLayout : function(ct, target){
7649 var cs = ct.items.items, len = cs.length, c, i;
7652 target.addClass('x-table-layout-ct');
7654 this.table = target.createChild(
7655 Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true);
7657 this.renderAll(ct, target);
7661 getRow : function(index){
7662 var row = this.table.tBodies[0].childNodes[index];
7664 row = document.createElement('tr');
7665 this.table.tBodies[0].appendChild(row);
7671 getNextCell : function(c){
7672 var cell = this.getNextNonSpan(this.currentColumn, this.currentRow);
7673 var curCol = this.currentColumn = cell[0], curRow = this.currentRow = cell[1];
7674 for(var rowIndex = curRow; rowIndex < curRow + (c.rowspan || 1); rowIndex++){
7675 if(!this.cells[rowIndex]){
7676 this.cells[rowIndex] = [];
7678 for(var colIndex = curCol; colIndex < curCol + (c.colspan || 1); colIndex++){
7679 this.cells[rowIndex][colIndex] = true;
7682 var td = document.createElement('td');
7686 var cls = 'x-table-layout-cell';
7688 cls += ' ' + c.cellCls;
7692 td.colSpan = c.colspan;
7695 td.rowSpan = c.rowspan;
7697 this.getRow(curRow).appendChild(td);
7702 getNextNonSpan: function(colIndex, rowIndex){
7703 var cols = this.columns;
7704 while((cols && colIndex >= cols) || (this.cells[rowIndex] && this.cells[rowIndex][colIndex])) {
7705 if(cols && colIndex >= cols){
7712 return [colIndex, rowIndex];
7716 renderItem : function(c, position, target){
7717 // Ensure we have our inner table to get cells to render into.
7719 this.table = target.createChild(
7720 Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true);
7722 if(c && !c.rendered){
7723 c.render(this.getNextCell(c));
7724 this.configureItem(c);
7725 }else if(c && !this.isValidParent(c, target)){
7726 var container = this.getNextCell(c);
7727 container.insertBefore(c.getPositionEl().dom, null);
7728 c.container = Ext.get(container);
7729 this.configureItem(c);
7734 isValidParent : function(c, target){
7735 return c.getPositionEl().up('table', 5).dom.parentNode === (target.dom || target);
7738 destroy: function(){
7740 Ext.layout.TableLayout.superclass.destroy.call(this);
7744 * @property activeItem
7749 Ext.Container.LAYOUTS['table'] = Ext.layout.TableLayout;/**
7750 * @class Ext.layout.AbsoluteLayout
7751 * @extends Ext.layout.AnchorLayout
7752 * <p>This is a layout that inherits the anchoring of <b>{@link Ext.layout.AnchorLayout}</b> and adds the
7753 * ability for x/y positioning using the standard x and y component config options.</p>
7754 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
7755 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
7756 * <p>Example usage:</p>
7758 var form = new Ext.form.FormPanel({
7759 title: 'Absolute Layout',
7762 // layout-specific configs go here
7763 extraCls: 'x-abs-layout-item',
7766 url:'save-form.php',
7767 defaultType: 'textfield',
7777 anchor:'100%' // anchor width by percentage
7787 anchor: '100%' // anchor width by percentage
7793 anchor: '100% 100%' // anchor width and height
7798 Ext.layout.AbsoluteLayout = Ext.extend(Ext.layout.AnchorLayout, {
7800 extraCls: 'x-abs-layout-item',
7804 onLayout : function(ct, target){
7806 this.paddingLeft = target.getPadding('l');
7807 this.paddingTop = target.getPadding('t');
7808 Ext.layout.AbsoluteLayout.superclass.onLayout.call(this, ct, target);
7812 adjustWidthAnchor : function(value, comp){
7813 return value ? value - comp.getPosition(true)[0] + this.paddingLeft : value;
7817 adjustHeightAnchor : function(value, comp){
7818 return value ? value - comp.getPosition(true)[1] + this.paddingTop : value;
7821 * @property activeItem
7825 Ext.Container.LAYOUTS['absolute'] = Ext.layout.AbsoluteLayout;
7827 * @class Ext.layout.BoxLayout
7828 * @extends Ext.layout.ContainerLayout
7829 * <p>Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.</p>
7831 Ext.layout.BoxLayout = Ext.extend(Ext.layout.ContainerLayout, {
7833 * @cfg {Object} defaultMargins
7834 * <p>If the individual contained items do not have a <tt>margins</tt>
7835 * property specified, the default margins from this property will be
7836 * applied to each item.</p>
7837 * <br><p>This property may be specified as an object containing margins
7838 * to apply in the format:</p><pre><code>
7841 right: (right margin),
7842 bottom: (bottom margin),
7845 * <p>This property may also be specified as a string containing
7846 * space-separated, numeric margin values. The order of the sides associated
7847 * with each value matches the way CSS processes margin values:</p>
7848 * <div class="mdetail-params"><ul>
7849 * <li>If there is only one value, it applies to all sides.</li>
7850 * <li>If there are two values, the top and bottom borders are set to the
7851 * first value and the right and left are set to the second.</li>
7852 * <li>If there are three values, the top is set to the first value, the left
7853 * and right are set to the second, and the bottom is set to the third.</li>
7854 * <li>If there are four values, they apply to the top, right, bottom, and
7855 * left, respectively.</li>
7857 * <p>Defaults to:</p><pre><code>
7858 * {top:0, right:0, bottom:0, left:0}
7861 defaultMargins : {left:0,top:0,right:0,bottom:0},
7863 * @cfg {String} padding
7864 * <p>Sets the padding to be applied to all child items managed by this layout.</p>
7865 * <p>This property must be specified as a string containing
7866 * space-separated, numeric padding values. The order of the sides associated
7867 * with each value matches the way CSS processes padding values:</p>
7868 * <div class="mdetail-params"><ul>
7869 * <li>If there is only one value, it applies to all sides.</li>
7870 * <li>If there are two values, the top and bottom borders are set to the
7871 * first value and the right and left are set to the second.</li>
7872 * <li>If there are three values, the top is set to the first value, the left
7873 * and right are set to the second, and the bottom is set to the third.</li>
7874 * <li>If there are four values, they apply to the top, right, bottom, and
7875 * left, respectively.</li>
7877 * <p>Defaults to: <code>"0"</code></p>
7880 // documented in subclasses
7884 monitorResize : true,
7887 extraCls : 'x-box-item',
7888 targetCls : 'x-box-layout-ct',
7889 innerCls : 'x-box-inner',
7891 constructor : function(config){
7892 Ext.layout.BoxLayout.superclass.constructor.call(this, config);
7894 if (Ext.isString(this.defaultMargins)) {
7895 this.defaultMargins = this.parseMargins(this.defaultMargins);
7898 var handler = this.overflowHandler;
7900 if (typeof handler == 'string') {
7906 var handlerType = 'none';
7907 if (handler && handler.type != undefined) {
7908 handlerType = handler.type;
7911 var constructor = Ext.layout.boxOverflow[handlerType];
7912 if (constructor[this.type]) {
7913 constructor = constructor[this.type];
7916 this.overflowHandler = new constructor(this, handler);
7921 * Runs the child box calculations and caches them in childBoxCache. Subclasses can used these cached values
7924 onLayout: function(container, target) {
7925 Ext.layout.BoxLayout.superclass.onLayout.call(this, container, target);
7927 var tSize = this.getLayoutTargetSize(),
7928 items = this.getVisibleItems(container),
7929 calcs = this.calculateChildBoxes(items, tSize),
7930 boxes = calcs.boxes,
7933 //invoke the overflow handler, if one is configured
7934 if (tSize.width > 0) {
7935 var handler = this.overflowHandler,
7936 method = meta.tooNarrow ? 'handleOverflow' : 'clearOverflow';
7938 var results = handler[method](calcs, tSize);
7941 if (results.targetSize) {
7942 tSize = results.targetSize;
7945 if (results.recalculate) {
7946 items = this.getVisibleItems(container);
7947 calcs = this.calculateChildBoxes(items, tSize);
7948 boxes = calcs.boxes;
7955 * @property layoutTargetLastSize
7957 * Private cache of the last measured size of the layout target. This should never be used except by
7958 * BoxLayout subclasses during their onLayout run.
7960 this.layoutTargetLastSize = tSize;
7964 * @property childBoxCache
7966 * Array of the last calculated height, width, top and left positions of each visible rendered component
7967 * within the Box layout.
7969 this.childBoxCache = calcs;
7971 this.updateInnerCtSize(tSize, calcs);
7972 this.updateChildBoxes(boxes);
7974 // Putting a box layout into an overflowed container is NOT correct and will make a second layout pass necessary.
7975 this.handleTargetOverflow(tSize, container, target);
7979 * Resizes and repositions each child component
7980 * @param {Array} boxes The box measurements
7982 updateChildBoxes: function(boxes) {
7983 for (var i = 0, length = boxes.length; i < length; i++) {
7985 comp = box.component;
7987 if (box.dirtySize) {
7988 comp.setSize(box.width, box.height);
7990 // Don't set positions to NaN
7991 if (isNaN(box.left) || isNaN(box.top)) {
7995 comp.setPosition(box.left, box.top);
8001 * Called by onRender just before the child components are sized and positioned. This resizes the innerCt
8002 * to make sure all child items fit within it. We call this before sizing the children because if our child
8003 * items are larger than the previous innerCt size the browser will insert scrollbars and then remove them
8004 * again immediately afterwards, giving a performance hit.
8005 * Subclasses should provide an implementation.
8006 * @param {Object} currentSize The current height and width of the innerCt
8007 * @param {Array} calculations The new box calculations of all items to be laid out
8009 updateInnerCtSize: function(tSize, calcs) {
8010 var align = this.align,
8011 padding = this.padding,
8012 width = tSize.width,
8013 height = tSize.height;
8015 if (this.type == 'hbox') {
8016 var innerCtWidth = width,
8017 innerCtHeight = calcs.meta.maxHeight + padding.top + padding.bottom;
8019 if (align == 'stretch') {
8020 innerCtHeight = height;
8021 } else if (align == 'middle') {
8022 innerCtHeight = Math.max(height, innerCtHeight);
8025 var innerCtHeight = height,
8026 innerCtWidth = calcs.meta.maxWidth + padding.left + padding.right;
8028 if (align == 'stretch') {
8029 innerCtWidth = width;
8030 } else if (align == 'center') {
8031 innerCtWidth = Math.max(width, innerCtWidth);
8035 this.innerCt.setSize(innerCtWidth || undefined, innerCtHeight || undefined);
8040 * This should be called after onLayout of any BoxLayout subclass. If the target's overflow is not set to 'hidden',
8041 * we need to lay out a second time because the scrollbars may have modified the height and width of the layout
8042 * target. Having a Box layout inside such a target is therefore not recommended.
8043 * @param {Object} previousTargetSize The size and height of the layout target before we just laid out
8044 * @param {Ext.Container} container The container
8045 * @param {Ext.Element} target The target element
8047 handleTargetOverflow: function(previousTargetSize, container, target) {
8048 var overflow = target.getStyle('overflow');
8050 if (overflow && overflow != 'hidden' &&!this.adjustmentPass) {
8051 var newTargetSize = this.getLayoutTargetSize();
8052 if (newTargetSize.width != previousTargetSize.width || newTargetSize.height != previousTargetSize.height){
8053 this.adjustmentPass = true;
8054 this.onLayout(container, target);
8058 delete this.adjustmentPass;
8062 isValidParent : function(c, target) {
8063 return this.innerCt && c.getPositionEl().dom.parentNode == this.innerCt.dom;
8068 * Returns all items that are both rendered and visible
8069 * @return {Array} All matching items
8071 getVisibleItems: function(ct) {
8072 var ct = ct || this.container,
8073 t = ct.getLayoutTarget(),
8074 cti = ct.items.items,
8079 for (i = 0; i < len; i++) {
8080 if((c = cti[i]).rendered && this.isValidParent(c, t) && c.hidden !== true && c.collapsed !== true && c.shouldLayout !== false){
8089 renderAll : function(ct, target) {
8090 if (!this.innerCt) {
8091 // the innerCt prevents wrapping and shuffling while the container is resizing
8092 this.innerCt = target.createChild({cls:this.innerCls});
8093 this.padding = this.parseMargins(this.padding);
8095 Ext.layout.BoxLayout.superclass.renderAll.call(this, ct, this.innerCt);
8098 getLayoutTargetSize : function() {
8099 var target = this.container.getLayoutTarget(), ret;
8102 ret = target.getViewSize();
8104 // IE in strict mode will return a width of 0 on the 1st pass of getViewSize.
8105 // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly
8107 if (Ext.isIE && Ext.isStrict && ret.width == 0){
8108 ret = target.getStyleSize();
8111 ret.width -= target.getPadding('lr');
8112 ret.height -= target.getPadding('tb');
8119 renderItem : function(c) {
8120 if(Ext.isString(c.margins)){
8121 c.margins = this.parseMargins(c.margins);
8122 }else if(!c.margins){
8123 c.margins = this.defaultMargins;
8125 Ext.layout.BoxLayout.superclass.renderItem.apply(this, arguments);
8131 destroy: function() {
8132 Ext.destroy(this.overflowHandler);
8134 Ext.layout.BoxLayout.superclass.destroy.apply(this, arguments);
8140 Ext.ns('Ext.layout.boxOverflow');
8143 * @class Ext.layout.boxOverflow.None
8145 * Base class for Box Layout overflow handlers. These specialized classes are invoked when a Box Layout
8146 * (either an HBox or a VBox) has child items that are either too wide (for HBox) or too tall (for VBox)
8147 * for its container.
8150 Ext.layout.boxOverflow.None = Ext.extend(Object, {
8151 constructor: function(layout, config) {
8152 this.layout = layout;
8154 Ext.apply(this, config || {});
8157 handleOverflow: Ext.emptyFn,
8159 clearOverflow: Ext.emptyFn
8163 Ext.layout.boxOverflow.none = Ext.layout.boxOverflow.None;
8165 * @class Ext.layout.boxOverflow.Menu
8166 * @extends Ext.layout.boxOverflow.None
8169 Ext.layout.boxOverflow.Menu = Ext.extend(Ext.layout.boxOverflow.None, {
8173 * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers,
8174 * which must always be present at the rightmost edge of the Container
8176 afterCls: 'x-strip-right',
8179 * @property noItemsMenuText
8181 * HTML fragment to render into the toolbar overflow menu if there are no items to display
8183 noItemsMenuText : '<div class="x-toolbar-no-items">(None)</div>',
8185 constructor: function(layout) {
8186 Ext.layout.boxOverflow.Menu.superclass.constructor.apply(this, arguments);
8189 * @property menuItems
8191 * Array of all items that are currently hidden and should go into the dropdown menu
8193 this.menuItems = [];
8198 * Creates the beforeCt, innerCt and afterCt elements if they have not already been created
8199 * @param {Ext.Container} container The Container attached to this Layout instance
8200 * @param {Ext.Element} target The target Element
8202 createInnerElements: function() {
8203 if (!this.afterCt) {
8204 this.afterCt = this.layout.innerCt.insertSibling({cls: this.afterCls}, 'before');
8211 clearOverflow: function(calculations, targetSize) {
8212 var newWidth = targetSize.width + (this.afterCt ? this.afterCt.getWidth() : 0),
8213 items = this.menuItems;
8217 for (var index = 0, length = items.length; index < length; index++) {
8218 items.pop().component.show();
8223 height: targetSize.height,
8232 showTrigger: function() {
8234 this.menuTrigger.show();
8240 hideTrigger: function() {
8241 if (this.menuTrigger != undefined) {
8242 this.menuTrigger.hide();
8248 * Called before the overflow menu is shown. This constructs the menu's items, caching them for as long as it can.
8250 beforeMenuShow: function(menu) {
8251 var items = this.menuItems,
8256 var needsSep = function(group, item){
8257 return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator);
8263 for (var i = 0; i < len; i++) {
8264 item = items[i].component;
8266 if (prev && (needsSep(item, prev) || needsSep(prev, item))) {
8270 this.addComponentToMenu(menu, item);
8274 // put something so the menu isn't empty if no compatible items found
8275 if (menu.items.length < 1) {
8276 menu.add(this.noItemsMenuText);
8282 * Returns a menu config for a given component. This config is used to create a menu item
8283 * to be added to the expander menu
8284 * @param {Ext.Component} component The component to create the config for
8285 * @param {Boolean} hideOnClick Passed through to the menu item
8287 createMenuConfig : function(component, hideOnClick){
8288 var config = Ext.apply({}, component.initialConfig),
8289 group = component.toggleGroup;
8291 Ext.copyTo(config, component, [
8292 'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu'
8296 text : component.overflowText || component.text,
8297 hideOnClick: hideOnClick
8300 if (group || component.enableToggle) {
8303 checked: component.pressed,
8305 checkchange: function(item, checked){
8306 component.toggle(checked);
8312 delete config.ownerCt;
8313 delete config.xtype;
8321 * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually.
8322 * @param {Ext.menu.Menu} menu The menu to add to
8323 * @param {Ext.Component} component The component to add
8325 addComponentToMenu : function(menu, component) {
8326 if (component instanceof Ext.Toolbar.Separator) {
8329 } else if (Ext.isFunction(component.isXType)) {
8330 if (component.isXType('splitbutton')) {
8331 menu.add(this.createMenuConfig(component, true));
8333 } else if (component.isXType('button')) {
8334 menu.add(this.createMenuConfig(component, !component.menu));
8336 } else if (component.isXType('buttongroup')) {
8337 component.items.each(function(item){
8338 this.addComponentToMenu(menu, item);
8346 * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as
8347 * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item
8349 clearMenu : function(){
8350 var menu = this.moreMenu;
8351 if (menu && menu.items) {
8352 menu.items.each(function(item){
8360 * Creates the overflow trigger and menu used when enableOverflow is set to true and the items
8361 * in the layout are too wide to fit in the space available
8363 createMenu: function() {
8364 if (!this.menuTrigger) {
8365 this.createInnerElements();
8370 * @type Ext.menu.Menu
8371 * The expand menu - holds items for every item that cannot be shown
8372 * because the container is currently not large enough.
8374 this.menu = new Ext.menu.Menu({
8375 ownerCt : this.layout.container,
8378 beforeshow: this.beforeMenuShow
8384 * @property menuTrigger
8386 * The expand button which triggers the overflow menu to be shown
8388 this.menuTrigger = new Ext.Button({
8389 iconCls : 'x-toolbar-more-icon',
8390 cls : 'x-toolbar-more',
8392 renderTo: this.afterCt
8400 destroy: function() {
8401 Ext.destroy(this.menu, this.menuTrigger);
8405 Ext.layout.boxOverflow.menu = Ext.layout.boxOverflow.Menu;
8409 * @class Ext.layout.boxOverflow.HorizontalMenu
8410 * @extends Ext.layout.boxOverflow.Menu
8413 Ext.layout.boxOverflow.HorizontalMenu = Ext.extend(Ext.layout.boxOverflow.Menu, {
8415 constructor: function() {
8416 Ext.layout.boxOverflow.HorizontalMenu.superclass.constructor.apply(this, arguments);
8420 origFunction = layout.calculateChildBoxes;
8422 layout.calculateChildBoxes = function(visibleItems, targetSize) {
8423 var calcs = origFunction.apply(layout, arguments),
8425 items = me.menuItems;
8427 //calculate the width of the items currently hidden solely because there is not enough space
8429 var hiddenWidth = 0;
8430 for (var index = 0, length = items.length; index < length; index++) {
8431 hiddenWidth += items[index].width;
8434 meta.minimumWidth += hiddenWidth;
8435 meta.tooNarrow = meta.minimumWidth > targetSize.width;
8441 handleOverflow: function(calculations, targetSize) {
8444 var newWidth = targetSize.width - this.afterCt.getWidth(),
8445 boxes = calculations.boxes,
8447 recalculate = false;
8449 //calculate the width of all visible items and any spare width
8450 for (var index = 0, length = boxes.length; index < length; index++) {
8451 usedWidth += boxes[index].width;
8454 var spareWidth = newWidth - usedWidth,
8457 //see if we can re-show any of the hidden components
8458 for (var index = 0, length = this.menuItems.length; index < length; index++) {
8459 var hidden = this.menuItems[index],
8460 comp = hidden.component,
8461 width = hidden.width;
8463 if (width < spareWidth) {
8466 spareWidth -= width;
8475 this.menuItems = this.menuItems.slice(showCount);
8477 for (var i = boxes.length - 1; i >= 0; i--) {
8478 var item = boxes[i].component,
8479 right = boxes[i].left + boxes[i].width;
8481 if (right >= newWidth) {
8482 this.menuItems.unshift({
8484 width : boxes[i].width
8494 if (this.menuItems.length == 0) {
8500 height: targetSize.height,
8503 recalculate: recalculate
8508 Ext.layout.boxOverflow.menu.hbox = Ext.layout.boxOverflow.HorizontalMenu;/**
8509 * @class Ext.layout.boxOverflow.Scroller
8510 * @extends Ext.layout.boxOverflow.None
8513 Ext.layout.boxOverflow.Scroller = Ext.extend(Ext.layout.boxOverflow.None, {
8515 * @cfg animateScroll
8517 * True to animate the scrolling of items within the layout (defaults to true, ignored if enableScroll is false)
8519 animateScroll: true,
8522 * @cfg scrollIncrement
8524 * The number of pixels to scroll by on scroller click (defaults to 100)
8526 scrollIncrement: 100,
8529 * @cfg wheelIncrement
8531 * The number of pixels to increment on mouse wheel scrolling (defaults to <tt>3</tt>).
8536 * @cfg scrollRepeatInterval
8538 * Number of milliseconds between each scroll while a scroller button is held down (defaults to 400)
8540 scrollRepeatInterval: 400,
8543 * @cfg scrollDuration
8545 * Number of seconds that each scroll animation lasts (defaults to 0.4)
8547 scrollDuration: 0.4,
8552 * CSS class added to the beforeCt element. This is the element that holds any special items such as scrollers,
8553 * which must always be present at the leftmost edge of the Container
8555 beforeCls: 'x-strip-left',
8560 * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers,
8561 * which must always be present at the rightmost edge of the Container
8563 afterCls: 'x-strip-right',
8568 * CSS class added to both scroller elements if enableScroll is used
8570 scrollerCls: 'x-strip-scroller',
8573 * @cfg beforeScrollerCls
8575 * CSS class added to the left scroller element if enableScroll is used
8577 beforeScrollerCls: 'x-strip-scroller-left',
8580 * @cfg afterScrollerCls
8582 * CSS class added to the right scroller element if enableScroll is used
8584 afterScrollerCls: 'x-strip-scroller-right',
8588 * Sets up an listener to scroll on the layout's innerCt mousewheel event
8590 createWheelListener: function() {
8591 this.layout.innerCt.on({
8593 mousewheel: function(e) {
8596 this.scrollBy(e.getWheelDelta() * this.wheelIncrement * -1, false);
8603 * Most of the heavy lifting is done in the subclasses
8605 handleOverflow: function(calculations, targetSize) {
8606 this.createInnerElements();
8607 this.showScrollers();
8613 clearOverflow: function() {
8614 this.hideScrollers();
8619 * Shows the scroller elements in the beforeCt and afterCt. Creates the scrollers first if they are not already
8622 showScrollers: function() {
8623 this.createScrollers();
8625 this.beforeScroller.show();
8626 this.afterScroller.show();
8628 this.updateScrollButtons();
8633 * Hides the scroller elements in the beforeCt and afterCt
8635 hideScrollers: function() {
8636 if (this.beforeScroller != undefined) {
8637 this.beforeScroller.hide();
8638 this.afterScroller.hide();
8644 * Creates the clickable scroller elements and places them into the beforeCt and afterCt
8646 createScrollers: function() {
8647 if (!this.beforeScroller && !this.afterScroller) {
8648 var before = this.beforeCt.createChild({
8649 cls: String.format("{0} {1} ", this.scrollerCls, this.beforeScrollerCls)
8652 var after = this.afterCt.createChild({
8653 cls: String.format("{0} {1}", this.scrollerCls, this.afterScrollerCls)
8656 before.addClassOnOver(this.beforeScrollerCls + '-hover');
8657 after.addClassOnOver(this.afterScrollerCls + '-hover');
8659 before.setVisibilityMode(Ext.Element.DISPLAY);
8660 after.setVisibilityMode(Ext.Element.DISPLAY);
8662 this.beforeRepeater = new Ext.util.ClickRepeater(before, {
8663 interval: this.scrollRepeatInterval,
8664 handler : this.scrollLeft,
8668 this.afterRepeater = new Ext.util.ClickRepeater(after, {
8669 interval: this.scrollRepeatInterval,
8670 handler : this.scrollRight,
8675 * @property beforeScroller
8677 * The left scroller element. Only created when needed.
8679 this.beforeScroller = before;
8682 * @property afterScroller
8684 * The left scroller element. Only created when needed.
8686 this.afterScroller = after;
8693 destroy: function() {
8694 Ext.destroy(this.beforeScroller, this.afterScroller, this.beforeRepeater, this.afterRepeater, this.beforeCt, this.afterCt);
8699 * Scrolls left or right by the number of pixels specified
8700 * @param {Number} delta Number of pixels to scroll to the right by. Use a negative number to scroll left
8702 scrollBy: function(delta, animate) {
8703 this.scrollTo(this.getScrollPosition() + delta, animate);
8708 * Normalizes an item reference, string id or numerical index into a reference to the item
8709 * @param {Ext.Component|String|Number} item The item reference, id or index
8710 * @return {Ext.Component} The item
8712 getItem: function(item) {
8713 if (Ext.isString(item)) {
8714 item = Ext.getCmp(item);
8715 } else if (Ext.isNumber(item)) {
8716 item = this.items[item];
8724 * @return {Object} Object passed to scrollTo when scrolling
8726 getScrollAnim: function() {
8728 duration: this.scrollDuration,
8729 callback: this.updateScrollButtons,
8736 * Enables or disables each scroller button based on the current scroll position
8738 updateScrollButtons: function() {
8739 if (this.beforeScroller == undefined || this.afterScroller == undefined) {
8743 var beforeMeth = this.atExtremeBefore() ? 'addClass' : 'removeClass',
8744 afterMeth = this.atExtremeAfter() ? 'addClass' : 'removeClass',
8745 beforeCls = this.beforeScrollerCls + '-disabled',
8746 afterCls = this.afterScrollerCls + '-disabled';
8748 this.beforeScroller[beforeMeth](beforeCls);
8749 this.afterScroller[afterMeth](afterCls);
8750 this.scrolling = false;
8755 * Returns true if the innerCt scroll is already at its left-most point
8756 * @return {Boolean} True if already at furthest left point
8758 atExtremeBefore: function() {
8759 return this.getScrollPosition() === 0;
8764 * Scrolls to the left by the configured amount
8766 scrollLeft: function(animate) {
8767 this.scrollBy(-this.scrollIncrement, animate);
8772 * Scrolls to the right by the configured amount
8774 scrollRight: function(animate) {
8775 this.scrollBy(this.scrollIncrement, animate);
8779 * Scrolls to the given component.
8780 * @param {String|Number|Ext.Component} item The item to scroll to. Can be a numerical index, component id
8781 * or a reference to the component itself.
8782 * @param {Boolean} animate True to animate the scrolling
8784 scrollToItem: function(item, animate) {
8785 item = this.getItem(item);
8787 if (item != undefined) {
8788 var visibility = this.getItemVisibility(item);
8790 if (!visibility.fullyVisible) {
8791 var box = item.getBox(true, true),
8794 if (visibility.hiddenRight) {
8795 newX -= (this.layout.innerCt.getWidth() - box.width);
8798 this.scrollTo(newX, animate);
8805 * For a given item in the container, return an object with information on whether the item is visible
8806 * with the current innerCt scroll value.
8807 * @param {Ext.Component} item The item
8808 * @return {Object} Values for fullyVisible, hiddenLeft and hiddenRight
8810 getItemVisibility: function(item) {
8811 var box = this.getItem(item).getBox(true, true),
8813 itemRight = box.x + box.width,
8814 scrollLeft = this.getScrollPosition(),
8815 scrollRight = this.layout.innerCt.getWidth() + scrollLeft;
8818 hiddenLeft : itemLeft < scrollLeft,
8819 hiddenRight : itemRight > scrollRight,
8820 fullyVisible: itemLeft > scrollLeft && itemRight < scrollRight
8825 Ext.layout.boxOverflow.scroller = Ext.layout.boxOverflow.Scroller;
8829 * @class Ext.layout.boxOverflow.VerticalScroller
\r
8830 * @extends Ext.layout.boxOverflow.Scroller
\r
8833 Ext.layout.boxOverflow.VerticalScroller = Ext.extend(Ext.layout.boxOverflow.Scroller, {
8834 scrollIncrement: 75,
8837 handleOverflow: function(calculations, targetSize) {
8838 Ext.layout.boxOverflow.VerticalScroller.superclass.handleOverflow.apply(this, arguments);
8842 height: targetSize.height - (this.beforeCt.getHeight() + this.afterCt.getHeight()),
8843 width : targetSize.width
8850 * Creates the beforeCt and afterCt elements if they have not already been created
8852 createInnerElements: function() {
8853 var target = this.layout.innerCt;
8855 //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of
8856 //special items such as scrollers or dropdown menu triggers
8857 if (!this.beforeCt) {
8858 this.beforeCt = target.insertSibling({cls: this.beforeCls}, 'before');
8859 this.afterCt = target.insertSibling({cls: this.afterCls}, 'after');
8861 this.createWheelListener();
8867 * Scrolls to the given position. Performs bounds checking.
8868 * @param {Number} position The position to scroll to. This is constrained.
8869 * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll
8871 scrollTo: function(position, animate) {
8872 var oldPosition = this.getScrollPosition(),
8873 newPosition = position.constrain(0, this.getMaxScrollBottom());
8875 if (newPosition != oldPosition && !this.scrolling) {
8876 if (animate == undefined) {
8877 animate = this.animateScroll;
8880 this.layout.innerCt.scrollTo('top', newPosition, animate ? this.getScrollAnim() : false);
8883 this.scrolling = true;
8885 this.scrolling = false;
8886 this.updateScrollButtons();
8892 * Returns the current scroll position of the innerCt element
8893 * @return {Number} The current scroll position
8895 getScrollPosition: function(){
8896 return parseInt(this.layout.innerCt.dom.scrollTop, 10) || 0;
8901 * Returns the maximum value we can scrollTo
8902 * @return {Number} The max scroll value
8904 getMaxScrollBottom: function() {
8905 return this.layout.innerCt.dom.scrollHeight - this.layout.innerCt.getHeight();
8910 * Returns true if the innerCt scroll is already at its right-most point
8911 * @return {Boolean} True if already at furthest right point
8913 atExtremeAfter: function() {
8914 return this.getScrollPosition() >= this.getMaxScrollBottom();
8918 Ext.layout.boxOverflow.scroller.vbox = Ext.layout.boxOverflow.VerticalScroller;
8922 * @class Ext.layout.boxOverflow.HorizontalScroller
8923 * @extends Ext.layout.boxOverflow.Scroller
8926 Ext.layout.boxOverflow.HorizontalScroller = Ext.extend(Ext.layout.boxOverflow.Scroller, {
8927 handleOverflow: function(calculations, targetSize) {
8928 Ext.layout.boxOverflow.HorizontalScroller.superclass.handleOverflow.apply(this, arguments);
8932 height: targetSize.height,
8933 width : targetSize.width - (this.beforeCt.getWidth() + this.afterCt.getWidth())
8940 * Creates the beforeCt and afterCt elements if they have not already been created
8942 createInnerElements: function() {
8943 var target = this.layout.innerCt;
8945 //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of
8946 //special items such as scrollers or dropdown menu triggers
8947 if (!this.beforeCt) {
8948 this.afterCt = target.insertSibling({cls: this.afterCls}, 'before');
8949 this.beforeCt = target.insertSibling({cls: this.beforeCls}, 'before');
8951 this.createWheelListener();
8957 * Scrolls to the given position. Performs bounds checking.
8958 * @param {Number} position The position to scroll to. This is constrained.
8959 * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll
8961 scrollTo: function(position, animate) {
8962 var oldPosition = this.getScrollPosition(),
8963 newPosition = position.constrain(0, this.getMaxScrollRight());
8965 if (newPosition != oldPosition && !this.scrolling) {
8966 if (animate == undefined) {
8967 animate = this.animateScroll;
8970 this.layout.innerCt.scrollTo('left', newPosition, animate ? this.getScrollAnim() : false);
8973 this.scrolling = true;
8975 this.scrolling = false;
8976 this.updateScrollButtons();
8982 * Returns the current scroll position of the innerCt element
8983 * @return {Number} The current scroll position
8985 getScrollPosition: function(){
8986 return parseInt(this.layout.innerCt.dom.scrollLeft, 10) || 0;
8991 * Returns the maximum value we can scrollTo
8992 * @return {Number} The max scroll value
8994 getMaxScrollRight: function() {
8995 return this.layout.innerCt.dom.scrollWidth - this.layout.innerCt.getWidth();
9000 * Returns true if the innerCt scroll is already at its right-most point
9001 * @return {Boolean} True if already at furthest right point
9003 atExtremeAfter: function() {
9004 return this.getScrollPosition() >= this.getMaxScrollRight();
9008 Ext.layout.boxOverflow.scroller.hbox = Ext.layout.boxOverflow.HorizontalScroller;/**
9009 * @class Ext.layout.HBoxLayout
9010 * @extends Ext.layout.BoxLayout
9011 * <p>A layout that arranges items horizontally across a Container. This layout optionally divides available horizontal
9012 * space between child items containing a numeric <code>flex</code> configuration.</p>
9013 * This layout may also be used to set the heights of child items by configuring it with the {@link #align} option.
9015 Ext.layout.HBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
9017 * @cfg {String} align
9018 * Controls how the child items of the container are aligned. Acceptable configuration values for this
9020 * <div class="mdetail-params"><ul>
9021 * <li><b><tt>top</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned vertically
9022 * at the <b>top</b> of the container</div></li>
9023 * <li><b><tt>middle</tt></b> : <div class="sub-desc">child items are aligned vertically in the
9024 * <b>middle</b> of the container</div></li>
9025 * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched vertically to fill
9026 * the height of the container</div></li>
9027 * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched vertically to
9028 * the height of the largest item.</div></li>
9030 align: 'top', // top, middle, stretch, strechmax
9035 * @cfg {String} pack
9036 * Controls how the child items of the container are packed together. Acceptable configuration values
9037 * for this property are:
9038 * <div class="mdetail-params"><ul>
9039 * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
9040 * <b>left</b> side of container</div></li>
9041 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
9042 * <b>mid-width</b> of container</div></li>
9043 * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>right</b>
9044 * side of container</div></li>
9048 * @cfg {Number} flex
9049 * This configuation option is to be applied to <b>child <tt>items</tt></b> of the container managed
9050 * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>horizontally</b>
9051 * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
9052 * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
9053 * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
9058 * Calculates the size and positioning of each item in the HBox. This iterates over all of the rendered,
9059 * visible items and returns a height, width, top and left for each, as well as a reference to each. Also
9060 * returns meta data such as maxHeight which are useful when resizing layout wrappers such as this.innerCt.
9061 * @param {Array} visibleItems The array of all rendered, visible items to be calculated for
9062 * @param {Object} targetSize Object containing target size and height
9063 * @return {Object} Object containing box measurements for each child, plus meta data
9065 calculateChildBoxes: function(visibleItems, targetSize) {
9066 var visibleCount = visibleItems.length,
9068 padding = this.padding,
9069 topOffset = padding.top,
9070 leftOffset = padding.left,
9071 paddingVert = topOffset + padding.bottom,
9072 paddingHoriz = leftOffset + padding.right,
9074 width = targetSize.width - this.scrollOffset,
9075 height = targetSize.height,
9076 availHeight = Math.max(0, height - paddingVert),
9078 isStart = this.pack == 'start',
9079 isCenter = this.pack == 'center',
9080 isEnd = this.pack == 'end',
9088 //used to cache the calculated size and position values for each child item
9091 //used in the for loops below, just declared here for brevity
9092 child, childWidth, childHeight, childSize, childMargins, canLayout, i, calcs, flexedWidth,
9093 horizMargins, vertMargins, stretchHeight;
9095 //gather the total flex of all flexed items and the width taken up by fixed width items
9096 for (i = 0; i < visibleCount; i++) {
9097 child = visibleItems[i];
9098 childHeight = child.height;
9099 childWidth = child.width;
9100 canLayout = !child.hasLayout && typeof child.doLayout == 'function';
9102 // Static width (numeric) requires no calcs
9103 if (typeof childWidth != 'number') {
9105 // flex and not 'auto' width
9106 if (child.flex && !childWidth) {
9107 totalFlex += child.flex;
9109 // Not flexed or 'auto' width or undefined width
9111 //Render and layout sub-containers without a flex or width defined, as otherwise we
9112 //don't know how wide the sub-container should be and cannot calculate flexed widths
9113 if (!childWidth && canLayout) {
9117 childSize = child.getSize();
9118 childWidth = childSize.width;
9119 childHeight = childSize.height;
9123 childMargins = child.margins;
9124 horizMargins = childMargins.left + childMargins.right;
9126 nonFlexWidth += horizMargins + (childWidth || 0);
9127 desiredWidth += horizMargins + (child.flex ? child.minWidth || 0 : childWidth);
9128 minimumWidth += horizMargins + (child.minWidth || childWidth || 0);
9130 // Max height for align - force layout of non-laid out subcontainers without a numeric height
9131 if (typeof childHeight != 'number') {
9135 childHeight = child.getHeight();
9138 maxHeight = Math.max(maxHeight, childHeight + childMargins.top + childMargins.bottom);
9140 //cache the size of each child component. Don't set height or width to 0, keep undefined instead
9143 height : childHeight || undefined,
9144 width : childWidth || undefined
9148 var shortfall = desiredWidth - width,
9149 tooNarrow = minimumWidth > width;
9151 //the width available to the flexed items
9152 var availableWidth = Math.max(0, width - nonFlexWidth - paddingHoriz);
9155 for (i = 0; i < visibleCount; i++) {
9156 boxes[i].width = visibleItems[i].minWidth || visibleItems[i].width || boxes[i].width;
9159 //all flexed items should be sized to their minimum width, other items should be shrunk down until
9160 //the shortfall has been accounted for
9161 if (shortfall > 0) {
9165 * When we have a shortfall but are not tooNarrow, we need to shrink the width of each non-flexed item.
9166 * Flexed items are immediately reduced to their minWidth and anything already at minWidth is ignored.
9167 * The remaining items are collected into the minWidths array, which is later used to distribute the shortfall.
9169 for (var index = 0, length = visibleCount; index < length; index++) {
9170 var item = visibleItems[index],
9171 minWidth = item.minWidth || 0;
9173 //shrink each non-flex tab by an equal amount to make them all fit. Flexed items are all
9174 //shrunk to their minWidth because they're flexible and should be the first to lose width
9176 boxes[index].width = minWidth;
9179 minWidth : minWidth,
9180 available: boxes[index].width - minWidth,
9186 //sort by descending amount of width remaining before minWidth is reached
9187 minWidths.sort(function(a, b) {
9188 return a.available > b.available ? 1 : -1;
9192 * Distribute the shortfall (difference between total desired with of all items and actual width available)
9193 * between the non-flexed items. We try to distribute the shortfall evenly, but apply it to items with the
9194 * smallest difference between their width and minWidth first, so that if reducing the width by the average
9195 * amount would make that item less than its minWidth, we carry the remainder over to the next item.
9197 for (var i = 0, length = minWidths.length; i < length; i++) {
9198 var itemIndex = minWidths[i].index;
9200 if (itemIndex == undefined) {
9204 var item = visibleItems[itemIndex],
9205 box = boxes[itemIndex],
9206 oldWidth = box.width,
9207 minWidth = item.minWidth,
9208 newWidth = Math.max(minWidth, oldWidth - Math.ceil(shortfall / (length - i))),
9209 reduction = oldWidth - newWidth;
9211 boxes[itemIndex].width = newWidth;
9212 shortfall -= reduction;
9215 //temporary variables used in the flex width calculations below
9216 var remainingWidth = availableWidth,
9217 remainingFlex = totalFlex;
9219 //calculate the widths of each flexed item
9220 for (i = 0; i < visibleCount; i++) {
9221 child = visibleItems[i];
9224 childMargins = child.margins;
9225 vertMargins = childMargins.top + childMargins.bottom;
9227 if (isStart && child.flex && !child.width) {
9228 flexedWidth = Math.ceil((child.flex / remainingFlex) * remainingWidth);
9229 remainingWidth -= flexedWidth;
9230 remainingFlex -= child.flex;
9232 calcs.width = flexedWidth;
9233 calcs.dirtySize = true;
9240 leftOffset += availableWidth / 2;
9242 leftOffset += availableWidth;
9245 //finally, calculate the left and top position of each item
9246 for (i = 0; i < visibleCount; i++) {
9247 child = visibleItems[i];
9250 childMargins = child.margins;
9251 leftOffset += childMargins.left;
9252 vertMargins = childMargins.top + childMargins.bottom;
9254 calcs.left = leftOffset;
9255 calcs.top = topOffset + childMargins.top;
9257 switch (this.align) {
9259 stretchHeight = availHeight - vertMargins;
9260 calcs.height = stretchHeight.constrain(child.minHeight || 0, child.maxHeight || 1000000);
9261 calcs.dirtySize = true;
9264 stretchHeight = maxHeight - vertMargins;
9265 calcs.height = stretchHeight.constrain(child.minHeight || 0, child.maxHeight || 1000000);
9266 calcs.dirtySize = true;
9269 var diff = availHeight - calcs.height - vertMargins;
9271 calcs.top = topOffset + vertMargins + (diff / 2);
9275 leftOffset += calcs.width + childMargins.right;
9281 maxHeight : maxHeight,
9282 nonFlexWidth: nonFlexWidth,
9283 desiredWidth: desiredWidth,
9284 minimumWidth: minimumWidth,
9285 shortfall : desiredWidth - width,
9286 tooNarrow : tooNarrow
9292 Ext.Container.LAYOUTS.hbox = Ext.layout.HBoxLayout;/**
9293 * @class Ext.layout.VBoxLayout
9294 * @extends Ext.layout.BoxLayout
9295 * <p>A layout that arranges items vertically down a Container. This layout optionally divides available vertical
9296 * space between child items containing a numeric <code>flex</code> configuration.</p>
9297 * This layout may also be used to set the widths of child items by configuring it with the {@link #align} option.
9299 Ext.layout.VBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
9301 * @cfg {String} align
9302 * Controls how the child items of the container are aligned. Acceptable configuration values for this
9304 * <div class="mdetail-params"><ul>
9305 * <li><b><tt>left</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned horizontally
9306 * at the <b>left</b> side of the container</div></li>
9307 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are aligned horizontally at the
9308 * <b>mid-width</b> of the container</div></li>
9309 * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched horizontally to fill
9310 * the width of the container</div></li>
9311 * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched horizontally to
9312 * the size of the largest item.</div></li>
9315 align : 'left', // left, center, stretch, strechmax
9319 * @cfg {String} pack
9320 * Controls how the child items of the container are packed together. Acceptable configuration values
9321 * for this property are:
9322 * <div class="mdetail-params"><ul>
9323 * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
9324 * <b>top</b> side of container</div></li>
9325 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
9326 * <b>mid-height</b> of container</div></li>
9327 * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>bottom</b>
9328 * side of container</div></li>
9333 * @cfg {Number} flex
9334 * This configuation option is to be applied to <b>child <tt>items</tt></b> of the container managed
9335 * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>vertically</b>
9336 * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
9337 * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
9338 * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
9343 * Calculates the size and positioning of each item in the VBox. This iterates over all of the rendered,
9344 * visible items and returns a height, width, top and left for each, as well as a reference to each. Also
9345 * returns meta data such as maxHeight which are useful when resizing layout wrappers such as this.innerCt.
9346 * @param {Array} visibleItems The array of all rendered, visible items to be calculated for
9347 * @param {Object} targetSize Object containing target size and height
9348 * @return {Object} Object containing box measurements for each child, plus meta data
9350 calculateChildBoxes: function(visibleItems, targetSize) {
9351 var visibleCount = visibleItems.length,
9353 padding = this.padding,
9354 topOffset = padding.top,
9355 leftOffset = padding.left,
9356 paddingVert = topOffset + padding.bottom,
9357 paddingHoriz = leftOffset + padding.right,
9359 width = targetSize.width - this.scrollOffset,
9360 height = targetSize.height,
9361 availWidth = Math.max(0, width - paddingHoriz),
9363 isStart = this.pack == 'start',
9364 isCenter = this.pack == 'center',
9365 isEnd = this.pack == 'end',
9373 //used to cache the calculated size and position values for each child item
9376 //used in the for loops below, just declared here for brevity
9377 child, childWidth, childHeight, childSize, childMargins, canLayout, i, calcs, flexedWidth,
9378 horizMargins, vertMargins, stretchWidth;
9380 //gather the total flex of all flexed items and the width taken up by fixed width items
9381 for (i = 0; i < visibleCount; i++) {
9382 child = visibleItems[i];
9383 childHeight = child.height;
9384 childWidth = child.width;
9385 canLayout = !child.hasLayout && typeof child.doLayout == 'function';
9387 // Static height (numeric) requires no calcs
9388 if (typeof childHeight != 'number') {
9390 // flex and not 'auto' height
9391 if (child.flex && !childHeight) {
9392 totalFlex += child.flex;
9394 // Not flexed or 'auto' height or undefined height
9396 //Render and layout sub-containers without a flex or width defined, as otherwise we
9397 //don't know how wide the sub-container should be and cannot calculate flexed widths
9398 if (!childHeight && canLayout) {
9402 childSize = child.getSize();
9403 childWidth = childSize.width;
9404 childHeight = childSize.height;
9408 childMargins = child.margins;
9409 vertMargins = childMargins.top + childMargins.bottom;
9411 nonFlexHeight += vertMargins + (childHeight || 0);
9412 desiredHeight += vertMargins + (child.flex ? child.minHeight || 0 : childHeight);
9413 minimumHeight += vertMargins + (child.minHeight || childHeight || 0);
9415 // Max width for align - force layout of non-layed out subcontainers without a numeric width
9416 if (typeof childWidth != 'number') {
9420 childWidth = child.getWidth();
9423 maxWidth = Math.max(maxWidth, childWidth + childMargins.left + childMargins.right);
9425 //cache the size of each child component
9428 height : childHeight || undefined,
9429 width : childWidth || undefined
9433 var shortfall = desiredHeight - height,
9434 tooNarrow = minimumHeight > height;
9436 //the height available to the flexed items
9437 var availableHeight = Math.max(0, (height - nonFlexHeight - paddingVert));
9440 for (i = 0, length = visibleCount; i < length; i++) {
9441 boxes[i].height = visibleItems[i].minHeight || visibleItems[i].height || boxes[i].height;
9444 //all flexed items should be sized to their minimum width, other items should be shrunk down until
9445 //the shortfall has been accounted for
9446 if (shortfall > 0) {
9447 var minHeights = [];
9450 * When we have a shortfall but are not tooNarrow, we need to shrink the height of each non-flexed item.
9451 * Flexed items are immediately reduced to their minHeight and anything already at minHeight is ignored.
9452 * The remaining items are collected into the minHeights array, which is later used to distribute the shortfall.
9454 for (var index = 0, length = visibleCount; index < length; index++) {
9455 var item = visibleItems[index],
9456 minHeight = item.minHeight || 0;
9458 //shrink each non-flex tab by an equal amount to make them all fit. Flexed items are all
9459 //shrunk to their minHeight because they're flexible and should be the first to lose height
9461 boxes[index].height = minHeight;
9464 minHeight: minHeight,
9465 available: boxes[index].height - minHeight,
9471 //sort by descending minHeight value
9472 minHeights.sort(function(a, b) {
9473 return a.available > b.available ? 1 : -1;
9477 * Distribute the shortfall (difference between total desired with of all items and actual height available)
9478 * between the non-flexed items. We try to distribute the shortfall evenly, but apply it to items with the
9479 * smallest difference between their height and minHeight first, so that if reducing the height by the average
9480 * amount would make that item less than its minHeight, we carry the remainder over to the next item.
9482 for (var i = 0, length = minHeights.length; i < length; i++) {
9483 var itemIndex = minHeights[i].index;
9485 if (itemIndex == undefined) {
9489 var item = visibleItems[itemIndex],
9490 box = boxes[itemIndex],
9491 oldHeight = box.height,
9492 minHeight = item.minHeight,
9493 newHeight = Math.max(minHeight, oldHeight - Math.ceil(shortfall / (length - i))),
9494 reduction = oldHeight - newHeight;
9496 boxes[itemIndex].height = newHeight;
9497 shortfall -= reduction;
9500 //temporary variables used in the flex height calculations below
9501 var remainingHeight = availableHeight,
9502 remainingFlex = totalFlex;
9504 //calculate the height of each flexed item
9505 for (i = 0; i < visibleCount; i++) {
9506 child = visibleItems[i];
9509 childMargins = child.margins;
9510 horizMargins = childMargins.left + childMargins.right;
9512 if (isStart && child.flex && !child.height) {
9513 flexedHeight = Math.ceil((child.flex / remainingFlex) * remainingHeight);
9514 remainingHeight -= flexedHeight;
9515 remainingFlex -= child.flex;
9517 calcs.height = flexedHeight;
9518 calcs.dirtySize = true;
9525 topOffset += availableHeight / 2;
9527 topOffset += availableHeight;
9530 //finally, calculate the left and top position of each item
9531 for (i = 0; i < visibleCount; i++) {
9532 child = visibleItems[i];
9535 childMargins = child.margins;
9536 topOffset += childMargins.top;
9537 horizMargins = childMargins.left + childMargins.right;
9540 calcs.left = leftOffset + childMargins.left;
9541 calcs.top = topOffset;
9543 switch (this.align) {
9545 stretchWidth = availWidth - horizMargins;
9546 calcs.width = stretchWidth.constrain(child.minWidth || 0, child.maxWidth || 1000000);
9547 calcs.dirtySize = true;
9550 stretchWidth = maxWidth - horizMargins;
9551 calcs.width = stretchWidth.constrain(child.minWidth || 0, child.maxWidth || 1000000);
9552 calcs.dirtySize = true;
9555 var diff = availWidth - calcs.width - horizMargins;
9557 calcs.left = leftOffset + horizMargins + (diff / 2);
9561 topOffset += calcs.height + childMargins.bottom;
9567 maxWidth : maxWidth,
9568 nonFlexHeight: nonFlexHeight,
9569 desiredHeight: desiredHeight,
9570 minimumHeight: minimumHeight,
9571 shortfall : desiredHeight - height,
9572 tooNarrow : tooNarrow
9578 Ext.Container.LAYOUTS.vbox = Ext.layout.VBoxLayout;
9580 * @class Ext.layout.ToolbarLayout
9581 * @extends Ext.layout.ContainerLayout
9582 * Layout manager used by Ext.Toolbar. This is highly specialised for use by Toolbars and would not
9583 * usually be used by any other class.
9585 Ext.layout.ToolbarLayout = Ext.extend(Ext.layout.ContainerLayout, {
9586 monitorResize : true,
9591 * @property triggerWidth
9593 * The width allocated for the menu trigger at the extreme right end of the Toolbar
9598 * @property noItemsMenuText
9600 * HTML fragment to render into the toolbar overflow menu if there are no items to display
9602 noItemsMenuText : '<div class="x-toolbar-no-items">(None)</div>',
9606 * @property lastOverflow
9608 * Used internally to record whether the last layout caused an overflow or not
9610 lastOverflow: false,
9614 * @property tableHTML
9616 * String used to build the HTML injected to support the Toolbar's layout. The align property is
9617 * injected into this string inside the td.x-toolbar-left element during onLayout.
9620 '<table cellspacing="0" class="x-toolbar-ct">',
9623 '<td class="x-toolbar-left" align="{0}">',
9624 '<table cellspacing="0">',
9626 '<tr class="x-toolbar-left-row"></tr>',
9630 '<td class="x-toolbar-right" align="right">',
9631 '<table cellspacing="0" class="x-toolbar-right-ct">',
9635 '<table cellspacing="0">',
9637 '<tr class="x-toolbar-right-row"></tr>',
9642 '<table cellspacing="0">',
9644 '<tr class="x-toolbar-extras-row"></tr>',
9659 * Create the wrapping Toolbar HTML and render/move all the items into the correct places
9661 onLayout : function(ct, target) {
9662 //render the Toolbar <table> HTML if it's not already present
9664 var align = ct.buttonAlign == 'center' ? 'center' : 'left';
9666 target.addClass('x-toolbar-layout-ct');
9667 target.insertHtml('beforeEnd', String.format(this.tableHTML, align));
9669 this.leftTr = target.child('tr.x-toolbar-left-row', true);
9670 this.rightTr = target.child('tr.x-toolbar-right-row', true);
9671 this.extrasTr = target.child('tr.x-toolbar-extras-row', true);
9673 if (this.hiddenItem == undefined) {
9675 * @property hiddenItems
9677 * Holds all items that are currently hidden due to there not being enough space to render them
9678 * These items will appear on the expand menu.
9680 this.hiddenItems = [];
9684 var side = ct.buttonAlign == 'right' ? this.rightTr : this.leftTr,
9685 items = ct.items.items,
9688 //render each item if not already rendered, place it into the correct (left or right) target
9689 for (var i = 0, len = items.length, c; i < len; i++, position++) {
9693 side = this.rightTr;
9695 } else if (!c.rendered) {
9696 c.render(this.insertCell(c, side, position));
9697 this.configureItem(c);
9699 if (!c.xtbHidden && !this.isValidParent(c, side.childNodes[position])) {
9700 var td = this.insertCell(c, side, position);
9701 td.appendChild(c.getPositionEl().dom);
9702 c.container = Ext.get(td);
9707 //strip extra empty cells
9708 this.cleanup(this.leftTr);
9709 this.cleanup(this.rightTr);
9710 this.cleanup(this.extrasTr);
9711 this.fitToSize(target);
9716 * Removes any empty nodes from the given element
9717 * @param {Ext.Element} el The element to clean up
9719 cleanup : function(el) {
9720 var cn = el.childNodes, i, c;
9722 for (i = cn.length-1; i >= 0 && (c = cn[i]); i--) {
9723 if (!c.firstChild) {
9731 * Inserts the given Toolbar item into the given element
9732 * @param {Ext.Component} c The component to add
9733 * @param {Ext.Element} target The target to add the component to
9734 * @param {Number} position The position to add the component at
9736 insertCell : function(c, target, position) {
9737 var td = document.createElement('td');
9738 td.className = 'x-toolbar-cell';
9740 target.insertBefore(td, target.childNodes[position] || null);
9747 * Hides an item because it will not fit in the available width. The item will be unhidden again
9748 * if the Toolbar is resized to be large enough to show it
9749 * @param {Ext.Component} item The item to hide
9751 hideItem : function(item) {
9752 this.hiddenItems.push(item);
9754 item.xtbHidden = true;
9755 item.xtbWidth = item.getPositionEl().dom.parentNode.offsetWidth;
9761 * Unhides an item that was previously hidden due to there not being enough space left on the Toolbar
9762 * @param {Ext.Component} item The item to show
9764 unhideItem : function(item) {
9766 item.xtbHidden = false;
9767 this.hiddenItems.remove(item);
9772 * Returns the width of the given toolbar item. If the item is currently hidden because there
9773 * is not enough room to render it, its previous width is returned
9774 * @param {Ext.Component} c The component to measure
9775 * @return {Number} The width of the item
9777 getItemWidth : function(c) {
9778 return c.hidden ? (c.xtbWidth || 0) : c.getPositionEl().dom.parentNode.offsetWidth;
9783 * Called at the end of onLayout. At this point the Toolbar has already been resized, so we need
9784 * to fit the items into the available width. We add up the width required by all of the items in
9785 * the toolbar - if we don't have enough space we hide the extra items and render the expand menu
9787 * @param {Ext.Element} target The Element the Toolbar is currently laid out within
9789 fitToSize : function(target) {
9790 if (this.container.enableOverflow === false) {
9794 var width = target.dom.clientWidth,
9795 tableWidth = target.dom.firstChild.offsetWidth,
9796 clipWidth = width - this.triggerWidth,
9797 lastWidth = this.lastWidth || 0,
9799 hiddenItems = this.hiddenItems,
9800 hasHiddens = hiddenItems.length != 0,
9801 isLarger = width >= lastWidth;
9803 this.lastWidth = width;
9805 if (tableWidth > width || (hasHiddens && isLarger)) {
9806 var items = this.container.items.items,
9811 for (var i = 0; i < len; i++) {
9815 loopWidth += this.getItemWidth(item);
9816 if (loopWidth > clipWidth) {
9817 if (!(item.hidden || item.xtbHidden)) {
9818 this.hideItem(item);
9820 } else if (item.xtbHidden) {
9821 this.unhideItem(item);
9827 //test for number of hidden items again here because they may have changed above
9828 hasHiddens = hiddenItems.length != 0;
9833 if (!this.lastOverflow) {
9834 this.container.fireEvent('overflowchange', this.container, true);
9835 this.lastOverflow = true;
9837 } else if (this.more) {
9839 this.more.destroy();
9842 if (this.lastOverflow) {
9843 this.container.fireEvent('overflowchange', this.container, false);
9844 this.lastOverflow = false;
9851 * Returns a menu config for a given component. This config is used to create a menu item
9852 * to be added to the expander menu
9853 * @param {Ext.Component} component The component to create the config for
9854 * @param {Boolean} hideOnClick Passed through to the menu item
9856 createMenuConfig : function(component, hideOnClick){
9857 var config = Ext.apply({}, component.initialConfig),
9858 group = component.toggleGroup;
9860 Ext.copyTo(config, component, [
9861 'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu'
9865 text : component.overflowText || component.text,
9866 hideOnClick: hideOnClick
9869 if (group || component.enableToggle) {
9872 checked: component.pressed,
9874 checkchange: function(item, checked){
9875 component.toggle(checked);
9881 delete config.ownerCt;
9882 delete config.xtype;
9890 * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually.
9891 * @param {Ext.menu.Menu} menu The menu to add to
9892 * @param {Ext.Component} component The component to add
9894 addComponentToMenu : function(menu, component) {
9895 if (component instanceof Ext.Toolbar.Separator) {
9898 } else if (Ext.isFunction(component.isXType)) {
9899 if (component.isXType('splitbutton')) {
9900 menu.add(this.createMenuConfig(component, true));
9902 } else if (component.isXType('button')) {
9903 menu.add(this.createMenuConfig(component, !component.menu));
9905 } else if (component.isXType('buttongroup')) {
9906 component.items.each(function(item){
9907 this.addComponentToMenu(menu, item);
9915 * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as
9916 * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item
9918 clearMenu : function(){
9919 var menu = this.moreMenu;
9920 if (menu && menu.items) {
9921 menu.items.each(function(item){
9929 * Called before the expand menu is shown, this rebuilds the menu since it was last shown because
9930 * it is possible that the items hidden due to space limitations on the Toolbar have changed since.
9931 * @param {Ext.menu.Menu} m The menu
9933 beforeMoreShow : function(menu) {
9934 var items = this.container.items.items,
9939 var needsSep = function(group, item){
9940 return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator);
9945 for (var i = 0; i < len; i++) {
9947 if (item.xtbHidden) {
9948 if (prev && (needsSep(item, prev) || needsSep(prev, item))) {
9951 this.addComponentToMenu(menu, item);
9956 // put something so the menu isn't empty if no compatible items found
9957 if (menu.items.length < 1) {
9958 menu.add(this.noItemsMenuText);
9964 * Creates the expand trigger and menu, adding them to the <tr> at the extreme right of the
9967 initMore : function(){
9971 * @property moreMenu
9972 * @type Ext.menu.Menu
9973 * The expand menu - holds items for every Toolbar item that cannot be shown
9974 * because the Toolbar is currently not wide enough.
9976 this.moreMenu = new Ext.menu.Menu({
9977 ownerCt : this.container,
9979 beforeshow: this.beforeMoreShow,
9988 * The expand button which triggers the overflow menu to be shown
9990 this.more = new Ext.Button({
9991 iconCls: 'x-toolbar-more-icon',
9992 cls : 'x-toolbar-more',
9993 menu : this.moreMenu,
9994 ownerCt: this.container
9997 var td = this.insertCell(this.more, this.extrasTr, 100);
9998 this.more.render(td);
10002 destroy : function(){
10003 Ext.destroy(this.more, this.moreMenu);
10004 delete this.leftTr;
10005 delete this.rightTr;
10006 delete this.extrasTr;
10007 Ext.layout.ToolbarLayout.superclass.destroy.call(this);
10011 Ext.Container.LAYOUTS.toolbar = Ext.layout.ToolbarLayout;
10013 * @class Ext.layout.MenuLayout
10014 * @extends Ext.layout.ContainerLayout
10015 * <p>Layout manager used by {@link Ext.menu.Menu}. Generally this class should not need to be used directly.</p>
10017 Ext.layout.MenuLayout = Ext.extend(Ext.layout.ContainerLayout, {
10018 monitorResize : true,
10022 setContainer : function(ct){
10023 this.monitorResize = !ct.floating;
10024 // This event is only fired by the menu in IE, used so we don't couple
10025 // the menu with the layout.
10026 ct.on('autosize', this.doAutoSize, this);
10027 Ext.layout.MenuLayout.superclass.setContainer.call(this, ct);
10030 renderItem : function(c, position, target){
10031 if (!this.itemTpl) {
10032 this.itemTpl = Ext.layout.MenuLayout.prototype.itemTpl = new Ext.XTemplate(
10033 '<li id="{itemId}" class="{itemCls}">',
10034 '<tpl if="needsIcon">',
10035 '<img alt="{altText}" src="{icon}" class="{iconCls}"/>',
10041 if(c && !c.rendered){
10042 if(Ext.isNumber(position)){
10043 position = target.dom.childNodes[position];
10045 var a = this.getItemArgs(c);
10047 // The Component's positionEl is the <li> it is rendered into
10048 c.render(c.positionEl = position ?
10049 this.itemTpl.insertBefore(position, a, true) :
10050 this.itemTpl.append(target, a, true));
10052 // Link the containing <li> to the item.
10053 c.positionEl.menuItemId = c.getItemId();
10055 // If rendering a regular Component, and it needs an icon,
10056 // move the Component rightwards.
10057 if (!a.isMenuItem && a.needsIcon) {
10058 c.positionEl.addClass('x-menu-list-item-indent');
10060 this.configureItem(c);
10061 }else if(c && !this.isValidParent(c, target)){
10062 if(Ext.isNumber(position)){
10063 position = target.dom.childNodes[position];
10065 target.dom.insertBefore(c.getActionEl().dom, position || null);
10069 getItemArgs : function(c) {
10070 var isMenuItem = c instanceof Ext.menu.Item,
10071 canHaveIcon = !(isMenuItem || c instanceof Ext.menu.Separator);
10074 isMenuItem: isMenuItem,
10075 needsIcon: canHaveIcon && (c.icon || c.iconCls),
10076 icon: c.icon || Ext.BLANK_IMAGE_URL,
10077 iconCls: 'x-menu-item-icon ' + (c.iconCls || ''),
10078 itemId: 'x-menu-el-' + c.id,
10079 itemCls: 'x-menu-list-item ',
10080 altText: c.altText || ''
10084 // Valid if the Component is in a <li> which is part of our target <ul>
10085 isValidParent : function(c, target) {
10086 return c.el.up('li.x-menu-list-item', 5).dom.parentNode === (target.dom || target);
10089 onLayout : function(ct, target){
10090 Ext.layout.MenuLayout.superclass.onLayout.call(this, ct, target);
10094 doAutoSize : function(){
10095 var ct = this.container, w = ct.width;
10099 }else if(Ext.isIE){
10100 ct.setWidth(Ext.isStrict && (Ext.isIE7 || Ext.isIE8) ? 'auto' : ct.minWidth);
10101 var el = ct.getEl(), t = el.dom.offsetWidth; // force recalc
10102 ct.setWidth(ct.getLayoutTarget().getWidth() + el.getFrameWidth('lr'));
10107 Ext.Container.LAYOUTS['menu'] = Ext.layout.MenuLayout;
10109 * @class Ext.Viewport
10110 * @extends Ext.Container
10111 * <p>A specialized container representing the viewable application area (the browser viewport).</p>
10112 * <p>The Viewport renders itself to the document body, and automatically sizes itself to the size of
10113 * the browser viewport and manages window resizing. There may only be one Viewport created
10114 * in a page. Inner layouts are available by virtue of the fact that all {@link Ext.Panel Panel}s
10115 * added to the Viewport, either through its {@link #items}, or through the items, or the {@link #add}
10116 * method of any of its child Panels may themselves have a layout.</p>
10117 * <p>The Viewport does not provide scrolling, so child Panels within the Viewport should provide
10118 * for scrolling if needed using the {@link #autoScroll} config.</p>
10119 * <p>An example showing a classic application border layout:</p><pre><code>
10124 html: '<h1 class="x-panel-header">Page Title</h1>',
10131 title: 'Navigation',
10133 // the west region might typically utilize a {@link Ext.tree.TreePanel TreePanel} or a Panel with {@link Ext.layout.AccordionLayout Accordion layout}
10136 title: 'Title for Panel',
10138 html: 'Information goes here',
10144 title: 'Title for the Grid Panel',
10149 // remaining grid configuration not shown ...
10150 // notice that the GridPanel is added directly as the region
10151 // it is not "overnested" inside another Panel
10154 xtype: 'tabpanel', // TabPanel itself has no title
10156 title: 'Default Tab',
10157 html: 'The first tab\'s content. Others may be added dynamically'
10163 * Create a new Viewport
10164 * @param {Object} config The config object
10167 Ext.Viewport = Ext.extend(Ext.Container, {
10169 * Privatize config options which, if used, would interfere with the
10170 * correct operation of the Viewport as the sole manager of the
10171 * layout of the document body.
10174 * @cfg {Mixed} applyTo @hide
10177 * @cfg {Boolean} allowDomMove @hide
10180 * @cfg {Boolean} hideParent @hide
10183 * @cfg {Mixed} renderTo @hide
10186 * @cfg {Boolean} hideParent @hide
10189 * @cfg {Number} height @hide
10192 * @cfg {Number} width @hide
10195 * @cfg {Boolean} autoHeight @hide
10198 * @cfg {Boolean} autoWidth @hide
10201 * @cfg {Boolean} deferHeight @hide
10204 * @cfg {Boolean} monitorResize @hide
10207 initComponent : function() {
10208 Ext.Viewport.superclass.initComponent.call(this);
10209 document.getElementsByTagName('html')[0].className += ' x-viewport';
10210 this.el = Ext.getBody();
10211 this.el.setHeight = Ext.emptyFn;
10212 this.el.setWidth = Ext.emptyFn;
10213 this.el.setSize = Ext.emptyFn;
10214 this.el.dom.scroll = 'no';
10215 this.allowDomMove = false;
10216 this.autoWidth = true;
10217 this.autoHeight = true;
10218 Ext.EventManager.onWindowResize(this.fireResize, this);
10219 this.renderTo = this.el;
10222 fireResize : function(w, h){
10223 this.fireEvent('resize', this, w, h, w, h);
10226 Ext.reg('viewport', Ext.Viewport);
10229 * @extends Ext.Container
10230 * <p>Panel is a container that has specific functionality and structural components that make
10231 * it the perfect building block for application-oriented user interfaces.</p>
10232 * <p>Panels are, by virtue of their inheritance from {@link Ext.Container}, capable
10233 * of being configured with a {@link Ext.Container#layout layout}, and containing child Components.</p>
10234 * <p>When either specifying child {@link Ext.Component#items items} of a Panel, or dynamically {@link Ext.Container#add adding} Components
10235 * to a Panel, remember to consider how you wish the Panel to arrange those child elements, and whether
10236 * those child elements need to be sized using one of Ext's built-in <code><b>{@link Ext.Container#layout layout}</b></code> schemes. By
10237 * default, Panels use the {@link Ext.layout.ContainerLayout ContainerLayout} scheme. This simply renders
10238 * child components, appending them one after the other inside the Container, and <b>does not apply any sizing</b>
10240 * <p>A Panel may also contain {@link #bbar bottom} and {@link #tbar top} toolbars, along with separate
10241 * {@link #header}, {@link #footer} and {@link #body} sections (see {@link #frame} for additional
10242 * information).</p>
10243 * <p>Panel also provides built-in {@link #collapsible expandable and collapsible behavior}, along with
10244 * a variety of {@link #tools prebuilt tool buttons} that can be wired up to provide other customized
10245 * behavior. Panels can be easily dropped into any {@link Ext.Container Container} or layout, and the
10246 * layout and rendering pipeline is {@link Ext.Container#add completely managed by the framework}.</p>
10248 * @param {Object} config The config object
10251 Ext.Panel = Ext.extend(Ext.Container, {
10253 * The Panel's header {@link Ext.Element Element}. Read-only.
10254 * <p>This Element is used to house the {@link #title} and {@link #tools}</p>
10255 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
10256 * @type Ext.Element
10260 * The Panel's body {@link Ext.Element Element} which may be used to contain HTML content.
10261 * The content may be specified in the {@link #html} config, or it may be loaded using the
10262 * {@link autoLoad} config, or through the Panel's {@link #getUpdater Updater}. Read-only.
10263 * <p>If this is used to load visible HTML elements in either way, then
10264 * the Panel may not be used as a Layout for hosting nested Panels.</p>
10265 * <p>If this Panel is intended to be used as the host of a Layout (See {@link #layout}
10266 * then the body Element must not be loaded or changed - it is under the control
10267 * of the Panel's Layout.
10268 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
10269 * @type Ext.Element
10273 * The Panel's bwrap {@link Ext.Element Element} used to contain other Panel elements
10274 * (tbar, body, bbar, footer). See {@link #bodyCfg}. Read-only.
10275 * @type Ext.Element
10279 * True if this panel is collapsed. Read-only.
10281 * @property collapsed
10284 * @cfg {Object} bodyCfg
10285 * <p>A {@link Ext.DomHelper DomHelper} element specification object may be specified for any
10286 * Panel Element.</p>
10287 * <p>By default, the Default element in the table below will be used for the html markup to
10288 * create a child element with the commensurate Default class name (<code>baseCls</code> will be
10289 * replaced by <code>{@link #baseCls}</code>):</p>
10291 * Panel Default Default Custom Additional Additional
10292 * Element element class element class style
10293 * ======== ========================== ========= ============== ===========
10294 * {@link #header} div {@link #baseCls}+'-header' {@link #headerCfg} headerCssClass headerStyle
10295 * {@link #bwrap} div {@link #baseCls}+'-bwrap' {@link #bwrapCfg} bwrapCssClass bwrapStyle
10296 * + tbar div {@link #baseCls}+'-tbar' {@link #tbarCfg} tbarCssClass tbarStyle
10297 * + {@link #body} div {@link #baseCls}+'-body' {@link #bodyCfg} {@link #bodyCssClass} {@link #bodyStyle}
10298 * + bbar div {@link #baseCls}+'-bbar' {@link #bbarCfg} bbarCssClass bbarStyle
10299 * + {@link #footer} div {@link #baseCls}+'-footer' {@link #footerCfg} footerCssClass footerStyle
10301 * <p>Configuring a Custom element may be used, for example, to force the {@link #body} Element
10302 * to use a different form of markup than is created by default. An example of this might be
10303 * to {@link Ext.Element#createChild create a child} Panel containing a custom content, such as
10304 * a header, or forcing centering of all Panel content by having the body be a <center>
10308 title: 'Message Title',
10309 renderTo: Ext.getBody(),
10310 width: 200, height: 130,
10313 cls: 'x-panel-body', // Default class not applied if Custom element specified
10318 cls: 'x-panel-footer', // same as the Default class
10319 html: 'footer html'
10321 footerCssClass: 'custom-footer', // additional css class, see {@link Ext.element#addClass addClass}
10322 footerStyle: 'background-color:red' // see {@link #bodyStyle}
10325 * <p>The example above also explicitly creates a <code>{@link #footer}</code> with custom markup and
10326 * styling applied.</p>
10329 * @cfg {Object} headerCfg
10330 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
10331 * of this Panel's {@link #header} Element. See <code>{@link #bodyCfg}</code> also.</p>
10334 * @cfg {Object} bwrapCfg
10335 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
10336 * of this Panel's {@link #bwrap} Element. See <code>{@link #bodyCfg}</code> also.</p>
10339 * @cfg {Object} tbarCfg
10340 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
10341 * of this Panel's {@link #tbar} Element. See <code>{@link #bodyCfg}</code> also.</p>
10344 * @cfg {Object} bbarCfg
10345 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
10346 * of this Panel's {@link #bbar} Element. See <code>{@link #bodyCfg}</code> also.</p>
10349 * @cfg {Object} footerCfg
10350 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
10351 * of this Panel's {@link #footer} Element. See <code>{@link #bodyCfg}</code> also.</p>
10354 * @cfg {Boolean} closable
10355 * Panels themselves do not directly support being closed, but some Panel subclasses do (like
10356 * {@link Ext.Window}) or a Panel Class within an {@link Ext.TabPanel}. Specify <code>true</code>
10357 * to enable closing in such situations. Defaults to <code>false</code>.
10360 * The Panel's footer {@link Ext.Element Element}. Read-only.
10361 * <p>This Element is used to house the Panel's <code>{@link #buttons}</code> or <code>{@link #fbar}</code>.</p>
10362 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
10363 * @type Ext.Element
10367 * @cfg {Mixed} applyTo
10368 * <p>The id of the node, a DOM node or an existing Element corresponding to a DIV that is already present in
10369 * the document that specifies some panel-specific structural markup. When <code>applyTo</code> is used,
10370 * constituent parts of the panel can be specified by CSS class name within the main element, and the panel
10371 * will automatically create those components from that markup. Any required components not specified in the
10372 * markup will be autogenerated if necessary.</p>
10373 * <p>The following class names are supported (baseCls will be replaced by {@link #baseCls}):</p>
10374 * <ul><li>baseCls + '-header'</li>
10375 * <li>baseCls + '-header-text'</li>
10376 * <li>baseCls + '-bwrap'</li>
10377 * <li>baseCls + '-tbar'</li>
10378 * <li>baseCls + '-body'</li>
10379 * <li>baseCls + '-bbar'</li>
10380 * <li>baseCls + '-footer'</li></ul>
10381 * <p>Using this config, a call to render() is not required. If applyTo is specified, any value passed for
10382 * {@link #renderTo} will be ignored and the target element's parent node will automatically be used as the
10383 * panel's container.</p>
10386 * @cfg {Object/Array} tbar
10387 * <p>The top toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
10388 * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render.
10389 * To access the top toolbar after render, use {@link #getTopToolbar}.</p>
10390 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
10391 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
10392 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
10393 * submission parameters are collected from the DOM tree.</p>
10396 * @cfg {Object/Array} bbar
10397 * <p>The bottom toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
10398 * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render.
10399 * To access the bottom toolbar after render, use {@link #getBottomToolbar}.</p>
10400 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
10401 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
10402 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
10403 * submission parameters are collected from the DOM tree.</p>
10405 /** @cfg {Object/Array} fbar
10406 * <p>A {@link Ext.Toolbar Toolbar} object, a Toolbar config, or an array of
10407 * {@link Ext.Button Button}s/{@link Ext.Button Button} configs, describing a {@link Ext.Toolbar Toolbar} to be rendered into this Panel's footer element.</p>
10408 * <p>After render, the <code>fbar</code> property will be an {@link Ext.Toolbar Toolbar} instance.</p>
10409 * <p>If <code>{@link #buttons}</code> are specified, they will supersede the <code>fbar</code> configuration property.</p>
10410 * The Panel's <code>{@link #buttonAlign}</code> configuration affects the layout of these items, for example:
10412 var w = new Ext.Window({
10415 bbar: new Ext.Toolbar({
10422 {@link #buttonAlign}: 'left', // anything but 'center' or 'right' and you can use '-', and '->'
10423 // to control the alignment of fbar items
10431 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
10432 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
10433 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
10434 * submission parameters are collected from the DOM tree.</p>
10437 * @cfg {Boolean} header
10438 * <code>true</code> to create the Panel's header element explicitly, <code>false</code> to skip creating
10439 * it. If a <code>{@link #title}</code> is set the header will be created automatically, otherwise it will not.
10440 * If a <code>{@link #title}</code> is set but <code>header</code> is explicitly set to <code>false</code>, the header
10441 * will not be rendered.
10444 * @cfg {Boolean} footer
10445 * <code>true</code> to create the footer element explicitly, false to skip creating it. The footer
10446 * will be created automatically if <code>{@link #buttons}</code> or a <code>{@link #fbar}</code> have
10447 * been configured. See <code>{@link #bodyCfg}</code> for an example.
10450 * @cfg {String} title
10451 * The title text to be used as innerHTML (html tags are accepted) to display in the panel
10452 * <code>{@link #header}</code> (defaults to ''). When a <code>title</code> is specified the
10453 * <code>{@link #header}</code> element will automatically be created and displayed unless
10454 * {@link #header} is explicitly set to <code>false</code>. If you do not want to specify a
10455 * <code>title</code> at config time, but you may want one later, you must either specify a non-empty
10456 * <code>title</code> (a blank space ' ' will do) or <code>header:true</code> so that the container
10457 * element will get created.
10460 * @cfg {Array} buttons
10461 * <code>buttons</code> will be used as <code>{@link Ext.Container#items items}</code> for the toolbar in
10462 * the footer (<code>{@link #fbar}</code>). Typically the value of this configuration property will be
10463 * an array of {@link Ext.Button}s or {@link Ext.Button} configuration objects.
10464 * If an item is configured with <code>minWidth</code> or the Panel is configured with <code>minButtonWidth</code>,
10465 * that width will be applied to the item.
10468 * @cfg {Object/String/Function} autoLoad
10469 * A valid url spec according to the Updater {@link Ext.Updater#update} method.
10470 * If autoLoad is not null, the panel will attempt to load its contents
10471 * immediately upon render.<p>
10472 * The URL will become the default URL for this panel's {@link #body} element,
10473 * so it may be {@link Ext.Element#refresh refresh}ed at any time.</p>
10476 * @cfg {Boolean} frame
10477 * <code>false</code> by default to render with plain 1px square borders. <code>true</code> to render with
10478 * 9 elements, complete with custom rounded corners (also see {@link Ext.Element#boxWrap}).
10479 * <p>The template generated for each condition is depicted below:</p><pre><code>
10482 <div id="developer-specified-id-goes-here" class="x-panel">
10484 <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:false)</span></div>
10486 <div class="x-panel-bwrap">
10487 <div class="x-panel-body"><p>html value goes here</p></div>
10491 // frame = true (create 9 elements)
10492 <div id="developer-specified-id-goes-here" class="x-panel">
10493 <div class="x-panel-tl"><div class="x-panel-tr"><div class="x-panel-tc">
10494 <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:true)</span></div>
10495 </div></div></div>
10497 <div class="x-panel-bwrap">
10498 <div class="x-panel-ml"><div class="x-panel-mr"><div class="x-panel-mc">
10499 <div class="x-panel-body"><p>html value goes here</p></div>
10500 </div></div></div>
10502 <div class="x-panel-bl"><div class="x-panel-br"><div class="x-panel-bc"/>
10503 </div></div></div>
10508 * @cfg {Boolean} border
10509 * True to display the borders of the panel's body element, false to hide them (defaults to true). By default,
10510 * the border is a 2px wide inset border, but this can be further altered by setting {@link #bodyBorder} to false.
10513 * @cfg {Boolean} bodyBorder
10514 * True to display an interior border on the body element of the panel, false to hide it (defaults to true).
10515 * This only applies when {@link #border} == true. If border == true and bodyBorder == false, the border will display
10516 * as a 1px wide inset border, giving the entire body element an inset appearance.
10519 * @cfg {String/Object/Function} bodyCssClass
10520 * Additional css class selector to be applied to the {@link #body} element in the format expected by
10521 * {@link Ext.Element#addClass} (defaults to null). See {@link #bodyCfg}.
10524 * @cfg {String/Object/Function} bodyStyle
10525 * Custom CSS styles to be applied to the {@link #body} element in the format expected by
10526 * {@link Ext.Element#applyStyles} (defaults to null). See {@link #bodyCfg}.
10529 * @cfg {String} iconCls
10530 * The CSS class selector that specifies a background image to be used as the header icon (defaults to '').
10531 * <p>An example of specifying a custom icon class would be something like:
10533 // specify the property in the config for the class:
10537 // css class that specifies background image to be used as the icon image:
10538 .my-icon { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
10542 * @cfg {Boolean} collapsible
10543 * True to make the panel collapsible and have the expand/collapse toggle button automatically rendered into
10544 * the header tool button area, false to keep the panel statically sized with no button (defaults to false).
10547 * @cfg {Array} tools
10548 * An array of tool button configs to be added to the header tool area. When rendered, each tool is
10549 * stored as an {@link Ext.Element Element} referenced by a public property called <code><b></b>tools.<i><tool-type></i></code>
10550 * <p>Each tool config may contain the following properties:
10551 * <div class="mdetail-params"><ul>
10552 * <li><b>id</b> : String<div class="sub-desc"><b>Required.</b> The type
10553 * of tool to create. By default, this assigns a CSS class of the form <code>x-tool-<i><tool-type></i></code> to the
10554 * resulting tool Element. Ext provides CSS rules, and an icon sprite containing images for the tool types listed below.
10555 * The developer may implement custom tools by supplying alternate CSS rules and background images:
10557 * <div class="x-tool x-tool-toggle" style="float:left; margin-right:5;"> </div><div><code> toggle</code> (Created by default when {@link #collapsible} is <code>true</code>)</div>
10558 * <div class="x-tool x-tool-close" style="float:left; margin-right:5;"> </div><div><code> close</code></div>
10559 * <div class="x-tool x-tool-minimize" style="float:left; margin-right:5;"> </div><div><code> minimize</code></div>
10560 * <div class="x-tool x-tool-maximize" style="float:left; margin-right:5;"> </div><div><code> maximize</code></div>
10561 * <div class="x-tool x-tool-restore" style="float:left; margin-right:5;"> </div><div><code> restore</code></div>
10562 * <div class="x-tool x-tool-gear" style="float:left; margin-right:5;"> </div><div><code> gear</code></div>
10563 * <div class="x-tool x-tool-pin" style="float:left; margin-right:5;"> </div><div><code> pin</code></div>
10564 * <div class="x-tool x-tool-unpin" style="float:left; margin-right:5;"> </div><div><code> unpin</code></div>
10565 * <div class="x-tool x-tool-right" style="float:left; margin-right:5;"> </div><div><code> right</code></div>
10566 * <div class="x-tool x-tool-left" style="float:left; margin-right:5;"> </div><div><code> left</code></div>
10567 * <div class="x-tool x-tool-up" style="float:left; margin-right:5;"> </div><div><code> up</code></div>
10568 * <div class="x-tool x-tool-down" style="float:left; margin-right:5;"> </div><div><code> down</code></div>
10569 * <div class="x-tool x-tool-refresh" style="float:left; margin-right:5;"> </div><div><code> refresh</code></div>
10570 * <div class="x-tool x-tool-minus" style="float:left; margin-right:5;"> </div><div><code> minus</code></div>
10571 * <div class="x-tool x-tool-plus" style="float:left; margin-right:5;"> </div><div><code> plus</code></div>
10572 * <div class="x-tool x-tool-help" style="float:left; margin-right:5;"> </div><div><code> help</code></div>
10573 * <div class="x-tool x-tool-search" style="float:left; margin-right:5;"> </div><div><code> search</code></div>
10574 * <div class="x-tool x-tool-save" style="float:left; margin-right:5;"> </div><div><code> save</code></div>
10575 * <div class="x-tool x-tool-print" style="float:left; margin-right:5;"> </div><div><code> print</code></div>
10577 * <li><b>handler</b> : Function<div class="sub-desc"><b>Required.</b> The function to
10578 * call when clicked. Arguments passed are:<ul>
10579 * <li><b>event</b> : Ext.EventObject<div class="sub-desc">The click event.</div></li>
10580 * <li><b>toolEl</b> : Ext.Element<div class="sub-desc">The tool Element.</div></li>
10581 * <li><b>panel</b> : Ext.Panel<div class="sub-desc">The host Panel</div></li>
10582 * <li><b>tc</b> : Object<div class="sub-desc">The tool configuration object</div></li>
10584 * <li><b>stopEvent</b> : Boolean<div class="sub-desc">Defaults to true. Specify as false to allow click event to propagate.</div></li>
10585 * <li><b>scope</b> : Object<div class="sub-desc">The scope in which to call the handler.</div></li>
10586 * <li><b>qtip</b> : String/Object<div class="sub-desc">A tip string, or
10587 * a config argument to {@link Ext.QuickTip#register}</div></li>
10588 * <li><b>hidden</b> : Boolean<div class="sub-desc">True to initially render hidden.</div></li>
10589 * <li><b>on</b> : Object<div class="sub-desc">A listener config object specifiying
10590 * event listeners in the format of an argument to {@link #addListener}</div></li>
10592 * <p>Note that, apart from the toggle tool which is provided when a panel is collapsible, these
10593 * tools only provide the visual button. Any required functionality must be provided by adding
10594 * handlers that implement the necessary behavior.</p>
10595 * <p>Example usage:</p>
10599 qtip: 'Refresh form Data',
10601 handler: function(event, toolEl, panel){
10608 handler: function(event, toolEl, panel){
10613 * <p>For the custom id of <code>'help'</code> define two relevant css classes with a link to
10614 * a 15x15 image:</p>
10616 .x-tool-help {background-image: url(images/help.png);}
10617 .x-tool-help-over {background-image: url(images/help_over.png);}
10618 // if using an image sprite:
10619 .x-tool-help {background-image: url(images/help.png) no-repeat 0 0;}
10620 .x-tool-help-over {background-position:-15px 0;}
10624 * @cfg {Ext.Template/Ext.XTemplate} toolTemplate
10625 * <p>A Template used to create {@link #tools} in the {@link #header} Element. Defaults to:</p><pre><code>
10626 new Ext.Template('<div class="x-tool x-tool-{id}">&#160;</div>')</code></pre>
10627 * <p>This may may be overridden to provide a custom DOM structure for tools based upon a more
10628 * complex XTemplate. The template's data is a single tool configuration object (Not the entire Array)
10629 * as specified in {@link #tools}. In the following example an <a> tag is used to provide a
10630 * visual indication when hovering over the tool:</p><pre><code>
10631 var win = new Ext.Window({
10634 href: '/MyPdfDoc.pdf'
10636 toolTemplate: new Ext.XTemplate(
10637 '<tpl if="id==\'download\'">',
10638 '<a class="x-tool x-tool-pdf" href="{href}"></a>',
10640 '<tpl if="id!=\'download\'">',
10641 '<div class="x-tool x-tool-{id}">&#160;</div>',
10648 * <p>Note that the CSS class 'x-tool-pdf' should have an associated style rule which provides an
10649 * appropriate background image, something like:</p>
10651 a.x-tool-pdf {background-image: url(../shared/extjs/images/pdf.gif)!important;}
10655 * @cfg {Boolean} hideCollapseTool
10656 * <code>true</code> to hide the expand/collapse toggle button when <code>{@link #collapsible} == true</code>,
10657 * <code>false</code> to display it (defaults to <code>false</code>).
10660 * @cfg {Boolean} titleCollapse
10661 * <code>true</code> to allow expanding and collapsing the panel (when <code>{@link #collapsible} = true</code>)
10662 * by clicking anywhere in the header bar, <code>false</code>) to allow it only by clicking to tool button
10663 * (defaults to <code>false</code>)). If this panel is a child item of a border layout also see the
10664 * {@link Ext.layout.BorderLayout.Region BorderLayout.Region}
10665 * <code>{@link Ext.layout.BorderLayout.Region#floatable floatable}</code> config option.
10669 * @cfg {Mixed} floating
10670 * <p>This property is used to configure the underlying {@link Ext.Layer}. Acceptable values for this
10671 * configuration property are:</p><div class="mdetail-params"><ul>
10672 * <li><b><code>false</code></b> : <b>Default.</b><div class="sub-desc">Display the panel inline where it is
10673 * rendered.</div></li>
10674 * <li><b><code>true</code></b> : <div class="sub-desc">Float the panel (absolute position it with automatic
10675 * shimming and shadow).<ul>
10676 * <div class="sub-desc">Setting floating to true will create an Ext.Layer for this panel and display the
10677 * panel at negative offsets so that it is hidden.</div>
10678 * <div class="sub-desc">Since the panel will be absolute positioned, the position must be set explicitly
10679 * <i>after</i> render (e.g., <code>myPanel.setPosition(100,100);</code>).</div>
10680 * <div class="sub-desc"><b>Note</b>: when floating a panel you should always assign a fixed width,
10681 * otherwise it will be auto width and will expand to fill to the right edge of the viewport.</div>
10683 * <li><b><code>{@link Ext.Layer object}</code></b> : <div class="sub-desc">The specified object will be used
10684 * as the configuration object for the {@link Ext.Layer} that will be created.</div></li>
10688 * @cfg {Boolean/String} shadow
10689 * <code>true</code> (or a valid Ext.Shadow {@link Ext.Shadow#mode} value) to display a shadow behind the
10690 * panel, <code>false</code> to display no shadow (defaults to <code>'sides'</code>). Note that this option
10691 * only applies when <code>{@link #floating} = true</code>.
10694 * @cfg {Number} shadowOffset
10695 * The number of pixels to offset the shadow if displayed (defaults to <code>4</code>). Note that this
10696 * option only applies when <code>{@link #floating} = true</code>.
10699 * @cfg {Boolean} shim
10700 * <code>false</code> to disable the iframe shim in browsers which need one (defaults to <code>true</code>).
10701 * Note that this option only applies when <code>{@link #floating} = true</code>.
10704 * @cfg {Object/Array} keys
10705 * A {@link Ext.KeyMap} config object (in the format expected by {@link Ext.KeyMap#addBinding}
10706 * used to assign custom key handling to this panel (defaults to <code>null</code>).
10709 * @cfg {Boolean/Object} draggable
10710 * <p><code>true</code> to enable dragging of this Panel (defaults to <code>false</code>).</p>
10711 * <p>For custom drag/drop implementations, an <b>Ext.Panel.DD</b> config could also be passed
10712 * in this config instead of <code>true</code>. Ext.Panel.DD is an internal, undocumented class which
10713 * moves a proxy Element around in place of the Panel's element, but provides no other behaviour
10714 * during dragging or on drop. It is a subclass of {@link Ext.dd.DragSource}, so behaviour may be
10715 * added by implementing the interface methods of {@link Ext.dd.DragDrop} e.g.:
10721 renderTo: Ext.getBody(),
10727 // Config option of Ext.Panel.DD class.
10728 // It's a floating Panel, so do not show a placeholder proxy in the original position.
10729 insertProxy: false,
10731 // Called for each mousemove event while dragging the DD object.
10732 onDrag : function(e){
10733 // Record the x,y position of the drag proxy so that we can
10734 // position the Panel at end of drag.
10735 var pel = this.proxy.getEl();
10736 this.x = pel.getLeft(true);
10737 this.y = pel.getTop(true);
10739 // Keep the Shadow aligned if there is one.
10740 var s = this.panel.getEl().shadow;
10742 s.realign(this.x, this.y, pel.getWidth(), pel.getHeight());
10746 // Called on the mouseup event.
10747 endDrag : function(e){
10748 this.panel.setPosition(this.x, this.y);
10755 * @cfg {Boolean} disabled
10756 * Render this panel disabled (default is <code>false</code>). An important note when using the disabled
10757 * config on panels is that IE will often fail to initialize the disabled mask element correectly if
10758 * the panel's layout has not yet completed by the time the Panel is disabled during the render process.
10759 * If you experience this issue, you may need to instead use the {@link #afterlayout} event to initialize
10760 * the disabled state:
10769 single: true // important, as many layouts can occur
10776 * @cfg {Boolean} autoHeight
10777 * <code>true</code> to use height:'auto', <code>false</code> to use fixed height (defaults to <code>false</code>).
10778 * <b>Note</b>: Setting <code>autoHeight: true</code> means that the browser will manage the panel's height
10779 * based on its contents, and that Ext will not manage it at all. If the panel is within a layout that
10780 * manages dimensions (<code>fit</code>, <code>border</code>, etc.) then setting <code>autoHeight: true</code>
10781 * can cause issues with scrolling and will not generally work as expected since the panel will take
10782 * on the height of its contents rather than the height required by the Ext layout.
10787 * @cfg {String} baseCls
10788 * The base CSS class to apply to this panel's element (defaults to <code>'x-panel'</code>).
10789 * <p>Another option available by default is to specify <code>'x-plain'</code> which strips all styling
10790 * except for required attributes for Ext layouts to function (e.g. overflow:hidden).
10791 * See <code>{@link #unstyled}</code> also.</p>
10793 baseCls : 'x-panel',
10795 * @cfg {String} collapsedCls
10796 * A CSS class to add to the panel's element after it has been collapsed (defaults to
10797 * <code>'x-panel-collapsed'</code>).
10799 collapsedCls : 'x-panel-collapsed',
10801 * @cfg {Boolean} maskDisabled
10802 * <code>true</code> to mask the panel when it is {@link #disabled}, <code>false</code> to not mask it (defaults
10803 * to <code>true</code>). Either way, the panel will always tell its contained elements to disable themselves
10804 * when it is disabled, but masking the panel can provide an additional visual cue that the panel is
10807 maskDisabled : true,
10809 * @cfg {Boolean} animCollapse
10810 * <code>true</code> to animate the transition when the panel is collapsed, <code>false</code> to skip the
10811 * animation (defaults to <code>true</code> if the {@link Ext.Fx} class is available, otherwise <code>false</code>).
10813 animCollapse : Ext.enableFx,
10815 * @cfg {Boolean} headerAsText
10816 * <code>true</code> to display the panel <code>{@link #title}</code> in the <code>{@link #header}</code>,
10817 * <code>false</code> to hide it (defaults to <code>true</code>).
10819 headerAsText : true,
10821 * @cfg {String} buttonAlign
10822 * The alignment of any {@link #buttons} added to this panel. Valid values are <code>'right'</code>,
10823 * <code>'left'</code> and <code>'center'</code> (defaults to <code>'right'</code>).
10825 buttonAlign : 'right',
10827 * @cfg {Boolean} collapsed
10828 * <code>true</code> to render the panel collapsed, <code>false</code> to render it expanded (defaults to
10829 * <code>false</code>).
10833 * @cfg {Boolean} collapseFirst
10834 * <code>true</code> to make sure the collapse/expand toggle button always renders first (to the left of)
10835 * any other tools in the panel's title bar, <code>false</code> to render it last (defaults to <code>true</code>).
10837 collapseFirst : true,
10839 * @cfg {Number} minButtonWidth
10840 * Minimum width in pixels of all {@link #buttons} in this panel (defaults to <code>75</code>)
10842 minButtonWidth : 75,
10844 * @cfg {Boolean} unstyled
10845 * Overrides the <code>{@link #baseCls}</code> setting to <code>{@link #baseCls} = 'x-plain'</code> which renders
10846 * the panel unstyled except for required attributes for Ext layouts to function (e.g. overflow:hidden).
10849 * @cfg {String} elements
10850 * A comma-delimited list of panel elements to initialize when the panel is rendered. Normally, this list will be
10851 * generated automatically based on the items added to the panel at config time, but sometimes it might be useful to
10852 * make sure a structural element is rendered even if not specified at config time (for example, you may want
10853 * to add a button or toolbar dynamically after the panel has been rendered). Adding those elements to this
10854 * list will allocate the required placeholders in the panel when it is rendered. Valid values are<div class="mdetail-params"><ul>
10855 * <li><code>header</code></li>
10856 * <li><code>tbar</code> (top bar)</li>
10857 * <li><code>body</code></li>
10858 * <li><code>bbar</code> (bottom bar)</li>
10859 * <li><code>footer</code></li>
10861 * Defaults to '<code>body</code>'.
10865 * @cfg {Boolean} preventBodyReset
10866 * Defaults to <code>false</code>. When set to <code>true</code>, an extra css class <code>'x-panel-normal'</code>
10867 * will be added to the panel's element, effectively applying css styles suggested by the W3C
10868 * (see http://www.w3.org/TR/CSS21/sample.html) to the Panel's <b>body</b> element (not the header,
10871 preventBodyReset : false,
10874 * @cfg {Number/String} padding
10875 * A shortcut for setting a padding style on the body element. The value can either be
10876 * a number to be applied to all sides, or a normal css string describing padding.
10877 * Defaults to <tt>undefined</tt>.
10880 padding: undefined,
10882 /** @cfg {String} resizeEvent
10883 * The event to listen to for resizing in layouts. Defaults to <tt>'bodyresize'</tt>.
10885 resizeEvent: 'bodyresize',
10887 // protected - these could be used to customize the behavior of the window,
10888 // but changing them would not be useful without further mofifications and
10889 // could lead to unexpected or undesirable results.
10890 toolTarget : 'header',
10891 collapseEl : 'bwrap',
10893 disabledClass : '',
10895 // private, notify box this class will handle heights
10896 deferHeight : true,
10902 collapseDefaults : {
10907 initComponent : function(){
10908 Ext.Panel.superclass.initComponent.call(this);
10912 * @event bodyresize
10913 * Fires after the Panel has been resized.
10914 * @param {Ext.Panel} p the Panel which has been resized.
10915 * @param {Number} width The Panel body's new width.
10916 * @param {Number} height The Panel body's new height.
10920 * @event titlechange
10921 * Fires after the Panel title has been {@link #title set} or {@link #setTitle changed}.
10922 * @param {Ext.Panel} p the Panel which has had its title changed.
10923 * @param {String} The new title.
10927 * @event iconchange
10928 * Fires after the Panel icon class has been {@link #iconCls set} or {@link #setIconClass changed}.
10929 * @param {Ext.Panel} p the Panel which has had its {@link #iconCls icon class} changed.
10930 * @param {String} The new icon class.
10931 * @param {String} The old icon class.
10936 * Fires after the Panel has been collapsed.
10937 * @param {Ext.Panel} p the Panel that has been collapsed.
10942 * Fires after the Panel has been expanded.
10943 * @param {Ext.Panel} p The Panel that has been expanded.
10947 * @event beforecollapse
10948 * Fires before the Panel is collapsed. A handler can return false to cancel the collapse.
10949 * @param {Ext.Panel} p the Panel being collapsed.
10950 * @param {Boolean} animate True if the collapse is animated, else false.
10954 * @event beforeexpand
10955 * Fires before the Panel is expanded. A handler can return false to cancel the expand.
10956 * @param {Ext.Panel} p The Panel being expanded.
10957 * @param {Boolean} animate True if the expand is animated, else false.
10961 * @event beforeclose
10962 * Fires before the Panel is closed. Note that Panels do not directly support being closed, but some
10963 * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel. This event only
10964 * applies to such subclasses.
10965 * A handler can return false to cancel the close.
10966 * @param {Ext.Panel} p The Panel being closed.
10971 * Fires after the Panel is closed. Note that Panels do not directly support being closed, but some
10972 * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel.
10973 * @param {Ext.Panel} p The Panel that has been closed.
10978 * Fires after the Panel has been visually activated.
10979 * Note that Panels do not directly support being activated, but some Panel subclasses
10980 * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
10981 * activate and deactivate events under the control of the TabPanel.
10982 * @param {Ext.Panel} p The Panel that has been activated.
10986 * @event deactivate
10987 * Fires after the Panel has been visually deactivated.
10988 * Note that Panels do not directly support being deactivated, but some Panel subclasses
10989 * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
10990 * activate and deactivate events under the control of the TabPanel.
10991 * @param {Ext.Panel} p The Panel that has been deactivated.
10997 this.baseCls = 'x-plain';
11001 this.toolbars = [];
11004 this.elements += ',tbar';
11005 this.topToolbar = this.createToolbar(this.tbar);
11010 this.elements += ',bbar';
11011 this.bottomToolbar = this.createToolbar(this.bbar);
11015 if(this.header === true){
11016 this.elements += ',header';
11017 this.header = null;
11018 }else if(this.headerCfg || (this.title && this.header !== false)){
11019 this.elements += ',header';
11022 if(this.footerCfg || this.footer === true){
11023 this.elements += ',footer';
11024 this.footer = null;
11028 this.fbar = this.buttons;
11029 this.buttons = null;
11032 this.createFbar(this.fbar);
11035 this.on('render', this.doAutoLoad, this, {delay:10});
11040 createFbar : function(fbar){
11041 var min = this.minButtonWidth;
11042 this.elements += ',footer';
11043 this.fbar = this.createToolbar(fbar, {
11044 buttonAlign: this.buttonAlign,
11045 toolbarCls: 'x-panel-fbar',
11046 enableOverflow: false,
11047 defaults: function(c){
11049 minWidth: c.minWidth || min
11053 // @compat addButton and buttons could possibly be removed
11056 * This Panel's Array of buttons as created from the <code>{@link #buttons}</code>
11057 * config property. Read only.
11059 * @property buttons
11061 this.fbar.items.each(function(c){
11062 c.minWidth = c.minWidth || this.minButtonWidth;
11064 this.buttons = this.fbar.items.items;
11068 createToolbar: function(tb, options){
11070 // Convert array to proper toolbar config
11071 if(Ext.isArray(tb)){
11076 result = tb.events ? Ext.apply(tb, options) : this.createComponent(Ext.apply({}, tb, options), 'toolbar');
11077 this.toolbars.push(result);
11082 createElement : function(name, pnode){
11084 pnode.appendChild(this[name].dom);
11088 if(name === 'bwrap' || this.elements.indexOf(name) != -1){
11089 if(this[name+'Cfg']){
11090 this[name] = Ext.fly(pnode).createChild(this[name+'Cfg']);
11092 var el = document.createElement('div');
11093 el.className = this[name+'Cls'];
11094 this[name] = Ext.get(pnode.appendChild(el));
11096 if(this[name+'CssClass']){
11097 this[name].addClass(this[name+'CssClass']);
11099 if(this[name+'Style']){
11100 this[name].applyStyles(this[name+'Style']);
11106 onRender : function(ct, position){
11107 Ext.Panel.superclass.onRender.call(this, ct, position);
11108 this.createClasses();
11116 if(this.collapsible && !this.hideCollapseTool){
11117 this.tools = this.tools ? this.tools.slice(0) : [];
11118 this.tools[this.collapseFirst?'unshift':'push']({
11120 handler : this.toggleCollapse,
11127 this.elements += (this.header !== false) ? ',header' : '';
11131 el.addClass(this.baseCls);
11132 if(d.firstChild){ // existing markup
11133 this.header = el.down('.'+this.headerCls);
11134 this.bwrap = el.down('.'+this.bwrapCls);
11135 var cp = this.bwrap ? this.bwrap : el;
11136 this.tbar = cp.down('.'+this.tbarCls);
11137 this.body = cp.down('.'+this.bodyCls);
11138 this.bbar = cp.down('.'+this.bbarCls);
11139 this.footer = cp.down('.'+this.footerCls);
11140 this.fromMarkup = true;
11142 if (this.preventBodyReset === true) {
11143 el.addClass('x-panel-reset');
11146 el.addClass(this.cls);
11150 this.elements += ',footer';
11153 // This block allows for maximum flexibility and performance when using existing markup
11155 // framing requires special markup
11157 el.insertHtml('afterBegin', String.format(Ext.Element.boxMarkup, this.baseCls));
11159 this.createElement('header', d.firstChild.firstChild.firstChild);
11160 this.createElement('bwrap', d);
11162 // append the mid and bottom frame to the bwrap
11163 bw = this.bwrap.dom;
11164 var ml = d.childNodes[1], bl = d.childNodes[2];
11165 bw.appendChild(ml);
11166 bw.appendChild(bl);
11168 var mc = bw.firstChild.firstChild.firstChild;
11169 this.createElement('tbar', mc);
11170 this.createElement('body', mc);
11171 this.createElement('bbar', mc);
11172 this.createElement('footer', bw.lastChild.firstChild.firstChild);
11175 this.bwrap.dom.lastChild.className += ' x-panel-nofooter';
11178 * Store a reference to this element so:
11179 * a) We aren't looking it up all the time
11180 * b) The last element is reported incorrectly when using a loadmask
11182 this.ft = Ext.get(this.bwrap.dom.lastChild);
11183 this.mc = Ext.get(mc);
11185 this.createElement('header', d);
11186 this.createElement('bwrap', d);
11188 // append the mid and bottom frame to the bwrap
11189 bw = this.bwrap.dom;
11190 this.createElement('tbar', bw);
11191 this.createElement('body', bw);
11192 this.createElement('bbar', bw);
11193 this.createElement('footer', bw);
11196 this.body.addClass(this.bodyCls + '-noheader');
11198 this.tbar.addClass(this.tbarCls + '-noheader');
11203 if(Ext.isDefined(this.padding)){
11204 this.body.setStyle('padding', this.body.addUnits(this.padding));
11207 if(this.border === false){
11208 this.el.addClass(this.baseCls + '-noborder');
11209 this.body.addClass(this.bodyCls + '-noborder');
11211 this.header.addClass(this.headerCls + '-noborder');
11214 this.footer.addClass(this.footerCls + '-noborder');
11217 this.tbar.addClass(this.tbarCls + '-noborder');
11220 this.bbar.addClass(this.bbarCls + '-noborder');
11224 if(this.bodyBorder === false){
11225 this.body.addClass(this.bodyCls + '-noborder');
11228 this.bwrap.enableDisplayMode('block');
11231 this.header.unselectable();
11233 // for tools, we need to wrap any existing header markup
11234 if(this.headerAsText){
11235 this.header.dom.innerHTML =
11236 '<span class="' + this.headerTextCls + '">'+this.header.dom.innerHTML+'</span>';
11239 this.setIconClass(this.iconCls);
11245 this.makeFloating(this.floating);
11248 if(this.collapsible && this.titleCollapse && this.header){
11249 this.mon(this.header, 'click', this.toggleCollapse, this);
11250 this.header.setStyle('cursor', 'pointer');
11253 this.addTool.apply(this, ts);
11256 // Render Toolbars.
11258 this.footer.addClass('x-panel-btns');
11259 this.fbar.ownerCt = this;
11260 this.fbar.render(this.footer);
11261 this.footer.createChild({cls:'x-clear'});
11263 if(this.tbar && this.topToolbar){
11264 this.topToolbar.ownerCt = this;
11265 this.topToolbar.render(this.tbar);
11267 if(this.bbar && this.bottomToolbar){
11268 this.bottomToolbar.ownerCt = this;
11269 this.bottomToolbar.render(this.bbar);
11274 * Sets the CSS class that provides the icon image for this panel. This method will replace any existing
11275 * icon class if one has already been set and fire the {@link #iconchange} event after completion.
11276 * @param {String} cls The new CSS class name
11278 setIconClass : function(cls){
11279 var old = this.iconCls;
11280 this.iconCls = cls;
11281 if(this.rendered && this.header){
11283 this.header.addClass('x-panel-icon');
11284 this.header.replaceClass(old, this.iconCls);
11286 var hd = this.header,
11287 img = hd.child('img.x-panel-inline-icon');
11289 Ext.fly(img).replaceClass(old, this.iconCls);
11291 var hdspan = hd.child('span.' + this.headerTextCls);
11293 Ext.DomHelper.insertBefore(hdspan.dom, {
11294 tag:'img', alt: '', src: Ext.BLANK_IMAGE_URL, cls:'x-panel-inline-icon '+this.iconCls
11300 this.fireEvent('iconchange', this, cls, old);
11304 makeFloating : function(cfg){
11305 this.floating = true;
11306 this.el = new Ext.Layer(Ext.apply({}, cfg, {
11307 shadow: Ext.isDefined(this.shadow) ? this.shadow : 'sides',
11308 shadowOffset: this.shadowOffset,
11310 shim: this.shim === false ? false : undefined
11315 * Returns the {@link Ext.Toolbar toolbar} from the top (<code>{@link #tbar}</code>) section of the panel.
11316 * @return {Ext.Toolbar} The toolbar
11318 getTopToolbar : function(){
11319 return this.topToolbar;
11323 * Returns the {@link Ext.Toolbar toolbar} from the bottom (<code>{@link #bbar}</code>) section of the panel.
11324 * @return {Ext.Toolbar} The toolbar
11326 getBottomToolbar : function(){
11327 return this.bottomToolbar;
11331 * Returns the {@link Ext.Toolbar toolbar} from the footer (<code>{@link #fbar}</code>) section of the panel.
11332 * @return {Ext.Toolbar} The toolbar
11334 getFooterToolbar : function() {
11339 * Adds a button to this panel. Note that this method must be called prior to rendering. The preferred
11340 * approach is to add buttons via the {@link #buttons} config.
11341 * @param {String/Object} config A valid {@link Ext.Button} config. A string will become the text for a default
11342 * button config, an object will be treated as a button config object.
11343 * @param {Function} handler The function to be called on button {@link Ext.Button#click}
11344 * @param {Object} scope The scope (<code>this</code> reference) in which the button handler function is executed. Defaults to the Button.
11345 * @return {Ext.Button} The button that was added
11347 addButton : function(config, handler, scope){
11349 this.createFbar([]);
11352 if(Ext.isString(config)){
11353 config = {text: config};
11355 config = Ext.apply({
11360 return this.fbar.add(config);
11364 addTool : function(){
11365 if(!this.rendered){
11369 Ext.each(arguments, function(arg){
11370 this.tools.push(arg);
11374 // nowhere to render tools!
11375 if(!this[this.toolTarget]){
11378 if(!this.toolTemplate){
11379 // initialize the global tool template on first use
11380 var tt = new Ext.Template(
11381 '<div class="x-tool x-tool-{id}"> </div>'
11383 tt.disableFormats = true;
11385 Ext.Panel.prototype.toolTemplate = tt;
11387 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
11389 if(!this.tools[tc.id]){
11390 var overCls = 'x-tool-'+tc.id+'-over';
11391 var t = this.toolTemplate.insertFirst(this[this.toolTarget], tc, true);
11392 this.tools[tc.id] = t;
11393 t.enableDisplayMode('block');
11394 this.mon(t, 'click', this.createToolHandler(t, tc, overCls, this));
11396 this.mon(t, tc.on);
11402 if(Ext.isObject(tc.qtip)){
11403 Ext.QuickTips.register(Ext.apply({
11407 t.dom.qtip = tc.qtip;
11410 t.addClassOnOver(overCls);
11415 onLayout : function(shallow, force){
11416 Ext.Panel.superclass.onLayout.apply(this, arguments);
11417 if(this.hasLayout && this.toolbars.length > 0){
11418 Ext.each(this.toolbars, function(tb){
11419 tb.doLayout(undefined, force);
11425 syncHeight : function(){
11426 var h = this.toolbarHeight,
11428 lsh = this.lastSize.height,
11431 if(this.autoHeight || !Ext.isDefined(lsh) || lsh == 'auto'){
11436 if(h != this.getToolbarHeight()){
11437 h = Math.max(0, lsh - this.getFrameHeight());
11440 this.toolbarHeight = this.getToolbarHeight();
11441 this.onBodyResize(sz.width, sz.height);
11446 onShow : function(){
11448 return this.el.show();
11450 Ext.Panel.superclass.onShow.call(this);
11454 onHide : function(){
11456 return this.el.hide();
11458 Ext.Panel.superclass.onHide.call(this);
11462 createToolHandler : function(t, tc, overCls, panel){
11463 return function(e){
11464 t.removeClass(overCls);
11465 if(tc.stopEvent !== false){
11469 tc.handler.call(tc.scope || t, e, t, panel, tc);
11475 afterRender : function(){
11476 if(this.floating && !this.hidden){
11480 this.setTitle(this.title);
11482 Ext.Panel.superclass.afterRender.call(this); // do sizing calcs last
11483 if (this.collapsed) {
11484 this.collapsed = false;
11485 this.collapse(false);
11491 getKeyMap : function(){
11493 this.keyMap = new Ext.KeyMap(this.el, this.keys);
11495 return this.keyMap;
11499 initEvents : function(){
11503 if(this.draggable){
11504 this.initDraggable();
11506 if(this.toolbars.length > 0){
11507 Ext.each(this.toolbars, function(tb){
11511 afterlayout: this.syncHeight,
11512 remove: this.syncHeight
11521 initDraggable : function(){
11523 * <p>If this Panel is configured {@link #draggable}, this property will contain
11524 * an instance of {@link Ext.dd.DragSource} which handles dragging the Panel.</p>
11525 * The developer must provide implementations of the abstract methods of {@link Ext.dd.DragSource}
11526 * in order to supply behaviour for each stage of the drag/drop process. See {@link #draggable}.
11527 * @type Ext.dd.DragSource.
11530 this.dd = new Ext.Panel.DD(this, Ext.isBoolean(this.draggable) ? null : this.draggable);
11534 beforeEffect : function(anim){
11536 this.el.beforeAction();
11538 if(anim !== false){
11539 this.el.addClass('x-panel-animated');
11544 afterEffect : function(anim){
11546 this.el.removeClass('x-panel-animated');
11549 // private - wraps up an animation param with internal callbacks
11550 createEffect : function(a, cb, scope){
11558 }else if(!a.callback){
11560 }else { // wrap it up
11561 o.callback = function(){
11563 Ext.callback(a.callback, a.scope);
11566 return Ext.applyIf(o, a);
11570 * Collapses the panel body so that it becomes hidden. Fires the {@link #beforecollapse} event which will
11571 * cancel the collapse action if it returns false.
11572 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
11573 * {@link #animCollapse} panel config)
11574 * @return {Ext.Panel} this
11576 collapse : function(animate){
11577 if(this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforecollapse', this, animate) === false){
11580 var doAnim = animate === true || (animate !== false && this.animCollapse);
11581 this.beforeEffect(doAnim);
11582 this.onCollapse(doAnim, animate);
11587 onCollapse : function(doAnim, animArg){
11589 this[this.collapseEl].slideOut(this.slideAnchor,
11590 Ext.apply(this.createEffect(animArg||true, this.afterCollapse, this),
11591 this.collapseDefaults));
11593 this[this.collapseEl].hide(this.hideMode);
11594 this.afterCollapse(false);
11599 afterCollapse : function(anim){
11600 this.collapsed = true;
11601 this.el.addClass(this.collapsedCls);
11602 if(anim !== false){
11603 this[this.collapseEl].hide(this.hideMode);
11605 this.afterEffect(anim);
11607 // Reset lastSize of all sub-components so they KNOW they are in a collapsed container
11608 this.cascade(function(c) {
11610 c.lastSize = { width: undefined, height: undefined };
11613 this.fireEvent('collapse', this);
11617 * Expands the panel body so that it becomes visible. Fires the {@link #beforeexpand} event which will
11618 * cancel the expand action if it returns false.
11619 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
11620 * {@link #animCollapse} panel config)
11621 * @return {Ext.Panel} this
11623 expand : function(animate){
11624 if(!this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforeexpand', this, animate) === false){
11627 var doAnim = animate === true || (animate !== false && this.animCollapse);
11628 this.el.removeClass(this.collapsedCls);
11629 this.beforeEffect(doAnim);
11630 this.onExpand(doAnim, animate);
11635 onExpand : function(doAnim, animArg){
11637 this[this.collapseEl].slideIn(this.slideAnchor,
11638 Ext.apply(this.createEffect(animArg||true, this.afterExpand, this),
11639 this.expandDefaults));
11641 this[this.collapseEl].show(this.hideMode);
11642 this.afterExpand(false);
11647 afterExpand : function(anim){
11648 this.collapsed = false;
11649 if(anim !== false){
11650 this[this.collapseEl].show(this.hideMode);
11652 this.afterEffect(anim);
11653 if (this.deferLayout) {
11654 delete this.deferLayout;
11655 this.doLayout(true);
11657 this.fireEvent('expand', this);
11661 * Shortcut for performing an {@link #expand} or {@link #collapse} based on the current state of the panel.
11662 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
11663 * {@link #animCollapse} panel config)
11664 * @return {Ext.Panel} this
11666 toggleCollapse : function(animate){
11667 this[this.collapsed ? 'expand' : 'collapse'](animate);
11672 onDisable : function(){
11673 if(this.rendered && this.maskDisabled){
11676 Ext.Panel.superclass.onDisable.call(this);
11680 onEnable : function(){
11681 if(this.rendered && this.maskDisabled){
11684 Ext.Panel.superclass.onEnable.call(this);
11688 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
11692 if(Ext.isDefined(w) || Ext.isDefined(h)){
11693 if(!this.collapsed){
11694 // First, set the the Panel's body width.
11695 // If we have auto-widthed it, get the resulting full offset width so we can size the Toolbars to match
11696 // The Toolbars must not buffer this resize operation because we need to know their heights.
11698 if(Ext.isNumber(w)){
11699 this.body.setWidth(w = this.adjustBodyWidth(w - this.getFrameWidth()));
11700 } else if (w == 'auto') {
11701 w = this.body.setWidth('auto').dom.offsetWidth;
11703 w = this.body.dom.offsetWidth;
11707 this.tbar.setWidth(w);
11708 if(this.topToolbar){
11709 this.topToolbar.setSize(w);
11713 this.bbar.setWidth(w);
11714 if(this.bottomToolbar){
11715 this.bottomToolbar.setSize(w);
11716 // The bbar does not move on resize without this.
11718 this.bbar.setStyle('position', 'static');
11719 this.bbar.setStyle('position', '');
11724 this.footer.setWidth(w);
11726 this.fbar.setSize(Ext.isIE ? (w - this.footer.getFrameWidth('lr')) : 'auto');
11730 // At this point, the Toolbars must be layed out for getFrameHeight to find a result.
11731 if(Ext.isNumber(h)){
11732 h = Math.max(0, h - this.getFrameHeight());
11733 //h = Math.max(0, h - (this.getHeight() - this.body.getHeight()));
11734 this.body.setHeight(h);
11735 }else if(h == 'auto'){
11736 this.body.setHeight(h);
11739 if(this.disabled && this.el._mask){
11740 this.el._mask.setSize(this.el.dom.clientWidth, this.el.getHeight());
11743 // Adds an event to set the correct height afterExpand. This accounts for the deferHeight flag in panel
11744 this.queuedBodySize = {width: w, height: h};
11745 if(!this.queuedExpand && this.allowQueuedExpand !== false){
11746 this.queuedExpand = true;
11747 this.on('expand', function(){
11748 delete this.queuedExpand;
11749 this.onResize(this.queuedBodySize.width, this.queuedBodySize.height);
11750 }, this, {single:true});
11753 this.onBodyResize(w, h);
11756 Ext.Panel.superclass.onResize.call(this, adjWidth, adjHeight, rawWidth, rawHeight);
11761 onBodyResize: function(w, h){
11762 this.fireEvent('bodyresize', this, w, h);
11766 getToolbarHeight: function(){
11769 Ext.each(this.toolbars, function(tb){
11770 h += tb.getHeight();
11777 adjustBodyHeight : function(h){
11782 adjustBodyWidth : function(w){
11787 onPosition : function(){
11792 * Returns the width in pixels of the framing elements of this panel (not including the body width). To
11793 * retrieve the body width see {@link #getInnerWidth}.
11794 * @return {Number} The frame width
11796 getFrameWidth : function(){
11797 var w = this.el.getFrameWidth('lr') + this.bwrap.getFrameWidth('lr');
11800 var l = this.bwrap.dom.firstChild;
11801 w += (Ext.fly(l).getFrameWidth('l') + Ext.fly(l.firstChild).getFrameWidth('r'));
11802 w += this.mc.getFrameWidth('lr');
11808 * Returns the height in pixels of the framing elements of this panel (including any top and bottom bars and
11809 * header and footer elements, but not including the body height). To retrieve the body height see {@link #getInnerHeight}.
11810 * @return {Number} The frame height
11812 getFrameHeight : function() {
11813 var h = this.el.getFrameWidth('tb') + this.bwrap.getFrameWidth('tb');
11814 h += (this.tbar ? this.tbar.getHeight() : 0) +
11815 (this.bbar ? this.bbar.getHeight() : 0);
11818 h += this.el.dom.firstChild.offsetHeight + this.ft.dom.offsetHeight + this.mc.getFrameWidth('tb');
11820 h += (this.header ? this.header.getHeight() : 0) +
11821 (this.footer ? this.footer.getHeight() : 0);
11827 * Returns the width in pixels of the body element (not including the width of any framing elements).
11828 * For the frame width see {@link #getFrameWidth}.
11829 * @return {Number} The body width
11831 getInnerWidth : function(){
11832 return this.getSize().width - this.getFrameWidth();
11836 * Returns the height in pixels of the body element (not including the height of any framing elements).
11837 * For the frame height see {@link #getFrameHeight}.
11838 * @return {Number} The body height
11840 getInnerHeight : function(){
11841 return this.body.getHeight();
11843 return this.getSize().height - this.getFrameHeight();
11848 syncShadow : function(){
11850 this.el.sync(true);
11855 getLayoutTarget : function(){
11860 getContentTarget : function(){
11865 * <p>Sets the title text for the panel and optionally the {@link #iconCls icon class}.</p>
11866 * <p>In order to be able to set the title, a header element must have been created
11867 * for the Panel. This is triggered either by configuring the Panel with a non-blank <code>{@link #title}</code>,
11868 * or configuring it with <code><b>{@link #header}: true</b></code>.</p>
11869 * @param {String} title The title text to set
11870 * @param {String} iconCls (optional) {@link #iconCls iconCls} A user-defined CSS class that provides the icon image for this panel
11872 setTitle : function(title, iconCls){
11873 this.title = title;
11874 if(this.header && this.headerAsText){
11875 this.header.child('span').update(title);
11878 this.setIconClass(iconCls);
11880 this.fireEvent('titlechange', this, title);
11885 * Get the {@link Ext.Updater} for this panel. Enables you to perform Ajax updates of this panel's body.
11886 * @return {Ext.Updater} The Updater
11888 getUpdater : function(){
11889 return this.body.getUpdater();
11893 * Loads this content panel immediately with content returned from an XHR call.
11894 * @param {Object/String/Function} config A config object containing any of the following options:
11897 url: 'your-url.php',
11898 params: {param1: 'foo', param2: 'bar'}, // or a URL encoded string
11899 callback: yourFunction,
11900 scope: yourObject, // optional scope for the callback
11903 text: 'Loading...',
11908 * The only required property is url. The optional properties nocache, text and scripts
11909 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their
11910 * associated property on this panel Updater instance.
11911 * @return {Ext.Panel} this
11914 var um = this.body.getUpdater();
11915 um.update.apply(um, arguments);
11920 beforeDestroy : function(){
11921 Ext.Panel.superclass.beforeDestroy.call(this);
11923 this.header.removeAllListeners();
11926 for(var k in this.tools){
11927 Ext.destroy(this.tools[k]);
11930 if(this.toolbars.length > 0){
11931 Ext.each(this.toolbars, function(tb){
11932 tb.un('afterlayout', this.syncHeight, this);
11933 tb.un('remove', this.syncHeight, this);
11936 if(Ext.isArray(this.buttons)){
11937 while(this.buttons.length) {
11938 Ext.destroy(this.buttons[0]);
11960 Ext.destroy(this.toolbars);
11964 createClasses : function(){
11965 this.headerCls = this.baseCls + '-header';
11966 this.headerTextCls = this.baseCls + '-header-text';
11967 this.bwrapCls = this.baseCls + '-bwrap';
11968 this.tbarCls = this.baseCls + '-tbar';
11969 this.bodyCls = this.baseCls + '-body';
11970 this.bbarCls = this.baseCls + '-bbar';
11971 this.footerCls = this.baseCls + '-footer';
11975 createGhost : function(cls, useShim, appendTo){
11976 var el = document.createElement('div');
11977 el.className = 'x-panel-ghost ' + (cls ? cls : '');
11979 el.appendChild(this.el.dom.firstChild.cloneNode(true));
11981 Ext.fly(el.appendChild(document.createElement('ul'))).setHeight(this.bwrap.getHeight());
11982 el.style.width = this.el.dom.offsetWidth + 'px';;
11984 this.container.dom.appendChild(el);
11986 Ext.getDom(appendTo).appendChild(el);
11988 if(useShim !== false && this.el.useShim !== false){
11989 var layer = new Ext.Layer({shadow:false, useDisplay:true, constrain:false}, el);
11993 return new Ext.Element(el);
11998 doAutoLoad : function(){
11999 var u = this.body.getUpdater();
12001 u.setRenderer(this.renderer);
12003 u.update(Ext.isObject(this.autoLoad) ? this.autoLoad : {url: this.autoLoad});
12007 * Retrieve a tool by id.
12008 * @param {String} id
12009 * @return {Object} tool
12011 getTool : function(id) {
12012 return this.tools[id];
12016 * @cfg {String} autoEl @hide
12019 Ext.reg('panel', Ext.Panel);
12021 * @class Ext.Editor
12022 * @extends Ext.Component
12023 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
12025 * Create a new Editor
12026 * @param {Object} config The config object
12029 Ext.Editor = function(field, config){
12031 this.field = Ext.create(field.field, 'textfield');
12032 config = Ext.apply({}, field); // copy so we don't disturb original config
12033 delete config.field;
12035 this.field = field;
12037 Ext.Editor.superclass.constructor.call(this, config);
12040 Ext.extend(Ext.Editor, Ext.Component, {
12042 * @cfg {Ext.form.Field} field
12043 * The Field object (or descendant) or config object for field
12046 * @cfg {Boolean} allowBlur
12047 * True to {@link #completeEdit complete the editing process} if in edit mode when the
12048 * field is blurred. Defaults to <tt>true</tt>.
12052 * @cfg {Boolean/String} autoSize
12053 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
12054 * or "height" to adopt the height only, "none" to always use the field dimensions. (defaults to false)
12057 * @cfg {Boolean} revertInvalid
12058 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
12059 * validation fails (defaults to true)
12062 * @cfg {Boolean} ignoreNoChange
12063 * True to skip the edit completion process (no save, no events fired) if the user completes an edit and
12064 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
12065 * will never be ignored.
12068 * @cfg {Boolean} hideEl
12069 * False to keep the bound element visible while the editor is displayed (defaults to true)
12072 * @cfg {Mixed} value
12073 * The data value of the underlying field (defaults to "")
12077 * @cfg {String} alignment
12078 * The position to align to (see {@link Ext.Element#alignTo} for more details, defaults to "c-c?").
12082 * @cfg {Array} offsets
12083 * The offsets to use when aligning (see {@link Ext.Element#alignTo} for more details. Defaults to <tt>[0, 0]</tt>.
12087 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
12088 * for bottom-right shadow (defaults to "frame")
12092 * @cfg {Boolean} constrain True to constrain the editor to the viewport
12096 * @cfg {Boolean} swallowKeys Handle the keydown/keypress events so they don't propagate (defaults to true)
12098 swallowKeys : true,
12100 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed. Defaults to <tt>true</tt>.
12102 completeOnEnter : true,
12104 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed. Defaults to <tt>true</tt>.
12106 cancelOnEsc : true,
12108 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
12112 initComponent : function(){
12113 Ext.Editor.superclass.initComponent.call(this);
12116 * @event beforestartedit
12117 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
12118 * false from the handler of this event.
12119 * @param {Editor} this
12120 * @param {Ext.Element} boundEl The underlying element bound to this editor
12121 * @param {Mixed} value The field value being set
12126 * Fires when this editor is displayed
12127 * @param {Ext.Element} boundEl The underlying element bound to this editor
12128 * @param {Mixed} value The starting field value
12132 * @event beforecomplete
12133 * Fires after a change has been made to the field, but before the change is reflected in the underlying
12134 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
12135 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
12136 * event will not fire since no edit actually occurred.
12137 * @param {Editor} this
12138 * @param {Mixed} value The current field value
12139 * @param {Mixed} startValue The original field value
12144 * Fires after editing is complete and any changed value has been written to the underlying field.
12145 * @param {Editor} this
12146 * @param {Mixed} value The current field value
12147 * @param {Mixed} startValue The original field value
12151 * @event canceledit
12152 * Fires after editing has been canceled and the editor's value has been reset.
12153 * @param {Editor} this
12154 * @param {Mixed} value The user-entered field value that was discarded
12155 * @param {Mixed} startValue The original field value that was set back into the editor after cancel
12159 * @event specialkey
12160 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
12161 * {@link Ext.EventObject#getKey} to determine which key was pressed.
12162 * @param {Ext.form.Field} this
12163 * @param {Ext.EventObject} e The event object
12170 onRender : function(ct, position){
12171 this.el = new Ext.Layer({
12172 shadow: this.shadow,
12176 shadowOffset: this.shadowOffset || 4,
12178 constrain: this.constrain
12181 this.el.setZIndex(this.zIndex);
12183 this.el.setStyle("overflow", Ext.isGecko ? "auto" : "hidden");
12184 if(this.field.msgTarget != 'title'){
12185 this.field.msgTarget = 'qtip';
12187 this.field.inEditor = true;
12188 this.mon(this.field, {
12191 specialkey: this.onSpecialKey
12193 if(this.field.grow){
12194 this.mon(this.field, "autosize", this.el.sync, this.el, {delay:1});
12196 this.field.render(this.el).show();
12197 this.field.getEl().dom.name = '';
12198 if(this.swallowKeys){
12199 this.field.el.swallowEvent([
12200 'keypress', // *** Opera
12201 'keydown' // *** all other browsers
12207 onSpecialKey : function(field, e){
12208 var key = e.getKey(),
12209 complete = this.completeOnEnter && key == e.ENTER,
12210 cancel = this.cancelOnEsc && key == e.ESC;
12211 if(complete || cancel){
12214 this.completeEdit();
12218 if(field.triggerBlur){
12219 field.triggerBlur();
12222 this.fireEvent('specialkey', field, e);
12226 * Starts the editing process and shows the editor.
12227 * @param {Mixed} el The element to edit
12228 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
12229 * to the innerHTML of el.
12231 startEdit : function(el, value){
12233 this.completeEdit();
12235 this.boundEl = Ext.get(el);
12236 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
12237 if(!this.rendered){
12238 this.render(this.parentEl || document.body);
12240 if(this.fireEvent("beforestartedit", this, this.boundEl, v) !== false){
12241 this.startValue = v;
12242 this.field.reset();
12243 this.field.setValue(v);
12244 this.realign(true);
12245 this.editing = true;
12251 doAutoSize : function(){
12253 var sz = this.boundEl.getSize(),
12254 fs = this.field.getSize();
12256 switch(this.autoSize){
12258 this.setSize(sz.width, fs.height);
12261 this.setSize(fs.width, sz.height);
12264 this.setSize(fs.width, fs.height);
12267 this.setSize(sz.width, sz.height);
12273 * Sets the height and width of this editor.
12274 * @param {Number} width The new width
12275 * @param {Number} height The new height
12277 setSize : function(w, h){
12278 delete this.field.lastSize;
12279 this.field.setSize(w, h);
12281 // IE7 in strict mode doesn't size properly.
12282 if(Ext.isGecko2 || Ext.isOpera || (Ext.isIE7 && Ext.isStrict)){
12283 // prevent layer scrollbars
12284 this.el.setSize(w, h);
12291 * Realigns the editor to the bound field based on the current alignment config value.
12292 * @param {Boolean} autoSize (optional) True to size the field to the dimensions of the bound element.
12294 realign : function(autoSize){
12295 if(autoSize === true){
12298 this.el.alignTo(this.boundEl, this.alignment, this.offsets);
12302 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
12303 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
12305 completeEdit : function(remainVisible){
12309 // Assert combo values first
12310 if (this.field.assertValue) {
12311 this.field.assertValue();
12313 var v = this.getValue();
12314 if(!this.field.isValid()){
12315 if(this.revertInvalid !== false){
12316 this.cancelEdit(remainVisible);
12320 if(String(v) === String(this.startValue) && this.ignoreNoChange){
12321 this.hideEdit(remainVisible);
12324 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
12325 v = this.getValue();
12326 if(this.updateEl && this.boundEl){
12327 this.boundEl.update(v);
12329 this.hideEdit(remainVisible);
12330 this.fireEvent("complete", this, v, this.startValue);
12335 onShow : function(){
12337 if(this.hideEl !== false){
12338 this.boundEl.hide();
12340 this.field.show().focus(false, true);
12341 this.fireEvent("startedit", this.boundEl, this.startValue);
12345 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
12346 * reverted to the original starting value.
12347 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
12348 * cancel (defaults to false)
12350 cancelEdit : function(remainVisible){
12352 var v = this.getValue();
12353 this.setValue(this.startValue);
12354 this.hideEdit(remainVisible);
12355 this.fireEvent("canceledit", this, v, this.startValue);
12360 hideEdit: function(remainVisible){
12361 if(remainVisible !== true){
12362 this.editing = false;
12368 onBlur : function(){
12369 // selectSameEditor flag allows the same editor to be started without onBlur firing on itself
12370 if(this.allowBlur === true && this.editing && this.selectSameEditor !== true){
12371 this.completeEdit();
12376 onHide : function(){
12378 this.completeEdit();
12382 if(this.field.collapse){
12383 this.field.collapse();
12386 if(this.hideEl !== false){
12387 this.boundEl.show();
12392 * Sets the data value of the editor
12393 * @param {Mixed} value Any valid value supported by the underlying field
12395 setValue : function(v){
12396 this.field.setValue(v);
12400 * Gets the data value of the editor
12401 * @return {Mixed} The data value
12403 getValue : function(){
12404 return this.field.getValue();
12407 beforeDestroy : function(){
12408 Ext.destroyMembers(this, 'field');
12410 delete this.parentEl;
12411 delete this.boundEl;
12414 Ext.reg('editor', Ext.Editor);
12416 * @class Ext.ColorPalette
12417 * @extends Ext.Component
12418 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
12419 * Here's an example of typical usage:
12421 var cp = new Ext.ColorPalette({value:'993300'}); // initial selected color
12422 cp.render('my-div');
12424 cp.on('select', function(palette, selColor){
12425 // do something with selColor
12429 * Create a new ColorPalette
12430 * @param {Object} config The config object
12431 * @xtype colorpalette
12433 Ext.ColorPalette = Ext.extend(Ext.Component, {
12435 * @cfg {String} tpl An existing XTemplate instance to be used in place of the default template for rendering the component.
12438 * @cfg {String} itemCls
12439 * The CSS class to apply to the containing element (defaults to 'x-color-palette')
12441 itemCls : 'x-color-palette',
12443 * @cfg {String} value
12444 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
12445 * the hex codes are case-sensitive.
12449 * @cfg {String} clickEvent
12450 * The DOM event that will cause a color to be selected. This can be any valid event name (dblclick, contextmenu).
12451 * Defaults to <tt>'click'</tt>.
12453 clickEvent :'click',
12455 ctype : 'Ext.ColorPalette',
12458 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the {@link #select} event
12460 allowReselect : false,
12463 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
12464 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
12465 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
12466 * of colors with the width setting until the box is symmetrical.</p>
12467 * <p>You can override individual colors if needed:</p>
12469 var cp = new Ext.ColorPalette();
12470 cp.colors[0] = 'FF0000'; // change the first box to red
12473 Or you can provide a custom array of your own for complete control:
12475 var cp = new Ext.ColorPalette();
12476 cp.colors = ['000000', '993300', '333300'];
12481 '000000', '993300', '333300', '003300', '003366', '000080', '333399', '333333',
12482 '800000', 'FF6600', '808000', '008000', '008080', '0000FF', '666699', '808080',
12483 'FF0000', 'FF9900', '99CC00', '339966', '33CCCC', '3366FF', '800080', '969696',
12484 'FF00FF', 'FFCC00', 'FFFF00', '00FF00', '00FFFF', '00CCFF', '993366', 'C0C0C0',
12485 'FF99CC', 'FFCC99', 'FFFF99', 'CCFFCC', 'CCFFFF', '99CCFF', 'CC99FF', 'FFFFFF'
12489 * @cfg {Function} handler
12490 * Optional. A function that will handle the select event of this palette.
12491 * The handler is passed the following parameters:<div class="mdetail-params"><ul>
12492 * <li><code>palette</code> : ColorPalette<div class="sub-desc">The {@link #palette Ext.ColorPalette}.</div></li>
12493 * <li><code>color</code> : String<div class="sub-desc">The 6-digit color hex code (without the # symbol).</div></li>
12497 * @cfg {Object} scope
12498 * The scope (<tt><b>this</b></tt> reference) in which the <code>{@link #handler}</code>
12499 * function will be called. Defaults to this ColorPalette instance.
12503 initComponent : function(){
12504 Ext.ColorPalette.superclass.initComponent.call(this);
12508 * Fires when a color is selected
12509 * @param {ColorPalette} this
12510 * @param {String} color The 6-digit color hex code (without the # symbol)
12516 this.on('select', this.handler, this.scope, true);
12521 onRender : function(container, position){
12526 Ext.ColorPalette.superclass.onRender.call(this, container, position);
12527 var t = this.tpl || new Ext.XTemplate(
12528 '<tpl for="."><a href="#" class="color-{.}" hidefocus="on"><em><span style="background:#{.}" unselectable="on"> </span></em></a></tpl>'
12530 t.overwrite(this.el, this.colors);
12531 this.mon(this.el, this.clickEvent, this.handleClick, this, {delegate: 'a'});
12532 if(this.clickEvent != 'click'){
12533 this.mon(this.el, 'click', Ext.emptyFn, this, {delegate: 'a', preventDefault: true});
12538 afterRender : function(){
12539 Ext.ColorPalette.superclass.afterRender.call(this);
12541 var s = this.value;
12543 this.select(s, true);
12548 handleClick : function(e, t){
12549 e.preventDefault();
12550 if(!this.disabled){
12551 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
12552 this.select(c.toUpperCase());
12557 * Selects the specified color in the palette (fires the {@link #select} event)
12558 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
12559 * @param {Boolean} suppressEvent (optional) True to stop the select event from firing. Defaults to <tt>false</tt>.
12561 select : function(color, suppressEvent){
12562 color = color.replace('#', '');
12563 if(color != this.value || this.allowReselect){
12566 el.child('a.color-'+this.value).removeClass('x-color-palette-sel');
12568 el.child('a.color-'+color).addClass('x-color-palette-sel');
12569 this.value = color;
12570 if(suppressEvent !== true){
12571 this.fireEvent('select', this, color);
12577 * @cfg {String} autoEl @hide
12580 Ext.reg('colorpalette', Ext.ColorPalette);/**
12581 * @class Ext.DatePicker
12582 * @extends Ext.Component
12583 * <p>A popup date picker. This class is used by the {@link Ext.form.DateField DateField} class
12584 * to allow browsing and selection of valid dates.</p>
12585 * <p>All the string values documented below may be overridden by including an Ext locale file in
12588 * Create a new DatePicker
12589 * @param {Object} config The config object
12590 * @xtype datepicker
12592 Ext.DatePicker = Ext.extend(Ext.BoxComponent, {
12594 * @cfg {String} todayText
12595 * The text to display on the button that selects the current date (defaults to <code>'Today'</code>)
12597 todayText : 'Today',
12599 * @cfg {String} okText
12600 * The text to display on the ok button (defaults to <code>' OK '</code> to give the user extra clicking room)
12602 okText : ' OK ',
12604 * @cfg {String} cancelText
12605 * The text to display on the cancel button (defaults to <code>'Cancel'</code>)
12607 cancelText : 'Cancel',
12609 * @cfg {Function} handler
12610 * Optional. A function that will handle the select event of this picker.
12611 * The handler is passed the following parameters:<div class="mdetail-params"><ul>
12612 * <li><code>picker</code> : DatePicker<div class="sub-desc">This DatePicker.</div></li>
12613 * <li><code>date</code> : Date<div class="sub-desc">The selected date.</div></li>
12617 * @cfg {Object} scope
12618 * The scope (<code><b>this</b></code> reference) in which the <code>{@link #handler}</code>
12619 * function will be called. Defaults to this DatePicker instance.
12622 * @cfg {String} todayTip
12623 * A string used to format the message for displaying in a tooltip over the button that
12624 * selects the current date. Defaults to <code>'{0} (Spacebar)'</code> where
12625 * the <code>{0}</code> token is replaced by today's date.
12627 todayTip : '{0} (Spacebar)',
12629 * @cfg {String} minText
12630 * The error text to display if the minDate validation fails (defaults to <code>'This date is before the minimum date'</code>)
12632 minText : 'This date is before the minimum date',
12634 * @cfg {String} maxText
12635 * The error text to display if the maxDate validation fails (defaults to <code>'This date is after the maximum date'</code>)
12637 maxText : 'This date is after the maximum date',
12639 * @cfg {String} format
12640 * The default date format string which can be overriden for localization support. The format must be
12641 * valid according to {@link Date#parseDate} (defaults to <code>'m/d/y'</code>).
12645 * @cfg {String} disabledDaysText
12646 * The tooltip to display when the date falls on a disabled day (defaults to <code>'Disabled'</code>)
12648 disabledDaysText : 'Disabled',
12650 * @cfg {String} disabledDatesText
12651 * The tooltip text to display when the date falls on a disabled date (defaults to <code>'Disabled'</code>)
12653 disabledDatesText : 'Disabled',
12655 * @cfg {Array} monthNames
12656 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
12658 monthNames : Date.monthNames,
12660 * @cfg {Array} dayNames
12661 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
12663 dayNames : Date.dayNames,
12665 * @cfg {String} nextText
12666 * The next month navigation button tooltip (defaults to <code>'Next Month (Control+Right)'</code>)
12668 nextText : 'Next Month (Control+Right)',
12670 * @cfg {String} prevText
12671 * The previous month navigation button tooltip (defaults to <code>'Previous Month (Control+Left)'</code>)
12673 prevText : 'Previous Month (Control+Left)',
12675 * @cfg {String} monthYearText
12676 * The header month selector tooltip (defaults to <code>'Choose a month (Control+Up/Down to move years)'</code>)
12678 monthYearText : 'Choose a month (Control+Up/Down to move years)',
12680 * @cfg {Number} startDay
12681 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12685 * @cfg {Boolean} showToday
12686 * False to hide the footer area containing the Today button and disable the keyboard handler for spacebar
12687 * that selects the current date (defaults to <code>true</code>).
12691 * @cfg {Date} minDate
12692 * Minimum allowable date (JavaScript date object, defaults to null)
12695 * @cfg {Date} maxDate
12696 * Maximum allowable date (JavaScript date object, defaults to null)
12699 * @cfg {Array} disabledDays
12700 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
12703 * @cfg {RegExp} disabledDatesRE
12704 * JavaScript regular expression used to disable a pattern of dates (defaults to null). The {@link #disabledDates}
12705 * config will generate this regex internally, but if you specify disabledDatesRE it will take precedence over the
12706 * disabledDates value.
12709 * @cfg {Array} disabledDates
12710 * An array of 'dates' to disable, as strings. These strings will be used to build a dynamic regular
12711 * expression so they are very powerful. Some examples:
12713 * <li>['03/08/2003', '09/16/2003'] would disable those exact dates</li>
12714 * <li>['03/08', '09/16'] would disable those days for every year</li>
12715 * <li>['^03/08'] would only match the beginning (useful if you are using short years)</li>
12716 * <li>['03/../2006'] would disable every day in March 2006</li>
12717 * <li>['^03'] would disable every day in every March</li>
12719 * Note that the format of the dates included in the array should exactly match the {@link #format} config.
12720 * In order to support regular expressions, if you are using a date format that has '.' in it, you will have to
12721 * escape the dot when restricting dates. For example: ['03\\.08\\.03'].
12725 // Set by other components to stop the picker focus being updated when the value changes.
12726 focusOnSelect: true,
12728 // default value used to initialise each date in the DatePicker
12729 // (note: 12 noon was chosen because it steers well clear of all DST timezone changes)
12730 initHour: 12, // 24-hour format
12733 initComponent : function(){
12734 Ext.DatePicker.superclass.initComponent.call(this);
12736 this.value = this.value ?
12737 this.value.clearTime(true) : new Date().clearTime();
12742 * Fires when a date is selected
12743 * @param {DatePicker} this DatePicker
12744 * @param {Date} date The selected date
12750 this.on('select', this.handler, this.scope || this);
12753 this.initDisabledDays();
12757 initDisabledDays : function(){
12758 if(!this.disabledDatesRE && this.disabledDates){
12759 var dd = this.disabledDates,
12760 len = dd.length - 1,
12763 Ext.each(dd, function(d, i){
12764 re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i];
12769 this.disabledDatesRE = new RegExp(re + ')');
12774 * Replaces any existing disabled dates with new values and refreshes the DatePicker.
12775 * @param {Array/RegExp} disabledDates An array of date strings (see the {@link #disabledDates} config
12776 * for details on supported values), or a JavaScript regular expression used to disable a pattern of dates.
12778 setDisabledDates : function(dd){
12779 if(Ext.isArray(dd)){
12780 this.disabledDates = dd;
12781 this.disabledDatesRE = null;
12783 this.disabledDatesRE = dd;
12785 this.initDisabledDays();
12786 this.update(this.value, true);
12790 * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.
12791 * @param {Array} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config
12792 * for details on supported values.
12794 setDisabledDays : function(dd){
12795 this.disabledDays = dd;
12796 this.update(this.value, true);
12800 * Replaces any existing {@link #minDate} with the new value and refreshes the DatePicker.
12801 * @param {Date} value The minimum date that can be selected
12803 setMinDate : function(dt){
12805 this.update(this.value, true);
12809 * Replaces any existing {@link #maxDate} with the new value and refreshes the DatePicker.
12810 * @param {Date} value The maximum date that can be selected
12812 setMaxDate : function(dt){
12814 this.update(this.value, true);
12818 * Sets the value of the date field
12819 * @param {Date} value The date to set
12821 setValue : function(value){
12822 this.value = value.clearTime(true);
12823 this.update(this.value);
12827 * Gets the current selected value of the date field
12828 * @return {Date} The selected date
12830 getValue : function(){
12835 focus : function(){
12836 this.update(this.activeDate);
12840 onEnable: function(initial){
12841 Ext.DatePicker.superclass.onEnable.call(this);
12842 this.doDisabled(false);
12843 this.update(initial ? this.value : this.activeDate);
12851 onDisable : function(){
12852 Ext.DatePicker.superclass.onDisable.call(this);
12853 this.doDisabled(true);
12854 if(Ext.isIE && !Ext.isIE8){
12855 /* Really strange problem in IE6/7, when disabled, have to explicitly
12856 * repaint each of the nodes to get them to display correctly, simply
12857 * calling repaint on the main element doesn't appear to be enough.
12859 Ext.each([].concat(this.textNodes, this.el.query('th span')), function(el){
12860 Ext.fly(el).repaint();
12866 doDisabled : function(disabled){
12867 this.keyNav.setDisabled(disabled);
12868 this.prevRepeater.setDisabled(disabled);
12869 this.nextRepeater.setDisabled(disabled);
12870 if(this.showToday){
12871 this.todayKeyListener.setDisabled(disabled);
12872 this.todayBtn.setDisabled(disabled);
12877 onRender : function(container, position){
12879 '<table cellspacing="0">',
12880 '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'"> </a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'"> </a></td></tr>',
12881 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'],
12882 dn = this.dayNames,
12884 for(i = 0; i < 7; i++){
12885 var d = this.startDay+i;
12889 m.push('<th><span>', dn[d].substr(0,1), '</span></th>');
12891 m[m.length] = '</tr></thead><tbody><tr>';
12892 for(i = 0; i < 42; i++) {
12893 if(i % 7 === 0 && i !== 0){
12894 m[m.length] = '</tr><tr>';
12896 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
12898 m.push('</tr></tbody></table></td></tr>',
12899 this.showToday ? '<tr><td colspan="3" class="x-date-bottom" align="center"></td></tr>' : '',
12900 '</table><div class="x-date-mp"></div>');
12902 var el = document.createElement('div');
12903 el.className = 'x-date-picker';
12904 el.innerHTML = m.join('');
12906 container.dom.insertBefore(el, position);
12908 this.el = Ext.get(el);
12909 this.eventEl = Ext.get(el.firstChild);
12911 this.prevRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-left a'), {
12912 handler: this.showPrevMonth,
12914 preventDefault:true,
12918 this.nextRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-right a'), {
12919 handler: this.showNextMonth,
12921 preventDefault:true,
12925 this.monthPicker = this.el.down('div.x-date-mp');
12926 this.monthPicker.enableDisplayMode('block');
12928 this.keyNav = new Ext.KeyNav(this.eventEl, {
12929 'left' : function(e){
12931 this.showPrevMonth();
12933 this.update(this.activeDate.add('d', -1));
12937 'right' : function(e){
12939 this.showNextMonth();
12941 this.update(this.activeDate.add('d', 1));
12945 'up' : function(e){
12947 this.showNextYear();
12949 this.update(this.activeDate.add('d', -7));
12953 'down' : function(e){
12955 this.showPrevYear();
12957 this.update(this.activeDate.add('d', 7));
12961 'pageUp' : function(e){
12962 this.showNextMonth();
12965 'pageDown' : function(e){
12966 this.showPrevMonth();
12969 'enter' : function(e){
12970 e.stopPropagation();
12977 this.el.unselectable();
12979 this.cells = this.el.select('table.x-date-inner tbody td');
12980 this.textNodes = this.el.query('table.x-date-inner tbody span');
12982 this.mbtn = new Ext.Button({
12984 tooltip: this.monthYearText,
12985 renderTo: this.el.child('td.x-date-middle', true)
12987 this.mbtn.el.child('em').addClass('x-btn-arrow');
12989 if(this.showToday){
12990 this.todayKeyListener = this.eventEl.addKeyListener(Ext.EventObject.SPACE, this.selectToday, this);
12991 var today = (new Date()).dateFormat(this.format);
12992 this.todayBtn = new Ext.Button({
12993 renderTo: this.el.child('td.x-date-bottom', true),
12994 text: String.format(this.todayText, today),
12995 tooltip: String.format(this.todayTip, today),
12996 handler: this.selectToday,
13000 this.mon(this.eventEl, 'mousewheel', this.handleMouseWheel, this);
13001 this.mon(this.eventEl, 'click', this.handleDateClick, this, {delegate: 'a.x-date-date'});
13002 this.mon(this.mbtn, 'click', this.showMonthPicker, this);
13003 this.onEnable(true);
13007 createMonthPicker : function(){
13008 if(!this.monthPicker.dom.firstChild){
13009 var buf = ['<table border="0" cellspacing="0">'];
13010 for(var i = 0; i < 6; i++){
13012 '<tr><td class="x-date-mp-month"><a href="#">', Date.getShortMonthName(i), '</a></td>',
13013 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', Date.getShortMonthName(i + 6), '</a></td>',
13015 '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
13016 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
13020 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
13022 '</button><button type="button" class="x-date-mp-cancel">',
13024 '</button></td></tr>',
13027 this.monthPicker.update(buf.join(''));
13029 this.mon(this.monthPicker, 'click', this.onMonthClick, this);
13030 this.mon(this.monthPicker, 'dblclick', this.onMonthDblClick, this);
13032 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
13033 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
13035 this.mpMonths.each(function(m, a, i){
13038 m.dom.xmonth = 5 + Math.round(i * 0.5);
13040 m.dom.xmonth = Math.round((i-1) * 0.5);
13047 showMonthPicker : function(){
13048 if(!this.disabled){
13049 this.createMonthPicker();
13050 var size = this.el.getSize();
13051 this.monthPicker.setSize(size);
13052 this.monthPicker.child('table').setSize(size);
13054 this.mpSelMonth = (this.activeDate || this.value).getMonth();
13055 this.updateMPMonth(this.mpSelMonth);
13056 this.mpSelYear = (this.activeDate || this.value).getFullYear();
13057 this.updateMPYear(this.mpSelYear);
13059 this.monthPicker.slideIn('t', {duration:0.2});
13064 updateMPYear : function(y){
13066 var ys = this.mpYears.elements;
13067 for(var i = 1; i <= 10; i++){
13068 var td = ys[i-1], y2;
13070 y2 = y + Math.round(i * 0.5);
13071 td.firstChild.innerHTML = y2;
13074 y2 = y - (5-Math.round(i * 0.5));
13075 td.firstChild.innerHTML = y2;
13078 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
13083 updateMPMonth : function(sm){
13084 this.mpMonths.each(function(m, a, i){
13085 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
13090 selectMPMonth : function(m){
13095 onMonthClick : function(e, t){
13097 var el = new Ext.Element(t), pn;
13098 if(el.is('button.x-date-mp-cancel')){
13099 this.hideMonthPicker();
13101 else if(el.is('button.x-date-mp-ok')){
13102 var d = new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate());
13103 if(d.getMonth() != this.mpSelMonth){
13104 // 'fix' the JS rolling date conversion if needed
13105 d = new Date(this.mpSelYear, this.mpSelMonth, 1).getLastDateOfMonth();
13108 this.hideMonthPicker();
13110 else if((pn = el.up('td.x-date-mp-month', 2))){
13111 this.mpMonths.removeClass('x-date-mp-sel');
13112 pn.addClass('x-date-mp-sel');
13113 this.mpSelMonth = pn.dom.xmonth;
13115 else if((pn = el.up('td.x-date-mp-year', 2))){
13116 this.mpYears.removeClass('x-date-mp-sel');
13117 pn.addClass('x-date-mp-sel');
13118 this.mpSelYear = pn.dom.xyear;
13120 else if(el.is('a.x-date-mp-prev')){
13121 this.updateMPYear(this.mpyear-10);
13123 else if(el.is('a.x-date-mp-next')){
13124 this.updateMPYear(this.mpyear+10);
13129 onMonthDblClick : function(e, t){
13131 var el = new Ext.Element(t), pn;
13132 if((pn = el.up('td.x-date-mp-month', 2))){
13133 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
13134 this.hideMonthPicker();
13136 else if((pn = el.up('td.x-date-mp-year', 2))){
13137 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
13138 this.hideMonthPicker();
13143 hideMonthPicker : function(disableAnim){
13144 if(this.monthPicker){
13145 if(disableAnim === true){
13146 this.monthPicker.hide();
13148 this.monthPicker.slideOut('t', {duration:0.2});
13154 showPrevMonth : function(e){
13155 this.update(this.activeDate.add('mo', -1));
13159 showNextMonth : function(e){
13160 this.update(this.activeDate.add('mo', 1));
13164 showPrevYear : function(){
13165 this.update(this.activeDate.add('y', -1));
13169 showNextYear : function(){
13170 this.update(this.activeDate.add('y', 1));
13174 handleMouseWheel : function(e){
13176 if(!this.disabled){
13177 var delta = e.getWheelDelta();
13179 this.showPrevMonth();
13180 } else if(delta < 0){
13181 this.showNextMonth();
13187 handleDateClick : function(e, t){
13189 if(!this.disabled && t.dateValue && !Ext.fly(t.parentNode).hasClass('x-date-disabled')){
13190 this.cancelFocus = this.focusOnSelect === false;
13191 this.setValue(new Date(t.dateValue));
13192 delete this.cancelFocus;
13193 this.fireEvent('select', this, this.value);
13198 selectToday : function(){
13199 if(this.todayBtn && !this.todayBtn.disabled){
13200 this.setValue(new Date().clearTime());
13201 this.fireEvent('select', this, this.value);
13206 update : function(date, forceRefresh){
13208 var vd = this.activeDate, vis = this.isVisible();
13209 this.activeDate = date;
13210 if(!forceRefresh && vd && this.el){
13211 var t = date.getTime();
13212 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13213 this.cells.removeClass('x-date-selected');
13214 this.cells.each(function(c){
13215 if(c.dom.firstChild.dateValue == t){
13216 c.addClass('x-date-selected');
13217 if(vis && !this.cancelFocus){
13218 Ext.fly(c.dom.firstChild).focus(50);
13226 var days = date.getDaysInMonth(),
13227 firstOfMonth = date.getFirstDateOfMonth(),
13228 startingPos = firstOfMonth.getDay()-this.startDay;
13230 if(startingPos < 0){
13233 days += startingPos;
13235 var pm = date.add('mo', -1),
13236 prevStart = pm.getDaysInMonth()-startingPos,
13237 cells = this.cells.elements,
13238 textEls = this.textNodes,
13239 // convert everything to numbers so it's fast
13240 d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart, this.initHour)),
13241 today = new Date().clearTime().getTime(),
13242 sel = date.clearTime(true).getTime(),
13243 min = this.minDate ? this.minDate.clearTime(true) : Number.NEGATIVE_INFINITY,
13244 max = this.maxDate ? this.maxDate.clearTime(true) : Number.POSITIVE_INFINITY,
13245 ddMatch = this.disabledDatesRE,
13246 ddText = this.disabledDatesText,
13247 ddays = this.disabledDays ? this.disabledDays.join('') : false,
13248 ddaysText = this.disabledDaysText,
13249 format = this.format;
13251 if(this.showToday){
13252 var td = new Date().clearTime(),
13253 disable = (td < min || td > max ||
13254 (ddMatch && format && ddMatch.test(td.dateFormat(format))) ||
13255 (ddays && ddays.indexOf(td.getDay()) != -1));
13257 if(!this.disabled){
13258 this.todayBtn.setDisabled(disable);
13259 this.todayKeyListener[disable ? 'disable' : 'enable']();
13263 var setCellClass = function(cal, cell){
13265 var t = d.clearTime(true).getTime();
13266 cell.firstChild.dateValue = t;
13268 cell.className += ' x-date-today';
13269 cell.title = cal.todayText;
13272 cell.className += ' x-date-selected';
13274 Ext.fly(cell.firstChild).focus(50);
13279 cell.className = ' x-date-disabled';
13280 cell.title = cal.minText;
13284 cell.className = ' x-date-disabled';
13285 cell.title = cal.maxText;
13289 if(ddays.indexOf(d.getDay()) != -1){
13290 cell.title = ddaysText;
13291 cell.className = ' x-date-disabled';
13294 if(ddMatch && format){
13295 var fvalue = d.dateFormat(format);
13296 if(ddMatch.test(fvalue)){
13297 cell.title = ddText.replace('%0', fvalue);
13298 cell.className = ' x-date-disabled';
13304 for(; i < startingPos; i++) {
13305 textEls[i].innerHTML = (++prevStart);
13306 d.setDate(d.getDate()+1);
13307 cells[i].className = 'x-date-prevday';
13308 setCellClass(this, cells[i]);
13310 for(; i < days; i++){
13311 var intDay = i - startingPos + 1;
13312 textEls[i].innerHTML = (intDay);
13313 d.setDate(d.getDate()+1);
13314 cells[i].className = 'x-date-active';
13315 setCellClass(this, cells[i]);
13318 for(; i < 42; i++) {
13319 textEls[i].innerHTML = (++extraDays);
13320 d.setDate(d.getDate()+1);
13321 cells[i].className = 'x-date-nextday';
13322 setCellClass(this, cells[i]);
13325 this.mbtn.setText(this.monthNames[date.getMonth()] + ' ' + date.getFullYear());
13327 if(!this.internalRender){
13328 var main = this.el.dom.firstChild,
13329 w = main.offsetWidth;
13330 this.el.setWidth(w + this.el.getBorderWidth('lr'));
13331 Ext.fly(main).setWidth(w);
13332 this.internalRender = true;
13333 // opera does not respect the auto grow header center column
13334 // then, after it gets a width opera refuses to recalculate
13335 // without a second pass
13336 if(Ext.isOpera && !this.secondPass){
13337 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + 'px';
13338 this.secondPass = true;
13339 this.update.defer(10, this, [date]);
13346 beforeDestroy : function() {
13358 delete this.textNodes;
13359 delete this.cells.elements;
13364 * @cfg {String} autoEl @hide
13368 Ext.reg('datepicker', Ext.DatePicker);
13370 * @class Ext.LoadMask
13371 * A simple utility class for generically masking elements while loading data. If the {@link #store}
13372 * config option is specified, the masking will be automatically synchronized with the store's loading
13373 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
13374 * element's Updater load indicator and will be destroyed after the initial load.
13375 * <p>Example usage:</p>
13378 var myMask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait..."});
13382 * Create a new LoadMask
13383 * @param {Mixed} el The element or DOM node, or its id
13384 * @param {Object} config The config object
13386 Ext.LoadMask = function(el, config){
13387 this.el = Ext.get(el);
13388 Ext.apply(this, config);
13392 beforeload: this.onBeforeLoad,
13394 exception: this.onLoad
13396 this.removeMask = Ext.value(this.removeMask, false);
13398 var um = this.el.getUpdater();
13399 um.showLoadIndicator = false; // disable the default indicator
13402 beforeupdate: this.onBeforeLoad,
13403 update: this.onLoad,
13404 failure: this.onLoad
13406 this.removeMask = Ext.value(this.removeMask, true);
13410 Ext.LoadMask.prototype = {
13412 * @cfg {Ext.data.Store} store
13413 * Optional Store to which the mask is bound. The mask is displayed when a load request is issued, and
13414 * hidden on either load sucess, or load fail.
13417 * @cfg {Boolean} removeMask
13418 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
13419 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
13422 * @cfg {String} msg
13423 * The text to display in a centered loading message box (defaults to 'Loading...')
13425 msg : 'Loading...',
13427 * @cfg {String} msgCls
13428 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
13430 msgCls : 'x-mask-loading',
13433 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
13439 * Disables the mask to prevent it from being displayed
13441 disable : function(){
13442 this.disabled = true;
13446 * Enables the mask so that it can be displayed
13448 enable : function(){
13449 this.disabled = false;
13453 onLoad : function(){
13454 this.el.unmask(this.removeMask);
13458 onBeforeLoad : function(){
13459 if(!this.disabled){
13460 this.el.mask(this.msg, this.msgCls);
13465 * Show this LoadMask over the configured Element.
13468 this.onBeforeLoad();
13472 * Hide this LoadMask.
13479 destroy : function(){
13481 this.store.un('beforeload', this.onBeforeLoad, this);
13482 this.store.un('load', this.onLoad, this);
13483 this.store.un('exception', this.onLoad, this);
13485 var um = this.el.getUpdater();
13486 um.un('beforeupdate', this.onBeforeLoad, this);
13487 um.un('update', this.onLoad, this);
13488 um.un('failure', this.onLoad, this);
13491 };Ext.ns('Ext.slider');
13494 * @class Ext.slider.Thumb
13496 * Represents a single thumb element on a Slider. This would not usually be created manually and would instead
13497 * be created internally by an {@link Ext.slider.MultiSlider Ext.Slider}.
13499 Ext.slider.Thumb = Ext.extend(Object, {
13502 * True while the thumb is in a drag operation
13509 * @cfg {Ext.slider.MultiSlider} slider The Slider to render to (required)
13511 constructor: function(config) {
13514 * @type Ext.slider.MultiSlider
13515 * The slider this thumb is contained within
13517 Ext.apply(this, config || {}, {
13518 cls: 'x-slider-thumb',
13521 * @cfg {Boolean} constrain True to constrain the thumb so that it cannot overlap its siblings
13526 Ext.slider.Thumb.superclass.constructor.call(this, config);
13528 if (this.slider.vertical) {
13529 Ext.apply(this, Ext.slider.Thumb.Vertical);
13534 * Renders the thumb into a slider
13536 render: function() {
13537 this.el = this.slider.innerEl.insertFirst({cls: this.cls});
13543 * Enables the thumb if it is currently disabled
13545 enable: function() {
13546 this.disabled = false;
13547 this.el.removeClass(this.slider.disabledClass);
13551 * Disables the thumb if it is currently enabled
13553 disable: function() {
13554 this.disabled = true;
13555 this.el.addClass(this.slider.disabledClass);
13559 * Sets up an Ext.dd.DragTracker for this thumb
13561 initEvents: function() {
13564 el.addClassOnOver('x-slider-thumb-over');
13566 this.tracker = new Ext.dd.DragTracker({
13567 onBeforeStart: this.onBeforeDragStart.createDelegate(this),
13568 onStart : this.onDragStart.createDelegate(this),
13569 onDrag : this.onDrag.createDelegate(this),
13570 onEnd : this.onDragEnd.createDelegate(this),
13575 this.tracker.initEl(el);
13580 * This is tied into the internal Ext.dd.DragTracker. If the slider is currently disabled,
13581 * this returns false to disable the DragTracker too.
13582 * @return {Boolean} False if the slider is currently disabled
13584 onBeforeDragStart : function(e) {
13585 if (this.disabled) {
13588 this.slider.promoteThumb(this);
13595 * This is tied into the internal Ext.dd.DragTracker's onStart template method. Adds the drag CSS class
13596 * to the thumb and fires the 'dragstart' event
13598 onDragStart: function(e){
13599 this.el.addClass('x-slider-thumb-drag');
13600 this.dragging = true;
13601 this.dragStartValue = this.value;
13603 this.slider.fireEvent('dragstart', this.slider, e, this);
13608 * This is tied into the internal Ext.dd.DragTracker's onDrag template method. This is called every time
13609 * the DragTracker detects a drag movement. It updates the Slider's value using the position of the drag
13611 onDrag: function(e) {
13612 var slider = this.slider,
13613 index = this.index,
13614 newValue = this.getNewValue();
13616 if (this.constrain) {
13617 var above = slider.thumbs[index + 1],
13618 below = slider.thumbs[index - 1];
13620 if (below != undefined && newValue <= below.value) newValue = below.value;
13621 if (above != undefined && newValue >= above.value) newValue = above.value;
13624 slider.setValue(index, newValue, false);
13625 slider.fireEvent('drag', slider, e, this);
13628 getNewValue: function() {
13629 var slider = this.slider,
13630 pos = slider.innerEl.translatePoints(this.tracker.getXY());
13632 return Ext.util.Format.round(slider.reverseValue(pos.left), slider.decimalPrecision);
13637 * This is tied to the internal Ext.dd.DragTracker's onEnd template method. Removes the drag CSS class and
13638 * fires the 'changecomplete' event with the new value
13640 onDragEnd: function(e) {
13641 var slider = this.slider,
13642 value = this.value;
13644 this.el.removeClass('x-slider-thumb-drag');
13646 this.dragging = false;
13647 slider.fireEvent('dragend', slider, e);
13649 if (this.dragStartValue != value) {
13650 slider.fireEvent('changecomplete', slider, value, this);
13656 * Destroys the thumb
13658 destroy: function(){
13659 Ext.destroyMembers(this, 'tracker', 'el');
13664 * @class Ext.slider.MultiSlider
13665 * @extends Ext.BoxComponent
13666 * Slider which supports vertical or horizontal orientation, keyboard adjustments, configurable snapping, axis clicking and animation. Can be added as an item to any container. Example usage:
13669 renderTo: Ext.getBody(),
13677 * Sliders can be created with more than one thumb handle by passing an array of values instead of a single one:
13680 renderTo: Ext.getBody(),
13682 values: [25, 50, 75],
13686 //this defaults to true, setting to false allows the thumbs to pass each other
13687 {@link #constrainThumbs}: false
13691 Ext.slider.MultiSlider = Ext.extend(Ext.BoxComponent, {
13693 * @cfg {Number} value The value to initialize the slider with. Defaults to minValue.
13696 * @cfg {Boolean} vertical Orient the Slider vertically rather than horizontally, defaults to false.
13700 * @cfg {Number} minValue The minimum value for the Slider. Defaults to 0.
13704 * @cfg {Number} maxValue The maximum value for the Slider. Defaults to 100.
13708 * @cfg {Number/Boolean} decimalPrecision.
13709 * <p>The number of decimal places to which to round the Slider's value. Defaults to 0.</p>
13710 * <p>To disable rounding, configure as <tt><b>false</b></tt>.</p>
13712 decimalPrecision: 0,
13714 * @cfg {Number} keyIncrement How many units to change the Slider when adjusting with keyboard navigation. Defaults to 1. If the increment config is larger, it will be used instead.
13718 * @cfg {Number} increment How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'.
13724 * @property clickRange
13726 * Determines whether or not a click to the slider component is considered to be a user request to change the value. Specified as an array of [top, bottom],
13727 * the click event's 'top' property is compared to these numbers and the click only considered a change request if it falls within them. e.g. if the 'top'
13728 * value of the click event is 4 or 16, the click is not considered a change request as it falls outside of the [5, 15] range
13730 clickRange: [5,15],
13733 * @cfg {Boolean} clickToChange Determines whether or not clicking on the Slider axis will change the slider. Defaults to true
13735 clickToChange : true,
13737 * @cfg {Boolean} animate Turn on or off animation. Defaults to true
13741 * @cfg {Boolean} constrainThumbs True to disallow thumbs from overlapping one another. Defaults to true
13743 constrainThumbs: true,
13747 * @property topThumbZIndex
13749 * The number used internally to set the z index of the top thumb (see promoteThumb for details)
13751 topThumbZIndex: 10000,
13753 // private override
13754 initComponent : function(){
13755 if(!Ext.isDefined(this.value)){
13756 this.value = this.minValue;
13762 * Array containing references to each thumb
13766 Ext.slider.MultiSlider.superclass.initComponent.call(this);
13768 this.keyIncrement = Math.max(this.increment, this.keyIncrement);
13771 * @event beforechange
13772 * Fires before the slider value is changed. By returning false from an event handler,
13773 * you can cancel the event and prevent the slider from changing.
13774 * @param {Ext.slider.MultiSlider} slider The slider
13775 * @param {Number} newValue The new value which the slider is being changed to.
13776 * @param {Number} oldValue The old value which the slider was previously.
13782 * Fires when the slider value is changed.
13783 * @param {Ext.slider.MultiSlider} slider The slider
13784 * @param {Number} newValue The new value which the slider has been changed to.
13785 * @param {Ext.slider.Thumb} thumb The thumb that was changed
13790 * @event changecomplete
13791 * Fires when the slider value is changed by the user and any drag operations have completed.
13792 * @param {Ext.slider.MultiSlider} slider The slider
13793 * @param {Number} newValue The new value which the slider has been changed to.
13794 * @param {Ext.slider.Thumb} thumb The thumb that was changed
13800 * Fires after a drag operation has started.
13801 * @param {Ext.slider.MultiSlider} slider The slider
13802 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
13808 * Fires continuously during the drag operation while the mouse is moving.
13809 * @param {Ext.slider.MultiSlider} slider The slider
13810 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
13816 * Fires after the drag operation has completed.
13817 * @param {Ext.slider.MultiSlider} slider The slider
13818 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
13826 * Array of values to initalize the thumbs with
13828 if (this.values == undefined || Ext.isEmpty(this.values)) this.values = [0];
13830 var values = this.values;
13832 for (var i=0; i < values.length; i++) {
13833 this.addThumb(values[i]);
13837 Ext.apply(this, Ext.slider.Vertical);
13842 * Creates a new thumb and adds it to the slider
13843 * @param {Number} value The initial value to set on the thumb. Defaults to 0
13845 addThumb: function(value) {
13846 var thumb = new Ext.slider.Thumb({
13849 index : this.thumbs.length,
13850 constrain: this.constrainThumbs
13852 this.thumbs.push(thumb);
13854 //render the thumb now if needed
13855 if (this.rendered) thumb.render();
13860 * Moves the given thumb above all other by increasing its z-index. This is called when as drag
13861 * any thumb, so that the thumb that was just dragged is always at the highest z-index. This is
13862 * required when the thumbs are stacked on top of each other at one of the ends of the slider's
13863 * range, which can result in the user not being able to move any of them.
13864 * @param {Ext.slider.Thumb} topThumb The thumb to move to the top
13866 promoteThumb: function(topThumb) {
13867 var thumbs = this.thumbs,
13870 for (var i = 0, j = thumbs.length; i < j; i++) {
13873 if (thumb == topThumb) {
13874 zIndex = this.topThumbZIndex;
13879 thumb.el.setStyle('zIndex', zIndex);
13883 // private override
13884 onRender : function() {
13886 cls: 'x-slider ' + (this.vertical ? 'x-slider-vert' : 'x-slider-horz'),
13888 cls: 'x-slider-end',
13890 cls:'x-slider-inner',
13891 cn : [{tag:'a', cls:'x-slider-focus', href:"#", tabIndex: '-1', hidefocus:'on'}]
13896 Ext.slider.MultiSlider.superclass.onRender.apply(this, arguments);
13898 this.endEl = this.el.first();
13899 this.innerEl = this.endEl.first();
13900 this.focusEl = this.innerEl.child('.x-slider-focus');
13902 //render each thumb
13903 for (var i=0; i < this.thumbs.length; i++) {
13904 this.thumbs[i].render();
13907 //calculate the size of half a thumb
13908 var thumb = this.innerEl.child('.x-slider-thumb');
13909 this.halfThumb = (this.vertical ? thumb.getHeight() : thumb.getWidth()) / 2;
13916 * Adds keyboard and mouse listeners on this.el. Ignores click events on the internal focus element.
13917 * Creates a new DragTracker which is used to control what happens when the user drags the thumb around.
13919 initEvents : function(){
13920 this.mon(this.el, {
13922 mousedown: this.onMouseDown,
13923 keydown : this.onKeyDown
13926 this.focusEl.swallowEvent("click", true);
13931 * Mousedown handler for the slider. If the clickToChange is enabled and the click was not on the draggable 'thumb',
13932 * this calculates the new value of the slider and tells the implementation (Horizontal or Vertical) to move the thumb
13933 * @param {Ext.EventObject} e The click event
13935 onMouseDown : function(e){
13940 //see if the click was on any of the thumbs
13941 var thumbClicked = false;
13942 for (var i=0; i < this.thumbs.length; i++) {
13943 thumbClicked = thumbClicked || e.target == this.thumbs[i].el.dom;
13946 if (this.clickToChange && !thumbClicked) {
13947 var local = this.innerEl.translatePoints(e.getXY());
13948 this.onClickChange(local);
13955 * Moves the thumb to the indicated position. Note that a Vertical implementation is provided in Ext.slider.Vertical.
13956 * Only changes the value if the click was within this.clickRange.
13957 * @param {Object} local Object containing top and left values for the click event.
13959 onClickChange : function(local) {
13960 if (local.top > this.clickRange[0] && local.top < this.clickRange[1]) {
13961 //find the nearest thumb to the click event
13962 var thumb = this.getNearest(local, 'left'),
13963 index = thumb.index;
13965 this.setValue(index, Ext.util.Format.round(this.reverseValue(local.left), this.decimalPrecision), undefined, true);
13971 * Returns the nearest thumb to a click event, along with its distance
13972 * @param {Object} local Object containing top and left values from a click event
13973 * @param {String} prop The property of local to compare on. Use 'left' for horizontal sliders, 'top' for vertical ones
13974 * @return {Object} The closest thumb object and its distance from the click event
13976 getNearest: function(local, prop) {
13977 var localValue = prop == 'top' ? this.innerEl.getHeight() - local[prop] : local[prop],
13978 clickValue = this.reverseValue(localValue),
13979 nearestDistance = (this.maxValue - this.minValue) + 5, //add a small fudge for the end of the slider
13983 for (var i=0; i < this.thumbs.length; i++) {
13984 var thumb = this.thumbs[i],
13985 value = thumb.value,
13986 dist = Math.abs(value - clickValue);
13988 if (Math.abs(dist <= nearestDistance)) {
13991 nearestDistance = dist;
13999 * Handler for any keypresses captured by the slider. If the key is UP or RIGHT, the thumb is moved along to the right
14000 * by this.keyIncrement. If DOWN or LEFT it is moved left. Pressing CTRL moves the slider to the end in either direction
14001 * @param {Ext.EventObject} e The Event object
14003 onKeyDown : function(e){
14005 * The behaviour for keyboard handling with multiple thumbs is currently undefined.
14006 * There's no real sane default for it, so leave it like this until we come up
14007 * with a better way of doing it.
14009 if(this.disabled || this.thumbs.length !== 1){
14010 e.preventDefault();
14013 var k = e.getKey(),
14019 val = e.ctrlKey ? this.maxValue : this.getValue(0) + this.keyIncrement;
14020 this.setValue(0, val, undefined, true);
14025 val = e.ctrlKey ? this.minValue : this.getValue(0) - this.keyIncrement;
14026 this.setValue(0, val, undefined, true);
14029 e.preventDefault();
14035 * If using snapping, this takes a desired new value and returns the closest snapped
14037 * @param {Number} value The unsnapped value
14038 * @return {Number} The value of the nearest snap target
14040 doSnap : function(value){
14041 if (!(this.increment && value)) {
14044 var newValue = value,
14045 inc = this.increment,
14049 if (m * 2 >= inc) {
14051 } else if (m * 2 < -inc) {
14055 return newValue.constrain(this.minValue, this.maxValue);
14059 afterRender : function(){
14060 Ext.slider.MultiSlider.superclass.afterRender.apply(this, arguments);
14062 for (var i=0; i < this.thumbs.length; i++) {
14063 var thumb = this.thumbs[i];
14065 if (thumb.value !== undefined) {
14066 var v = this.normalizeValue(thumb.value);
14068 if (v !== thumb.value) {
14069 // delete this.value;
14070 this.setValue(i, v, false);
14072 this.moveThumb(i, this.translateValue(v), false);
14080 * Returns the ratio of pixels to mapped values. e.g. if the slider is 200px wide and maxValue - minValue is 100,
14082 * @return {Number} The ratio of pixels to mapped values
14084 getRatio : function(){
14085 var w = this.innerEl.getWidth(),
14086 v = this.maxValue - this.minValue;
14087 return v == 0 ? w : (w/v);
14092 * Returns a snapped, constrained value when given a desired value
14093 * @param {Number} value Raw number value
14094 * @return {Number} The raw value rounded to the correct d.p. and constrained within the set max and min values
14096 normalizeValue : function(v){
14097 v = this.doSnap(v);
14098 v = Ext.util.Format.round(v, this.decimalPrecision);
14099 v = v.constrain(this.minValue, this.maxValue);
14104 * Sets the minimum value for the slider instance. If the current value is less than the
14105 * minimum value, the current value will be changed.
14106 * @param {Number} val The new minimum value
14108 setMinValue : function(val){
14109 this.minValue = val;
14111 thumbs = this.thumbs,
14112 len = thumbs.length,
14115 for(; i < len; ++i){
14117 t.value = t.value < val ? val : t.value;
14123 * Sets the maximum value for the slider instance. If the current value is more than the
14124 * maximum value, the current value will be changed.
14125 * @param {Number} val The new maximum value
14127 setMaxValue : function(val){
14128 this.maxValue = val;
14130 thumbs = this.thumbs,
14131 len = thumbs.length,
14134 for(; i < len; ++i){
14136 t.value = t.value > val ? val : t.value;
14142 * Programmatically sets the value of the Slider. Ensures that the value is constrained within
14143 * the minValue and maxValue.
14144 * @param {Number} index Index of the thumb to move
14145 * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
14146 * @param {Boolean} animate Turn on or off animation, defaults to true
14148 setValue : function(index, v, animate, changeComplete) {
14149 var thumb = this.thumbs[index],
14152 v = this.normalizeValue(v);
14154 if (v !== thumb.value && this.fireEvent('beforechange', this, v, thumb.value, thumb) !== false) {
14157 this.moveThumb(index, this.translateValue(v), animate !== false);
14158 this.fireEvent('change', this, v, thumb);
14159 if(changeComplete){
14160 this.fireEvent('changecomplete', this, v, thumb);
14169 translateValue : function(v) {
14170 var ratio = this.getRatio();
14171 return (v * ratio) - (this.minValue * ratio) - this.halfThumb;
14176 * Given a pixel location along the slider, returns the mapped slider value for that pixel.
14177 * E.g. if we have a slider 200px wide with minValue = 100 and maxValue = 500, reverseValue(50)
14179 * @param {Number} pos The position along the slider to return a mapped value for
14180 * @return {Number} The mapped value for the given position
14182 reverseValue : function(pos){
14183 var ratio = this.getRatio();
14184 return (pos + (this.minValue * ratio)) / ratio;
14189 * @param {Number} index Index of the thumb to move
14191 moveThumb: function(index, v, animate){
14192 var thumb = this.thumbs[index].el;
14194 if(!animate || this.animate === false){
14197 thumb.shift({left: v, stopFx: true, duration:.35});
14202 focus : function(){
14203 this.focusEl.focus(10);
14207 onResize : function(w, h){
14208 var thumbs = this.thumbs,
14209 len = thumbs.length,
14213 * If we happen to be animating during a resize, the position of the thumb will likely be off
14214 * when the animation stops. As such, just stop any animations before syncing the thumbs.
14216 for(; i < len; ++i){
14217 thumbs[i].el.stopFx();
14219 // check to see if we're using an auto width
14220 if(Ext.isNumber(w)){
14221 this.innerEl.setWidth(w - (this.el.getPadding('l') + this.endEl.getPadding('r')));
14224 Ext.slider.MultiSlider.superclass.onResize.apply(this, arguments);
14228 onDisable: function(){
14229 Ext.slider.MultiSlider.superclass.onDisable.call(this);
14231 for (var i=0; i < this.thumbs.length; i++) {
14232 var thumb = this.thumbs[i],
14238 //IE breaks when using overflow visible and opacity other than 1.
14239 //Create a place holder for the thumb and display it.
14240 var xy = el.getXY();
14243 this.innerEl.addClass(this.disabledClass).dom.disabled = true;
14245 if (!this.thumbHolder) {
14246 this.thumbHolder = this.endEl.createChild({cls: 'x-slider-thumb ' + this.disabledClass});
14249 this.thumbHolder.show().setXY(xy);
14255 onEnable: function(){
14256 Ext.slider.MultiSlider.superclass.onEnable.call(this);
14258 for (var i=0; i < this.thumbs.length; i++) {
14259 var thumb = this.thumbs[i],
14265 this.innerEl.removeClass(this.disabledClass).dom.disabled = false;
14267 if (this.thumbHolder) this.thumbHolder.hide();
14276 * Synchronizes the thumb position to the proper proportion of the total component width based
14277 * on the current slider {@link #value}. This will be called automatically when the Slider
14278 * is resized by a layout, but if it is rendered auto width, this method can be called from
14279 * another resize handler to sync the Slider if necessary.
14281 syncThumb : function() {
14282 if (this.rendered) {
14283 for (var i=0; i < this.thumbs.length; i++) {
14284 this.moveThumb(i, this.translateValue(this.thumbs[i].value));
14290 * Returns the current value of the slider
14291 * @param {Number} index The index of the thumb to return a value for
14292 * @return {Number} The current value of the slider
14294 getValue : function(index) {
14295 return this.thumbs[index].value;
14299 * Returns an array of values - one for the location of each thumb
14300 * @return {Array} The set of thumb values
14302 getValues: function() {
14305 for (var i=0; i < this.thumbs.length; i++) {
14306 values.push(this.thumbs[i].value);
14313 beforeDestroy : function(){
14314 var thumbs = this.thumbs;
14315 for(var i = 0, len = thumbs.length; i < len; ++i){
14316 thumbs[i].destroy();
14319 Ext.destroyMembers(this, 'endEl', 'innerEl', 'focusEl', 'thumbHolder');
14320 Ext.slider.MultiSlider.superclass.beforeDestroy.call(this);
14324 Ext.reg('multislider', Ext.slider.MultiSlider);
14327 * @class Ext.slider.SingleSlider
14328 * @extends Ext.slider.MultiSlider
14329 * Slider which supports vertical or horizontal orientation, keyboard adjustments,
14330 * configurable snapping, axis clicking and animation. Can be added as an item to
14331 * any container. Example usage:
14333 new Ext.slider.SingleSlider({
14334 renderTo: Ext.getBody(),
14342 * The class Ext.slider.SingleSlider is aliased to Ext.Slider for backwards compatibility.
14344 Ext.slider.SingleSlider = Ext.extend(Ext.slider.MultiSlider, {
14345 constructor: function(config) {
14346 config = config || {};
14348 Ext.applyIf(config, {
14349 values: [config.value || 0]
14352 Ext.slider.SingleSlider.superclass.constructor.call(this, config);
14356 * Returns the current value of the slider
14357 * @return {Number} The current value of the slider
14359 getValue: function() {
14360 //just returns the value of the first thumb, which should be the only one in a single slider
14361 return Ext.slider.SingleSlider.superclass.getValue.call(this, 0);
14365 * Programmatically sets the value of the Slider. Ensures that the value is constrained within
14366 * the minValue and maxValue.
14367 * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
14368 * @param {Boolean} animate Turn on or off animation, defaults to true
14370 setValue: function(value, animate) {
14371 var args = Ext.toArray(arguments),
14374 //this is to maintain backwards compatiblity for sliders with only one thunb. Usually you must pass the thumb
14375 //index to setValue, but if we only have one thumb we inject the index here first if given the multi-slider
14376 //signature without the required index. The index will always be 0 for a single slider
14377 if (len == 1 || (len <= 3 && typeof arguments[1] != 'number')) {
14381 return Ext.slider.SingleSlider.superclass.setValue.apply(this, args);
14385 * Synchronizes the thumb position to the proper proportion of the total component width based
14386 * on the current slider {@link #value}. This will be called automatically when the Slider
14387 * is resized by a layout, but if it is rendered auto width, this method can be called from
14388 * another resize handler to sync the Slider if necessary.
14390 syncThumb : function() {
14391 return Ext.slider.SingleSlider.superclass.syncThumb.apply(this, [0].concat(arguments));
14395 getNearest : function(){
14396 // Since there's only 1 thumb, it's always the nearest
14397 return this.thumbs[0];
14401 //backwards compatibility
14402 Ext.Slider = Ext.slider.SingleSlider;
14404 Ext.reg('slider', Ext.slider.SingleSlider);
14406 // private class to support vertical sliders
14407 Ext.slider.Vertical = {
14408 onResize : function(w, h){
14409 this.innerEl.setHeight(h - (this.el.getPadding('t') + this.endEl.getPadding('b')));
14413 getRatio : function(){
14414 var h = this.innerEl.getHeight(),
14415 v = this.maxValue - this.minValue;
14419 moveThumb: function(index, v, animate) {
14420 var thumb = this.thumbs[index],
14423 if (!animate || this.animate === false) {
14426 el.shift({bottom: v, stopFx: true, duration:.35});
14430 onClickChange : function(local) {
14431 if (local.left > this.clickRange[0] && local.left < this.clickRange[1]) {
14432 var thumb = this.getNearest(local, 'top'),
14433 index = thumb.index,
14434 value = this.minValue + this.reverseValue(this.innerEl.getHeight() - local.top);
14436 this.setValue(index, Ext.util.Format.round(value, this.decimalPrecision), undefined, true);
14441 //private class to support vertical dragging of thumbs within a slider
14442 Ext.slider.Thumb.Vertical = {
14443 getNewValue: function() {
14444 var slider = this.slider,
14445 innerEl = slider.innerEl,
14446 pos = innerEl.translatePoints(this.tracker.getXY()),
14447 bottom = innerEl.getHeight() - pos.top;
14449 return slider.minValue + Ext.util.Format.round(bottom / slider.getRatio(), slider.decimalPrecision);
14453 * @class Ext.ProgressBar
14454 * @extends Ext.BoxComponent
14455 * <p>An updateable progress bar component. The progress bar supports two different modes: manual and automatic.</p>
14456 * <p>In manual mode, you are responsible for showing, updating (via {@link #updateProgress}) and clearing the
14457 * progress bar as needed from your own code. This method is most appropriate when you want to show progress
14458 * throughout an operation that has predictable points of interest at which you can update the control.</p>
14459 * <p>In automatic mode, you simply call {@link #wait} and let the progress bar run indefinitely, only clearing it
14460 * once the operation is complete. You can optionally have the progress bar wait for a specific amount of time
14461 * and then clear itself. Automatic mode is most appropriate for timed operations or asynchronous operations in
14462 * which you have no need for indicating intermediate progress.</p>
14463 * @cfg {Float} value A floating point value between 0 and 1 (e.g., .5, defaults to 0)
14464 * @cfg {String} text The progress bar text (defaults to '')
14465 * @cfg {Mixed} textEl The element to render the progress text to (defaults to the progress
14466 * bar's internal text element)
14467 * @cfg {String} id The progress bar element's id (defaults to an auto-generated id)
14470 Ext.ProgressBar = Ext.extend(Ext.BoxComponent, {
14472 * @cfg {String} baseCls
14473 * The base CSS class to apply to the progress bar's wrapper element (defaults to 'x-progress')
14475 baseCls : 'x-progress',
14478 * @cfg {Boolean} animate
14479 * True to animate the progress bar during transitions (defaults to false)
14487 initComponent : function(){
14488 Ext.ProgressBar.superclass.initComponent.call(this);
14492 * Fires after each update interval
14493 * @param {Ext.ProgressBar} this
14494 * @param {Number} The current progress value
14495 * @param {String} The current progress text
14502 onRender : function(ct, position){
14503 var tpl = new Ext.Template(
14504 '<div class="{cls}-wrap">',
14505 '<div class="{cls}-inner">',
14506 '<div class="{cls}-bar">',
14507 '<div class="{cls}-text">',
14508 '<div> </div>',
14511 '<div class="{cls}-text {cls}-text-back">',
14512 '<div> </div>',
14518 this.el = position ? tpl.insertBefore(position, {cls: this.baseCls}, true)
14519 : tpl.append(ct, {cls: this.baseCls}, true);
14522 this.el.dom.id = this.id;
14524 var inner = this.el.dom.firstChild;
14525 this.progressBar = Ext.get(inner.firstChild);
14528 //use an external text el
14529 this.textEl = Ext.get(this.textEl);
14530 delete this.textTopEl;
14532 //setup our internal layered text els
14533 this.textTopEl = Ext.get(this.progressBar.dom.firstChild);
14534 var textBackEl = Ext.get(inner.childNodes[1]);
14535 this.textTopEl.setStyle("z-index", 99).addClass('x-hidden');
14536 this.textEl = new Ext.CompositeElement([this.textTopEl.dom.firstChild, textBackEl.dom.firstChild]);
14537 this.textEl.setWidth(inner.offsetWidth);
14539 this.progressBar.setHeight(inner.offsetHeight);
14543 afterRender : function(){
14544 Ext.ProgressBar.superclass.afterRender.call(this);
14546 this.updateProgress(this.value, this.text);
14548 this.updateText(this.text);
14553 * Updates the progress bar value, and optionally its text. If the text argument is not specified,
14554 * any existing text value will be unchanged. To blank out existing text, pass ''. Note that even
14555 * if the progress bar value exceeds 1, it will never automatically reset -- you are responsible for
14556 * determining when the progress is complete and calling {@link #reset} to clear and/or hide the control.
14557 * @param {Float} value (optional) A floating point value between 0 and 1 (e.g., .5, defaults to 0)
14558 * @param {String} text (optional) The string to display in the progress text element (defaults to '')
14559 * @param {Boolean} animate (optional) Whether to animate the transition of the progress bar. If this value is
14560 * not specified, the default for the class is used (default to false)
14561 * @return {Ext.ProgressBar} this
14563 updateProgress : function(value, text, animate){
14564 this.value = value || 0;
14566 this.updateText(text);
14568 if(this.rendered && !this.isDestroyed){
14569 var w = Math.floor(value*this.el.dom.firstChild.offsetWidth);
14570 this.progressBar.setWidth(w, animate === true || (animate !== false && this.animate));
14571 if(this.textTopEl){
14572 //textTopEl should be the same width as the bar so overflow will clip as the bar moves
14573 this.textTopEl.removeClass('x-hidden').setWidth(w);
14576 this.fireEvent('update', this, value, text);
14581 * Initiates an auto-updating progress bar. A duration can be specified, in which case the progress
14582 * bar will automatically reset after a fixed amount of time and optionally call a callback function
14583 * if specified. If no duration is passed in, then the progress bar will run indefinitely and must
14584 * be manually cleared by calling {@link #reset}. The wait method accepts a config object with
14585 * the following properties:
14587 Property Type Description
14588 ---------- ------------ ----------------------------------------------------------------------
14589 duration Number The length of time in milliseconds that the progress bar should
14590 run before resetting itself (defaults to undefined, in which case it
14591 will run indefinitely until reset is called)
14592 interval Number The length of time in milliseconds between each progress update
14593 (defaults to 1000 ms)
14594 animate Boolean Whether to animate the transition of the progress bar. If this value is
14595 not specified, the default for the class is used.
14596 increment Number The number of progress update segments to display within the progress
14597 bar (defaults to 10). If the bar reaches the end and is still
14598 updating, it will automatically wrap back to the beginning.
14599 text String Optional text to display in the progress bar element (defaults to '').
14600 fn Function A callback function to execute after the progress bar finishes auto-
14601 updating. The function will be called with no arguments. This function
14602 will be ignored if duration is not specified since in that case the
14603 progress bar can only be stopped programmatically, so any required function
14604 should be called by the same code after it resets the progress bar.
14605 scope Object The scope that is passed to the callback function (only applies when
14606 duration and fn are both passed).
14611 var p = new Ext.ProgressBar({
14615 //Wait for 5 seconds, then update the status el (progress bar will auto-reset)
14617 interval: 100, //bar will move fast!
14620 text: 'Updating...',
14623 Ext.fly('status').update('Done!');
14627 //Or update indefinitely until some async action completes, then reset manually
14629 myAction.on('complete', function(){
14631 Ext.fly('status').update('Done!');
14634 * @param {Object} config (optional) Configuration options
14635 * @return {Ext.ProgressBar} this
14637 wait : function(o){
14638 if(!this.waitTimer){
14641 this.updateText(o.text);
14642 this.waitTimer = Ext.TaskMgr.start({
14644 var inc = o.increment || 10;
14646 this.updateProgress(((((i+inc)%inc)+1)*(100/inc))*0.01, null, o.animate);
14648 interval: o.interval || 1000,
14649 duration: o.duration,
14650 onStop: function(){
14652 o.fn.apply(o.scope || this);
14663 * Returns true if the progress bar is currently in a {@link #wait} operation
14664 * @return {Boolean} True if waiting, else false
14666 isWaiting : function(){
14667 return this.waitTimer !== null;
14671 * Updates the progress bar text. If specified, textEl will be updated, otherwise the progress
14672 * bar itself will display the updated text.
14673 * @param {String} text (optional) The string to display in the progress text element (defaults to '')
14674 * @return {Ext.ProgressBar} this
14676 updateText : function(text){
14677 this.text = text || ' ';
14679 this.textEl.update(this.text);
14685 * Synchronizes the inner bar width to the proper proportion of the total componet width based
14686 * on the current progress {@link #value}. This will be called automatically when the ProgressBar
14687 * is resized by a layout, but if it is rendered auto width, this method can be called from
14688 * another resize handler to sync the ProgressBar if necessary.
14690 syncProgressBar : function(){
14692 this.updateProgress(this.value, this.text);
14698 * Sets the size of the progress bar.
14699 * @param {Number} width The new width in pixels
14700 * @param {Number} height The new height in pixels
14701 * @return {Ext.ProgressBar} this
14703 setSize : function(w, h){
14704 Ext.ProgressBar.superclass.setSize.call(this, w, h);
14705 if(this.textTopEl){
14706 var inner = this.el.dom.firstChild;
14707 this.textEl.setSize(inner.offsetWidth, inner.offsetHeight);
14709 this.syncProgressBar();
14714 * Resets the progress bar value to 0 and text to empty string. If hide = true, the progress
14715 * bar will also be hidden (using the {@link #hideMode} property internally).
14716 * @param {Boolean} hide (optional) True to hide the progress bar (defaults to false)
14717 * @return {Ext.ProgressBar} this
14719 reset : function(hide){
14720 this.updateProgress(0);
14721 if(this.textTopEl){
14722 this.textTopEl.addClass('x-hidden');
14732 clearTimer : function(){
14733 if(this.waitTimer){
14734 this.waitTimer.onStop = null; //prevent recursion
14735 Ext.TaskMgr.stop(this.waitTimer);
14736 this.waitTimer = null;
14740 onDestroy: function(){
14743 if(this.textEl.isComposite){
14744 this.textEl.clear();
14746 Ext.destroyMembers(this, 'textEl', 'progressBar', 'textTopEl');
14748 Ext.ProgressBar.superclass.onDestroy.call(this);
14751 Ext.reg('progress', Ext.ProgressBar);