3 * Copyright(c) 2006-2010 Sencha Inc.
5 * http://www.sencha.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){
4557 Ext.applyIf(c.isAction ? c.initialConfig : c, d);
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(this.container) {
5198 this.container.un(this.container.resizeEvent, this.onResize, this);
5200 if(!Ext.isEmpty(this.targetCls)){
5201 var target = this.container.getLayoutTarget();
5203 target.removeClass(this.targetCls);
5208 * @class Ext.layout.AutoLayout
5209 * <p>The AutoLayout is the default layout manager delegated by {@link Ext.Container} to
5210 * render any child Components when no <tt>{@link Ext.Container#layout layout}</tt> is configured into
5211 * a {@link Ext.Container Container}.</tt>. AutoLayout provides only a passthrough of any layout calls
5212 * to any child containers.</p>
5214 Ext.layout.AutoLayout = Ext.extend(Ext.layout.ContainerLayout, {
5217 monitorResize: true,
5219 onLayout : function(ct, target){
5220 Ext.layout.AutoLayout.superclass.onLayout.call(this, ct, target);
5221 var cs = this.getRenderedItems(ct), len = cs.length, i, c;
5222 for(i = 0; i < len; i++){
5225 // Shallow layout children
5232 Ext.Container.LAYOUTS['auto'] = Ext.layout.AutoLayout;
5234 * @class Ext.layout.FitLayout
5235 * @extends Ext.layout.ContainerLayout
5236 * <p>This is a base class for layouts that contain <b>a single item</b> that automatically expands to fill the layout's
5237 * container. This class is intended to be extended or created via the <tt>layout:'fit'</tt> {@link Ext.Container#layout}
5238 * config, and should generally not need to be created directly via the new keyword.</p>
5239 * <p>FitLayout does not have any direct config options (other than inherited ones). To fit a panel to a container
5240 * using FitLayout, simply set layout:'fit' on the container and add a single panel to it. If the container has
5241 * multiple panels, only the first one will be displayed. Example usage:</p>
5243 var p = new Ext.Panel({
5244 title: 'Fit Layout',
5247 title: 'Inner Panel',
5248 html: '<p>This is the inner panel content</p>',
5254 Ext.layout.FitLayout = Ext.extend(Ext.layout.ContainerLayout, {
5260 getLayoutTargetSize : function() {
5261 var target = this.container.getLayoutTarget();
5265 // Style Sized (scrollbars not included)
5266 return target.getStyleSize();
5270 onLayout : function(ct, target){
5271 Ext.layout.FitLayout.superclass.onLayout.call(this, ct, target);
5273 this.setItemSize(this.activeItem || ct.items.itemAt(0), this.getLayoutTargetSize());
5278 setItemSize : function(item, size){
5279 if(item && size.height > 0){ // display none?
5284 Ext.Container.LAYOUTS['fit'] = Ext.layout.FitLayout;/**
5285 * @class Ext.layout.CardLayout
5286 * @extends Ext.layout.FitLayout
5287 * <p>This layout manages multiple child Components, each fitted to the Container, where only a single child Component can be
5288 * visible at any given time. This layout style is most commonly used for wizards, tab implementations, etc.
5289 * This class is intended to be extended or created via the layout:'card' {@link Ext.Container#layout} config,
5290 * and should generally not need to be created directly via the new keyword.</p>
5291 * <p>The CardLayout's focal method is {@link #setActiveItem}. Since only one panel is displayed at a time,
5292 * the only way to move from one Component to the next is by calling setActiveItem, passing the id or index of
5293 * the next panel to display. The layout itself does not provide a user interface for handling this navigation,
5294 * so that functionality must be provided by the developer.</p>
5295 * <p>In the following example, a simplistic wizard setup is demonstrated. A button bar is added
5296 * to the footer of the containing panel to provide navigation buttons. The buttons will be handled by a
5297 * common navigation routine -- for this example, the implementation of that routine has been ommitted since
5298 * it can be any type of custom logic. Note that other uses of a CardLayout (like a tab control) would require a
5299 * completely different implementation. For serious implementations, a better approach would be to extend
5300 * CardLayout to provide the custom functionality needed. Example usage:</p>
5302 var navHandler = function(direction){
5303 // This routine could contain business logic required to manage the navigation steps.
5304 // It would call setActiveItem as needed, manage navigation button state, handle any
5305 // branching logic that might be required, handle alternate actions like cancellation
5306 // or finalization, etc. A complete wizard implementation could get pretty
5307 // sophisticated depending on the complexity required, and should probably be
5308 // done as a subclass of CardLayout in a real-world implementation.
5311 var card = new Ext.Panel({
5312 title: 'Example Wizard',
5314 activeItem: 0, // make sure the active item is set on the container config!
5315 bodyStyle: 'padding:15px',
5317 // applied to each contained panel
5320 // just an example of one possible navigation scheme, using buttons
5325 handler: navHandler.createDelegate(this, [-1]),
5328 '->', // greedy spacer so that the buttons are aligned to each side
5332 handler: navHandler.createDelegate(this, [1])
5335 // the panels (or "cards") within the layout
5338 html: '<h1>Welcome to the Wizard!</h1><p>Step 1 of 3</p>'
5341 html: '<p>Step 2 of 3</p>'
5344 html: '<h1>Congratulations!</h1><p>Step 3 of 3 - Complete</p>'
5349 Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, {
5351 * @cfg {Boolean} deferredRender
5352 * True to render each contained item at the time it becomes active, false to render all contained items
5353 * as soon as the layout is rendered (defaults to false). If there is a significant amount of content or
5354 * a lot of heavy controls being rendered into panels that are not displayed by default, setting this to
5355 * true might improve performance.
5357 deferredRender : false,
5360 * @cfg {Boolean} layoutOnCardChange
5361 * True to force a layout of the active item when the active card is changed. Defaults to false.
5363 layoutOnCardChange : false,
5366 * @cfg {Boolean} renderHidden @hide
5369 renderHidden : true,
5374 * Sets the active (visible) item in the layout.
5375 * @param {String/Number} item The string component id or numeric index of the item to activate
5377 setActiveItem : function(item){
5378 var ai = this.activeItem,
5379 ct = this.container;
5380 item = ct.getComponent(item);
5382 // Is this a valid, different card?
5383 if(item && ai != item){
5385 // Changing cards, hide the current one
5388 if (ai.hidden !== true) {
5391 ai.fireEvent('deactivate', ai);
5394 var layout = item.doLayout && (this.layoutOnCardChange || !item.rendered);
5396 // Change activeItem reference
5397 this.activeItem = item;
5399 // The container is about to get a recursive layout, remove any deferLayout reference
5400 // because it will trigger a redundant layout.
5401 delete item.deferLayout;
5403 // Show the new component
5411 item.fireEvent('activate', item);
5416 renderAll : function(ct, target){
5417 if(this.deferredRender){
5418 this.renderItem(this.activeItem, undefined, target);
5420 Ext.layout.CardLayout.superclass.renderAll.call(this, ct, target);
5424 Ext.Container.LAYOUTS['card'] = Ext.layout.CardLayout;
5426 * @class Ext.layout.AnchorLayout
5427 * @extends Ext.layout.ContainerLayout
5428 * <p>This is a layout that enables anchoring of contained elements relative to the container's dimensions.
5429 * If the container is resized, all anchored items are automatically rerendered according to their
5430 * <b><tt>{@link #anchor}</tt></b> rules.</p>
5431 * <p>This class is intended to be extended or created via the layout:'anchor' {@link Ext.Container#layout}
5432 * config, and should generally not need to be created directly via the new keyword.</p>
5433 * <p>AnchorLayout does not have any direct config options (other than inherited ones). By default,
5434 * AnchorLayout will calculate anchor measurements based on the size of the container itself. However, the
5435 * container using the AnchorLayout can supply an anchoring-specific config property of <b>anchorSize</b>.
5436 * If anchorSize is specifed, the layout will use it as a virtual container for the purposes of calculating
5437 * anchor measurements based on it instead, allowing the container to be sized independently of the anchoring
5438 * logic if necessary. For example:</p>
5440 var viewport = new Ext.Viewport({
5442 anchorSize: {width:800, height:600},
5462 Ext.layout.AnchorLayout = Ext.extend(Ext.layout.ContainerLayout, {
5464 * @cfg {String} anchor
5465 * <p>This configuation option is to be applied to <b>child <tt>items</tt></b> of a container managed by
5466 * this layout (ie. configured with <tt>layout:'anchor'</tt>).</p><br/>
5468 * <p>This value is what tells the layout how an item should be anchored to the container. <tt>items</tt>
5469 * added to an AnchorLayout accept an anchoring-specific config property of <b>anchor</b> which is a string
5470 * containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%').
5471 * The following types of anchor values are supported:<div class="mdetail-params"><ul>
5473 * <li><b>Percentage</b> : Any value between 1 and 100, expressed as a percentage.<div class="sub-desc">
5474 * The first anchor is the percentage width that the item should take up within the container, and the
5475 * second is the percentage height. For example:<pre><code>
5476 // two values specified
5477 anchor: '100% 50%' // render item complete width of the container and
5478 // 1/2 height of the container
5479 // one value specified
5480 anchor: '100%' // the width value; the height will default to auto
5481 * </code></pre></div></li>
5483 * <li><b>Offsets</b> : Any positive or negative integer value.<div class="sub-desc">
5484 * This is a raw adjustment where the first anchor is the offset from the right edge of the container,
5485 * and the second is the offset from the bottom edge. For example:<pre><code>
5486 // two values specified
5487 anchor: '-50 -100' // render item the complete width of the container
5488 // minus 50 pixels and
5489 // the complete height minus 100 pixels.
5490 // one value specified
5491 anchor: '-50' // anchor value is assumed to be the right offset value
5492 // bottom offset will default to 0
5493 * </code></pre></div></li>
5495 * <li><b>Sides</b> : Valid values are <tt>'right'</tt> (or <tt>'r'</tt>) and <tt>'bottom'</tt>
5496 * (or <tt>'b'</tt>).<div class="sub-desc">
5497 * Either the container must have a fixed size or an anchorSize config value defined at render time in
5498 * order for these to have any effect.</div></li>
5500 * <li><b>Mixed</b> : <div class="sub-desc">
5501 * Anchor values can also be mixed as needed. For example, to render the width offset from the container
5502 * right edge by 50 pixels and 75% of the container's height use:
5505 * </code></pre></div></li>
5512 monitorResize : true,
5517 * @cfg {String} defaultAnchor
5519 * default anchor for all child container items applied if no anchor or specific width is set on the child item. Defaults to '100%'.
5522 defaultAnchor : '100%',
5524 parseAnchorRE : /^(r|right|b|bottom)$/i,
5527 getLayoutTargetSize : function() {
5528 var target = this.container.getLayoutTarget(), ret = {};
5530 ret = target.getViewSize();
5532 // IE in strict mode will return a width of 0 on the 1st pass of getViewSize.
5533 // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly
5535 if (Ext.isIE && Ext.isStrict && ret.width == 0){
5536 ret = target.getStyleSize();
5538 ret.width -= target.getPadding('lr');
5539 ret.height -= target.getPadding('tb');
5545 onLayout : function(container, target) {
5546 Ext.layout.AnchorLayout.superclass.onLayout.call(this, container, target);
5548 var size = this.getLayoutTargetSize(),
5549 containerWidth = size.width,
5550 containerHeight = size.height,
5551 overflow = target.getStyle('overflow'),
5552 components = this.getRenderedItems(container),
5553 len = components.length,
5567 if(containerWidth < 20 && containerHeight < 20){
5571 // find the container anchoring size
5572 if(container.anchorSize) {
5573 if(typeof container.anchorSize == 'number') {
5574 anchorWidth = container.anchorSize;
5576 anchorWidth = container.anchorSize.width;
5577 anchorHeight = container.anchorSize.height;
5580 anchorWidth = container.initialConfig.width;
5581 anchorHeight = container.initialConfig.height;
5584 for(i = 0; i < len; i++) {
5585 component = components[i];
5586 el = component.getPositionEl();
5588 // If a child container item has no anchor and no specific width, set the child to the default anchor size
5589 if (!component.anchor && component.items && !Ext.isNumber(component.width) && !(Ext.isIE6 && Ext.isStrict)){
5590 component.anchor = this.defaultAnchor;
5593 if(component.anchor) {
5594 anchorSpec = component.anchorSpec;
5595 // cache all anchor values
5597 anchorsArray = component.anchor.split(' ');
5598 component.anchorSpec = anchorSpec = {
5599 right: this.parseAnchor(anchorsArray[0], component.initialConfig.width, anchorWidth),
5600 bottom: this.parseAnchor(anchorsArray[1], component.initialConfig.height, anchorHeight)
5603 calcWidth = anchorSpec.right ? this.adjustWidthAnchor(anchorSpec.right(containerWidth) - el.getMargins('lr'), component) : undefined;
5604 calcHeight = anchorSpec.bottom ? this.adjustHeightAnchor(anchorSpec.bottom(containerHeight) - el.getMargins('tb'), component) : undefined;
5606 if(calcWidth || calcHeight) {
5608 component: component,
5609 width: calcWidth || undefined,
5610 height: calcHeight || undefined
5615 for (i = 0, len = boxes.length; i < len; i++) {
5617 box.component.setSize(box.width, box.height);
5620 if (overflow && overflow != 'hidden' && !this.adjustmentPass) {
5621 var newTargetSize = this.getLayoutTargetSize();
5622 if (newTargetSize.width != size.width || newTargetSize.height != size.height){
5623 this.adjustmentPass = true;
5624 this.onLayout(container, target);
5628 delete this.adjustmentPass;
5632 parseAnchor : function(a, start, cstart) {
5633 if (a && a != 'none') {
5636 if (this.parseAnchorRE.test(a)) {
5637 var diff = cstart - start;
5645 } else if(a.indexOf('%') != -1) {
5646 var ratio = parseFloat(a.replace('%', ''))*.01;
5650 return Math.floor(v*ratio);
5653 // simple offset adjustment
5655 a = parseInt(a, 10);
5657 return function(v) {
5670 adjustWidthAnchor : function(value, comp){
5675 adjustHeightAnchor : function(value, comp){
5680 * @property activeItem
5684 Ext.Container.LAYOUTS['anchor'] = Ext.layout.AnchorLayout;
5686 * @class Ext.layout.ColumnLayout
5687 * @extends Ext.layout.ContainerLayout
5688 * <p>This is the layout style of choice for creating structural layouts in a multi-column format where the width of
5689 * each column can be specified as a percentage or fixed width, but the height is allowed to vary based on the content.
5690 * This class is intended to be extended or created via the layout:'column' {@link Ext.Container#layout} config,
5691 * and should generally not need to be created directly via the new keyword.</p>
5692 * <p>ColumnLayout does not have any direct config options (other than inherited ones), but it does support a
5693 * specific config property of <b><tt>columnWidth</tt></b> that can be included in the config of any panel added to it. The
5694 * layout will use the columnWidth (if present) or width of each panel during layout to determine how to size each panel.
5695 * If width or columnWidth is not specified for a given panel, its width will default to the panel's width (or auto).</p>
5696 * <p>The width property is always evaluated as pixels, and must be a number greater than or equal to 1.
5697 * The columnWidth property is always evaluated as a percentage, and must be a decimal value greater than 0 and
5698 * less than 1 (e.g., .25).</p>
5699 * <p>The basic rules for specifying column widths are pretty simple. The logic makes two passes through the
5700 * set of contained panels. During the first layout pass, all panels that either have a fixed width or none
5701 * specified (auto) are skipped, but their widths are subtracted from the overall container width. During the second
5702 * pass, all panels with columnWidths are assigned pixel widths in proportion to their percentages based on
5703 * the total <b>remaining</b> container width. In other words, percentage width panels are designed to fill the space
5704 * left over by all the fixed-width and/or auto-width panels. Because of this, while you can specify any number of columns
5705 * with different percentages, the columnWidths must always add up to 1 (or 100%) when added together, otherwise your
5706 * layout may not render as expected. Example usage:</p>
5708 // All columns are percentages -- they must add up to 1
5709 var p = new Ext.Panel({
5710 title: 'Column Layout - Percentage Only',
5724 // Mix of width and columnWidth -- all columnWidth values must add up
5725 // to 1. The first column will take up exactly 120px, and the last two
5726 // columns will fill the remaining container width.
5727 var p = new Ext.Panel({
5728 title: 'Column Layout - Mixed',
5743 Ext.layout.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, {
5749 extraCls: 'x-column',
5755 targetCls: 'x-column-layout-ct',
5757 isValidParent : function(c, target){
5758 return this.innerCt && c.getPositionEl().dom.parentNode == this.innerCt.dom;
5761 getLayoutTargetSize : function() {
5762 var target = this.container.getLayoutTarget(), ret;
5764 ret = target.getViewSize();
5766 // IE in strict mode will return a width of 0 on the 1st pass of getViewSize.
5767 // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly
5769 if (Ext.isIE && Ext.isStrict && ret.width == 0){
5770 ret = target.getStyleSize();
5773 ret.width -= target.getPadding('lr');
5774 ret.height -= target.getPadding('tb');
5779 renderAll : function(ct, target) {
5781 // the innerCt prevents wrapping and shuffling while
5782 // the container is resizing
5783 this.innerCt = target.createChild({cls:'x-column-inner'});
5784 this.innerCt.createChild({cls:'x-clear'});
5786 Ext.layout.ColumnLayout.superclass.renderAll.call(this, ct, this.innerCt);
5790 onLayout : function(ct, target){
5791 var cs = ct.items.items,
5798 this.renderAll(ct, target);
5800 var size = this.getLayoutTargetSize();
5802 if(size.width < 1 && size.height < 1){ // display none?
5806 var w = size.width - this.scrollOffset,
5810 this.innerCt.setWidth(w);
5812 // some columns can be percentages while others are fixed
5813 // so we need to make 2 passes
5815 for(i = 0; i < len; i++){
5817 m = c.getPositionEl().getMargins('lr');
5820 pw -= (c.getWidth() + m);
5824 pw = pw < 0 ? 0 : pw;
5826 for(i = 0; i < len; i++){
5830 c.setSize(Math.floor(c.columnWidth * pw) - m);
5834 // Browsers differ as to when they account for scrollbars. We need to re-measure to see if the scrollbar
5835 // spaces were accounted for properly. If not, re-layout.
5837 if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) {
5838 var ts = this.getLayoutTargetSize();
5839 if (ts.width != size.width){
5840 this.adjustmentPass = true;
5841 this.onLayout(ct, target);
5845 delete this.adjustmentPass;
5849 * @property activeItem
5854 Ext.Container.LAYOUTS['column'] = Ext.layout.ColumnLayout;
5856 * @class Ext.layout.BorderLayout
5857 * @extends Ext.layout.ContainerLayout
5858 * <p>This is a multi-pane, application-oriented UI layout style that supports multiple
5859 * nested panels, automatic {@link Ext.layout.BorderLayout.Region#split split} bars between
5860 * {@link Ext.layout.BorderLayout.Region#BorderLayout.Region regions} and built-in
5861 * {@link Ext.layout.BorderLayout.Region#collapsible expanding and collapsing} of regions.</p>
5862 * <p>This class is intended to be extended or created via the <tt>layout:'border'</tt>
5863 * {@link Ext.Container#layout} config, and should generally not need to be created directly
5864 * via the new keyword.</p>
5865 * <p>BorderLayout does not have any direct config options (other than inherited ones).
5866 * All configuration options available for customizing the BorderLayout are at the
5867 * {@link Ext.layout.BorderLayout.Region} and {@link Ext.layout.BorderLayout.SplitRegion}
5869 * <p>Example usage:</p>
5871 var myBorderPanel = new Ext.Panel({
5872 {@link Ext.Component#renderTo renderTo}: document.body,
5873 {@link Ext.BoxComponent#width width}: 700,
5874 {@link Ext.BoxComponent#height height}: 500,
5875 {@link Ext.Panel#title title}: 'Border Layout',
5876 {@link Ext.Container#layout layout}: 'border',
5877 {@link Ext.Container#items items}: [{
5878 {@link Ext.Panel#title title}: 'South Region is resizable',
5879 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'south', // position for region
5880 {@link Ext.BoxComponent#height height}: 100,
5881 {@link Ext.layout.BorderLayout.Region#split split}: true, // enable resizing
5882 {@link Ext.SplitBar#minSize minSize}: 75, // defaults to {@link Ext.layout.BorderLayout.Region#minHeight 50}
5883 {@link Ext.SplitBar#maxSize maxSize}: 150,
5884 {@link Ext.layout.BorderLayout.Region#margins margins}: '0 5 5 5'
5886 // xtype: 'panel' implied by default
5887 {@link Ext.Panel#title title}: 'West Region is collapsible',
5888 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}:'west',
5889 {@link Ext.layout.BorderLayout.Region#margins margins}: '5 0 0 5',
5890 {@link Ext.BoxComponent#width width}: 200,
5891 {@link Ext.layout.BorderLayout.Region#collapsible collapsible}: true, // make collapsible
5892 {@link Ext.layout.BorderLayout.Region#cmargins cmargins}: '5 5 0 5', // adjust top margin when collapsed
5893 {@link Ext.Component#id id}: 'west-region-container',
5894 {@link Ext.Container#layout layout}: 'fit',
5895 {@link Ext.Panel#unstyled unstyled}: true
5897 {@link Ext.Panel#title title}: 'Center Region',
5898 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'center', // center region is required, no width/height specified
5899 {@link Ext.Component#xtype xtype}: 'container',
5900 {@link Ext.Container#layout layout}: 'fit',
5901 {@link Ext.layout.BorderLayout.Region#margins margins}: '5 5 0 0'
5905 * <p><b><u>Notes</u></b>:</p><div class="mdetail-params"><ul>
5906 * <li>Any container using the BorderLayout <b>must</b> have a child item with <tt>region:'center'</tt>.
5907 * The child item in the center region will always be resized to fill the remaining space not used by
5908 * the other regions in the layout.</li>
5909 * <li>Any child items with a region of <tt>west</tt> or <tt>east</tt> must have <tt>width</tt> defined
5910 * (an integer representing the number of pixels that the region should take up).</li>
5911 * <li>Any child items with a region of <tt>north</tt> or <tt>south</tt> must have <tt>height</tt> defined.</li>
5912 * <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
5913 * Components within a BorderLayout, have them wrapped by an additional Container which is directly
5914 * managed by the BorderLayout. If the region is to be collapsible, the Container used directly
5915 * by the BorderLayout manager should be a Panel. In the following example a Container (an Ext.Panel)
5916 * is added to the west region:
5917 * <div style="margin-left:16px"><pre><code>
5918 wrc = {@link Ext#getCmp Ext.getCmp}('west-region-container');
5919 wrc.{@link Ext.Panel#removeAll removeAll}();
5920 wrc.{@link Ext.Container#add add}({
5921 title: 'Added Panel',
5922 html: 'Some content'
5924 wrc.{@link Ext.Container#doLayout doLayout}();
5925 * </code></pre></div>
5927 * <li> To reference a {@link Ext.layout.BorderLayout.Region Region}:
5928 * <div style="margin-left:16px"><pre><code>
5929 wr = myBorderPanel.layout.west;
5930 * </code></pre></div>
5934 Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {
5942 targetCls: 'x-border-layout-ct',
5944 getLayoutTargetSize : function() {
5945 var target = this.container.getLayoutTarget();
5946 return target ? target.getViewSize() : {};
5950 onLayout : function(ct, target){
5951 var collapsed, i, c, pos, items = ct.items.items, len = items.length;
5954 for(i = 0; i < len; i++) {
5960 c.collapsed = false;
5962 c.render(target, i);
5963 c.getPositionEl().addClass('x-border-panel');
5965 this[pos] = pos != 'center' && c.split ?
5966 new Ext.layout.BorderLayout.SplitRegion(this, c.initialConfig, pos) :
5967 new Ext.layout.BorderLayout.Region(this, c.initialConfig, pos);
5968 this[pos].render(target, c);
5970 this.rendered = true;
5973 var size = this.getLayoutTargetSize();
5974 if(size.width < 20 || size.height < 20){ // display none?
5976 this.restoreCollapsed = collapsed;
5979 }else if(this.restoreCollapsed){
5980 collapsed = this.restoreCollapsed;
5981 delete this.restoreCollapsed;
5984 var w = size.width, h = size.height,
5985 centerW = w, centerH = h, centerY = 0, centerX = 0,
5986 n = this.north, s = this.south, west = this.west, e = this.east, c = this.center,
5987 b, m, totalWidth, totalHeight;
5988 if(!c && Ext.layout.BorderLayout.WARN !== false){
5989 throw 'No center region defined in BorderLayout ' + ct.id;
5992 if(n && n.isVisible()){
5995 b.width = w - (m.left+m.right);
5998 centerY = b.height + b.y + m.bottom;
6002 if(s && s.isVisible()){
6005 b.width = w - (m.left+m.right);
6007 totalHeight = (b.height + m.top + m.bottom);
6008 b.y = h - totalHeight + m.top;
6009 centerH -= totalHeight;
6012 if(west && west.isVisible()){
6014 m = west.getMargins();
6015 b.height = centerH - (m.top+m.bottom);
6017 b.y = centerY + m.top;
6018 totalWidth = (b.width + m.left + m.right);
6019 centerX += totalWidth;
6020 centerW -= totalWidth;
6021 west.applyLayout(b);
6023 if(e && e.isVisible()){
6026 b.height = centerH - (m.top+m.bottom);
6027 totalWidth = (b.width + m.left + m.right);
6028 b.x = w - totalWidth + m.left;
6029 b.y = centerY + m.top;
6030 centerW -= totalWidth;
6036 x: centerX + m.left,
6038 width: centerW - (m.left+m.right),
6039 height: centerH - (m.top+m.bottom)
6041 c.applyLayout(centerBox);
6044 for(i = 0, len = collapsed.length; i < len; i++){
6045 collapsed[i].collapse(false);
6048 if(Ext.isIE && Ext.isStrict){ // workaround IE strict repainting issue
6051 // Putting a border layout into an overflowed container is NOT correct and will make a second layout pass necessary.
6052 if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) {
6053 var ts = this.getLayoutTargetSize();
6054 if (ts.width != size.width || ts.height != size.height){
6055 this.adjustmentPass = true;
6056 this.onLayout(ct, target);
6059 delete this.adjustmentPass;
6062 destroy: function() {
6063 var r = ['north', 'south', 'east', 'west'], i, region;
6064 for (i = 0; i < r.length; i++) {
6065 region = this[r[i]];
6069 }else if (region.split){
6070 region.split.destroy(true);
6074 Ext.layout.BorderLayout.superclass.destroy.call(this);
6078 * @property activeItem
6084 * @class Ext.layout.BorderLayout.Region
6085 * <p>This is a region of a {@link Ext.layout.BorderLayout BorderLayout} that acts as a subcontainer
6086 * within the layout. Each region has its own {@link Ext.layout.ContainerLayout layout} that is
6087 * independent of other regions and the containing BorderLayout, and can be any of the
6088 * {@link Ext.layout.ContainerLayout valid Ext layout types}.</p>
6089 * <p>Region size is managed automatically and cannot be changed by the user -- for
6090 * {@link #split resizable regions}, see {@link Ext.layout.BorderLayout.SplitRegion}.</p>
6092 * Create a new Region.
6093 * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region.
6094 * @param {Object} config The configuration options
6095 * @param {String} position The region position. Valid values are: <tt>north</tt>, <tt>south</tt>,
6096 * <tt>east</tt>, <tt>west</tt> and <tt>center</tt>. Every {@link Ext.layout.BorderLayout BorderLayout}
6097 * <b>must have a center region</b> for the primary content -- all other regions are optional.
6099 Ext.layout.BorderLayout.Region = function(layout, config, pos){
6100 Ext.apply(this, config);
6101 this.layout = layout;
6102 this.position = pos;
6104 if(typeof this.margins == 'string'){
6105 this.margins = this.layout.parseMargins(this.margins);
6107 this.margins = Ext.applyIf(this.margins || {}, this.defaultMargins);
6108 if(this.collapsible){
6109 if(typeof this.cmargins == 'string'){
6110 this.cmargins = this.layout.parseMargins(this.cmargins);
6112 if(this.collapseMode == 'mini' && !this.cmargins){
6113 this.cmargins = {left:0,top:0,right:0,bottom:0};
6115 this.cmargins = Ext.applyIf(this.cmargins || {},
6116 pos == 'north' || pos == 'south' ? this.defaultNSCMargins : this.defaultEWCMargins);
6121 Ext.layout.BorderLayout.Region.prototype = {
6123 * @cfg {Boolean} animFloat
6124 * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated
6125 * panel that will close again once the user mouses out of that panel (or clicks out if
6126 * <tt>{@link #autoHide} = false</tt>). Setting <tt>{@link #animFloat} = false</tt> will
6127 * prevent the open and close of these floated panels from being animated (defaults to <tt>true</tt>).
6130 * @cfg {Boolean} autoHide
6131 * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated
6132 * panel. If <tt>autoHide = true</tt>, the panel will automatically hide after the user mouses
6133 * out of the panel. If <tt>autoHide = false</tt>, the panel will continue to display until the
6134 * user clicks outside of the panel (defaults to <tt>true</tt>).
6137 * @cfg {String} collapseMode
6138 * <tt>collapseMode</tt> supports two configuration values:<div class="mdetail-params"><ul>
6139 * <li><b><tt>undefined</tt></b> (default)<div class="sub-desc">By default, {@link #collapsible}
6140 * regions are collapsed by clicking the expand/collapse tool button that renders into the region's
6141 * title bar.</div></li>
6142 * <li><b><tt>'mini'</tt></b><div class="sub-desc">Optionally, when <tt>collapseMode</tt> is set to
6143 * <tt>'mini'</tt> the region's split bar will also display a small collapse button in the center of
6144 * the bar. In <tt>'mini'</tt> mode the region will collapse to a thinner bar than in normal mode.
6147 * <p><b>Note</b>: if a collapsible region does not have a title bar, then set <tt>collapseMode =
6148 * 'mini'</tt> and <tt>{@link #split} = true</tt> in order for the region to be {@link #collapsible}
6149 * by the user as the expand/collapse tool button (that would go in the title bar) will not be rendered.</p>
6150 * <p>See also <tt>{@link #cmargins}</tt>.</p>
6153 * @cfg {Object} margins
6154 * An object containing margins to apply to the region when in the expanded state in the
6155 * format:<pre><code>
6158 right: (right margin),
6159 bottom: (bottom margin),
6162 * <p>May also be a string containing space-separated, numeric margin values. The order of the
6163 * sides associated with each value matches the way CSS processes margin values:</p>
6164 * <p><div class="mdetail-params"><ul>
6165 * <li>If there is only one value, it applies to all sides.</li>
6166 * <li>If there are two values, the top and bottom borders are set to the first value and the
6167 * right and left are set to the second.</li>
6168 * <li>If there are three values, the top is set to the first value, the left and right are set
6169 * to the second, and the bottom is set to the third.</li>
6170 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
6172 * <p>Defaults to:</p><pre><code>
6173 * {top:0, right:0, bottom:0, left:0}
6177 * @cfg {Object} cmargins
6178 * An object containing margins to apply to the region when in the collapsed state in the
6179 * format:<pre><code>
6182 right: (right margin),
6183 bottom: (bottom margin),
6186 * <p>May also be a string containing space-separated, numeric margin values. The order of the
6187 * sides associated with each value matches the way CSS processes margin values.</p>
6189 * <li>If there is only one value, it applies to all sides.</li>
6190 * <li>If there are two values, the top and bottom borders are set to the first value and the
6191 * right and left are set to the second.</li>
6192 * <li>If there are three values, the top is set to the first value, the left and right are set
6193 * to the second, and the bottom is set to the third.</li>
6194 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
6198 * @cfg {Boolean} collapsible
6199 * <p><tt>true</tt> to allow the user to collapse this region (defaults to <tt>false</tt>). If
6200 * <tt>true</tt>, an expand/collapse tool button will automatically be rendered into the title
6201 * bar of the region, otherwise the button will not be shown.</p>
6202 * <p><b>Note</b>: that a title bar is required to display the collapse/expand toggle button -- if
6203 * no <tt>title</tt> is specified for the region's panel, the region will only be collapsible if
6204 * <tt>{@link #collapseMode} = 'mini'</tt> and <tt>{@link #split} = true</tt>.
6206 collapsible : false,
6208 * @cfg {Boolean} split
6209 * <p><tt>true</tt> to create a {@link Ext.layout.BorderLayout.SplitRegion SplitRegion} and
6210 * display a 5px wide {@link Ext.SplitBar} between this region and its neighbor, allowing the user to
6211 * resize the regions dynamically. Defaults to <tt>false</tt> creating a
6212 * {@link Ext.layout.BorderLayout.Region Region}.</p><br>
6213 * <p><b>Notes</b>:</p><div class="mdetail-params"><ul>
6214 * <li>this configuration option is ignored if <tt>region='center'</tt></li>
6215 * <li>when <tt>split == true</tt>, it is common to specify a
6216 * <tt>{@link Ext.SplitBar#minSize minSize}</tt> and <tt>{@link Ext.SplitBar#maxSize maxSize}</tt>
6217 * for the {@link Ext.BoxComponent BoxComponent} representing the region. These are not native
6218 * configs of {@link Ext.BoxComponent BoxComponent}, and are used only by this class.</li>
6219 * <li>if <tt>{@link #collapseMode} = 'mini'</tt> requires <tt>split = true</tt> to reserve space
6220 * for the collapse tool</tt></li>
6225 * @cfg {Boolean} floatable
6226 * <tt>true</tt> to allow clicking a collapsed region's bar to display the region's panel floated
6227 * above the layout, <tt>false</tt> to force the user to fully expand a collapsed region by
6228 * clicking the expand button to see it again (defaults to <tt>true</tt>).
6232 * @cfg {Number} minWidth
6233 * <p>The minimum allowable width in pixels for this region (defaults to <tt>50</tt>).
6234 * <tt>maxWidth</tt> may also be specified.</p><br>
6235 * <p><b>Note</b>: setting the <tt>{@link Ext.SplitBar#minSize minSize}</tt> /
6236 * <tt>{@link Ext.SplitBar#maxSize maxSize}</tt> supersedes any specified
6237 * <tt>minWidth</tt> / <tt>maxWidth</tt>.</p>
6241 * @cfg {Number} minHeight
6242 * The minimum allowable height in pixels for this region (defaults to <tt>50</tt>)
6243 * <tt>maxHeight</tt> may also be specified.</p><br>
6244 * <p><b>Note</b>: setting the <tt>{@link Ext.SplitBar#minSize minSize}</tt> /
6245 * <tt>{@link Ext.SplitBar#maxSize maxSize}</tt> supersedes any specified
6246 * <tt>minHeight</tt> / <tt>maxHeight</tt>.</p>
6251 defaultMargins : {left:0,top:0,right:0,bottom:0},
6253 defaultNSCMargins : {left:5,top:5,right:5,bottom:5},
6255 defaultEWCMargins : {left:5,top:0,right:5,bottom:0},
6256 floatingZIndex: 100,
6259 * True if this region is collapsed. Read-only.
6263 isCollapsed : false,
6266 * This region's panel. Read-only.
6271 * This region's layout. Read-only.
6276 * This region's layout position (north, south, east, west or center). Read-only.
6278 * @property position
6282 render : function(ct, p){
6284 p.el.enableDisplayMode();
6288 var gs = p.getState, ps = this.position;
6289 p.getState = function(){
6290 return Ext.apply(gs.call(p) || {}, this.state);
6291 }.createDelegate(this);
6294 p.allowQueuedExpand = false;
6296 beforecollapse: this.beforeCollapse,
6297 collapse: this.onCollapse,
6298 beforeexpand: this.beforeExpand,
6299 expand: this.onExpand,
6304 if(this.collapsible || this.floatable){
6305 p.collapseEl = 'el';
6306 p.slideAnchor = this.getSlideAnchor();
6308 if(p.tools && p.tools.toggle){
6309 p.tools.toggle.addClass('x-tool-collapse-'+ps);
6310 p.tools.toggle.addClassOnOver('x-tool-collapse-'+ps+'-over');
6316 getCollapsedEl : function(){
6317 if(!this.collapsedEl){
6318 if(!this.toolTemplate){
6319 var tt = new Ext.Template(
6320 '<div class="x-tool x-tool-{id}"> </div>'
6322 tt.disableFormats = true;
6324 Ext.layout.BorderLayout.Region.prototype.toolTemplate = tt;
6326 this.collapsedEl = this.targetEl.createChild({
6327 cls: "x-layout-collapsed x-layout-collapsed-"+this.position,
6328 id: this.panel.id + '-xcollapsed'
6330 this.collapsedEl.enableDisplayMode('block');
6332 if(this.collapseMode == 'mini'){
6333 this.collapsedEl.addClass('x-layout-cmini-'+this.position);
6334 this.miniCollapsedEl = this.collapsedEl.createChild({
6335 cls: "x-layout-mini x-layout-mini-"+this.position, html: " "
6337 this.miniCollapsedEl.addClassOnOver('x-layout-mini-over');
6338 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
6339 this.collapsedEl.on('click', this.onExpandClick, this, {stopEvent:true});
6341 if(this.collapsible !== false && !this.hideCollapseTool) {
6342 var t = this.expandToolEl = this.toolTemplate.append(
6343 this.collapsedEl.dom,
6344 {id:'expand-'+this.position}, true);
6345 t.addClassOnOver('x-tool-expand-'+this.position+'-over');
6346 t.on('click', this.onExpandClick, this, {stopEvent:true});
6348 if(this.floatable !== false || this.titleCollapse){
6349 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
6350 this.collapsedEl.on("click", this[this.floatable ? 'collapseClick' : 'onExpandClick'], this);
6354 return this.collapsedEl;
6358 onExpandClick : function(e){
6360 this.panel.expand(false);
6362 this.panel.expand();
6367 onCollapseClick : function(e){
6368 this.panel.collapse();
6372 beforeCollapse : function(p, animate){
6373 this.lastAnim = animate;
6375 this.splitEl.hide();
6377 this.getCollapsedEl().show();
6378 var el = this.panel.getEl();
6379 this.originalZIndex = el.getStyle('z-index');
6380 el.setStyle('z-index', 100);
6381 this.isCollapsed = true;
6382 this.layout.layout();
6386 onCollapse : function(animate){
6387 this.panel.el.setStyle('z-index', 1);
6388 if(this.lastAnim === false || this.panel.animCollapse === false){
6389 this.getCollapsedEl().dom.style.visibility = 'visible';
6391 this.getCollapsedEl().slideIn(this.panel.slideAnchor, {duration:.2});
6393 this.state.collapsed = true;
6394 this.panel.saveState();
6398 beforeExpand : function(animate){
6400 this.afterSlideIn();
6402 var c = this.getCollapsedEl();
6404 if(this.position == 'east' || this.position == 'west'){
6405 this.panel.setSize(undefined, c.getHeight());
6407 this.panel.setSize(c.getWidth(), undefined);
6410 c.dom.style.visibility = 'hidden';
6411 this.panel.el.setStyle('z-index', this.floatingZIndex);
6415 onExpand : function(){
6416 this.isCollapsed = false;
6418 this.splitEl.show();
6420 this.layout.layout();
6421 this.panel.el.setStyle('z-index', this.originalZIndex);
6422 this.state.collapsed = false;
6423 this.panel.saveState();
6427 collapseClick : function(e){
6429 e.stopPropagation();
6432 e.stopPropagation();
6438 onHide : function(){
6439 if(this.isCollapsed){
6440 this.getCollapsedEl().hide();
6441 }else if(this.splitEl){
6442 this.splitEl.hide();
6447 onShow : function(){
6448 if(this.isCollapsed){
6449 this.getCollapsedEl().show();
6450 }else if(this.splitEl){
6451 this.splitEl.show();
6456 * True if this region is currently visible, else false.
6459 isVisible : function(){
6460 return !this.panel.hidden;
6464 * Returns the current margins for this region. If the region is collapsed, the
6465 * {@link #cmargins} (collapsed margins) value will be returned, otherwise the
6466 * {@link #margins} value will be returned.
6467 * @return {Object} An object containing the element's margins: <tt>{left: (left
6468 * margin), top: (top margin), right: (right margin), bottom: (bottom margin)}</tt>
6470 getMargins : function(){
6471 return this.isCollapsed && this.cmargins ? this.cmargins : this.margins;
6475 * Returns the current size of this region. If the region is collapsed, the size of the
6476 * collapsedEl will be returned, otherwise the size of the region's panel will be returned.
6477 * @return {Object} An object containing the element's size: <tt>{width: (element width),
6478 * height: (element height)}</tt>
6480 getSize : function(){
6481 return this.isCollapsed ? this.getCollapsedEl().getSize() : this.panel.getSize();
6485 * Sets the specified panel as the container element for this region.
6486 * @param {Ext.Panel} panel The new panel
6488 setPanel : function(panel){
6493 * Returns the minimum allowable width for this region.
6494 * @return {Number} The minimum width
6496 getMinWidth: function(){
6497 return this.minWidth;
6501 * Returns the minimum allowable height for this region.
6502 * @return {Number} The minimum height
6504 getMinHeight: function(){
6505 return this.minHeight;
6509 applyLayoutCollapsed : function(box){
6510 var ce = this.getCollapsedEl();
6511 ce.setLeftTop(box.x, box.y);
6512 ce.setSize(box.width, box.height);
6516 applyLayout : function(box){
6517 if(this.isCollapsed){
6518 this.applyLayoutCollapsed(box);
6520 this.panel.setPosition(box.x, box.y);
6521 this.panel.setSize(box.width, box.height);
6526 beforeSlide: function(){
6527 this.panel.beforeEffect();
6531 afterSlide : function(){
6532 this.panel.afterEffect();
6536 initAutoHide : function(){
6537 if(this.autoHide !== false){
6538 if(!this.autoHideHd){
6539 this.autoHideSlideTask = new Ext.util.DelayedTask(this.slideIn, this);
6541 "mouseout": function(e){
6542 if(!e.within(this.el, true)){
6543 this.autoHideSlideTask.delay(500);
6546 "mouseover" : function(e){
6547 this.autoHideSlideTask.cancel();
6552 this.el.on(this.autoHideHd);
6553 this.collapsedEl.on(this.autoHideHd);
6558 clearAutoHide : function(){
6559 if(this.autoHide !== false){
6560 this.el.un("mouseout", this.autoHideHd.mouseout);
6561 this.el.un("mouseover", this.autoHideHd.mouseover);
6562 this.collapsedEl.un("mouseout", this.autoHideHd.mouseout);
6563 this.collapsedEl.un("mouseover", this.autoHideHd.mouseover);
6568 clearMonitor : function(){
6569 Ext.getDoc().un("click", this.slideInIf, this);
6573 * If this Region is {@link #floatable}, this method slides this Region into full visibility <i>over the top
6574 * of the center Region</i> where it floats until either {@link #slideIn} is called, or other regions of the layout
6575 * are clicked, or the mouse exits the Region.
6577 slideOut : function(){
6578 if(this.isSlid || this.el.hasActiveFx()){
6582 var ts = this.panel.tools, dh, pc;
6583 if(ts && ts.toggle){
6588 // Temporarily clear the collapsed flag so we can onResize the panel on the slide
6589 pc = this.panel.collapsed;
6590 this.panel.collapsed = false;
6592 if(this.position == 'east' || this.position == 'west'){
6593 // Temporarily clear the deferHeight flag so we can size the height on the slide
6594 dh = this.panel.deferHeight;
6595 this.panel.deferHeight = false;
6597 this.panel.setSize(undefined, this.collapsedEl.getHeight());
6599 // Put the deferHeight flag back after setSize
6600 this.panel.deferHeight = dh;
6602 this.panel.setSize(this.collapsedEl.getWidth(), undefined);
6605 // Put the collapsed flag back after onResize
6606 this.panel.collapsed = pc;
6608 this.restoreLT = [this.el.dom.style.left, this.el.dom.style.top];
6609 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
6610 this.el.setStyle("z-index", this.floatingZIndex+2);
6611 this.panel.el.replaceClass('x-panel-collapsed', 'x-panel-floating');
6612 if(this.animFloat !== false){
6614 this.el.slideIn(this.getSlideAnchor(), {
6615 callback: function(){
6617 this.initAutoHide();
6618 Ext.getDoc().on("click", this.slideInIf, this);
6624 this.initAutoHide();
6625 Ext.getDoc().on("click", this.slideInIf, this);
6630 afterSlideIn : function(){
6631 this.clearAutoHide();
6632 this.isSlid = false;
6633 this.clearMonitor();
6634 this.el.setStyle("z-index", "");
6635 this.panel.el.replaceClass('x-panel-floating', 'x-panel-collapsed');
6636 this.el.dom.style.left = this.restoreLT[0];
6637 this.el.dom.style.top = this.restoreLT[1];
6639 var ts = this.panel.tools;
6640 if(ts && ts.toggle){
6646 * If this Region is {@link #floatable}, and this Region has been slid into floating visibility, then this method slides
6647 * this region back into its collapsed state.
6649 slideIn : function(cb){
6650 if(!this.isSlid || this.el.hasActiveFx()){
6654 this.isSlid = false;
6655 if(this.animFloat !== false){
6657 this.el.slideOut(this.getSlideAnchor(), {
6658 callback: function(){
6661 this.afterSlideIn();
6669 this.afterSlideIn();
6674 slideInIf : function(e){
6675 if(!e.within(this.el)){
6705 getAnchor : function(){
6706 return this.anchors[this.position];
6710 getCollapseAnchor : function(){
6711 return this.canchors[this.position];
6715 getSlideAnchor : function(){
6716 return this.sanchors[this.position];
6720 getAlignAdj : function(){
6721 var cm = this.cmargins;
6722 switch(this.position){
6739 getExpandAdj : function(){
6740 var c = this.collapsedEl, cm = this.cmargins;
6741 switch(this.position){
6743 return [-(cm.right+c.getWidth()+cm.left), 0];
6746 return [cm.right+c.getWidth()+cm.left, 0];
6749 return [0, -(cm.top+cm.bottom+c.getHeight())];
6752 return [0, cm.top+cm.bottom+c.getHeight()];
6757 destroy : function(){
6758 if (this.autoHideSlideTask && this.autoHideSlideTask.cancel){
6759 this.autoHideSlideTask.cancel();
6761 Ext.destroyMembers(this, 'miniCollapsedEl', 'collapsedEl', 'expandToolEl');
6766 * @class Ext.layout.BorderLayout.SplitRegion
6767 * @extends Ext.layout.BorderLayout.Region
6768 * <p>This is a specialized type of {@link Ext.layout.BorderLayout.Region BorderLayout region} that
6769 * has a built-in {@link Ext.SplitBar} for user resizing of regions. The movement of the split bar
6770 * is configurable to move either {@link #tickSize smooth or incrementally}.</p>
6772 * Create a new SplitRegion.
6773 * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region.
6774 * @param {Object} config The configuration options
6775 * @param {String} position The region position. Valid values are: north, south, east, west and center. Every
6776 * BorderLayout must have a center region for the primary content -- all other regions are optional.
6778 Ext.layout.BorderLayout.SplitRegion = function(layout, config, pos){
6779 Ext.layout.BorderLayout.SplitRegion.superclass.constructor.call(this, layout, config, pos);
6781 this.applyLayout = this.applyFns[pos];
6784 Ext.extend(Ext.layout.BorderLayout.SplitRegion, Ext.layout.BorderLayout.Region, {
6786 * @cfg {Number} tickSize
6787 * The increment, in pixels by which to move this Region's {@link Ext.SplitBar SplitBar}.
6788 * By default, the {@link Ext.SplitBar SplitBar} moves smoothly.
6791 * @cfg {String} splitTip
6792 * The tooltip to display when the user hovers over a
6793 * {@link Ext.layout.BorderLayout.Region#collapsible non-collapsible} region's split bar
6794 * (defaults to <tt>"Drag to resize."</tt>). Only applies if
6795 * <tt>{@link #useSplitTips} = true</tt>.
6797 splitTip : "Drag to resize.",
6799 * @cfg {String} collapsibleSplitTip
6800 * The tooltip to display when the user hovers over a
6801 * {@link Ext.layout.BorderLayout.Region#collapsible collapsible} region's split bar
6802 * (defaults to "Drag to resize. Double click to hide."). Only applies if
6803 * <tt>{@link #useSplitTips} = true</tt>.
6805 collapsibleSplitTip : "Drag to resize. Double click to hide.",
6807 * @cfg {Boolean} useSplitTips
6808 * <tt>true</tt> to display a tooltip when the user hovers over a region's split bar
6809 * (defaults to <tt>false</tt>). The tooltip text will be the value of either
6810 * <tt>{@link #splitTip}</tt> or <tt>{@link #collapsibleSplitTip}</tt> as appropriate.
6812 useSplitTips : false,
6817 orientation: Ext.SplitBar.VERTICAL,
6818 placement: Ext.SplitBar.TOP,
6819 maxFn : 'getVMaxSize',
6820 minProp: 'minHeight',
6821 maxProp: 'maxHeight'
6824 orientation: Ext.SplitBar.VERTICAL,
6825 placement: Ext.SplitBar.BOTTOM,
6826 maxFn : 'getVMaxSize',
6827 minProp: 'minHeight',
6828 maxProp: 'maxHeight'
6831 orientation: Ext.SplitBar.HORIZONTAL,
6832 placement: Ext.SplitBar.RIGHT,
6833 maxFn : 'getHMaxSize',
6834 minProp: 'minWidth',
6838 orientation: Ext.SplitBar.HORIZONTAL,
6839 placement: Ext.SplitBar.LEFT,
6840 maxFn : 'getHMaxSize',
6841 minProp: 'minWidth',
6848 west : function(box){
6849 if(this.isCollapsed){
6850 return this.applyLayoutCollapsed(box);
6852 var sd = this.splitEl.dom, s = sd.style;
6853 this.panel.setPosition(box.x, box.y);
6854 var sw = sd.offsetWidth;
6855 s.left = (box.x+box.width-sw)+'px';
6856 s.top = (box.y)+'px';
6857 s.height = Math.max(0, box.height)+'px';
6858 this.panel.setSize(box.width-sw, box.height);
6860 east : function(box){
6861 if(this.isCollapsed){
6862 return this.applyLayoutCollapsed(box);
6864 var sd = this.splitEl.dom, s = sd.style;
6865 var sw = sd.offsetWidth;
6866 this.panel.setPosition(box.x+sw, box.y);
6867 s.left = (box.x)+'px';
6868 s.top = (box.y)+'px';
6869 s.height = Math.max(0, box.height)+'px';
6870 this.panel.setSize(box.width-sw, box.height);
6872 north : function(box){
6873 if(this.isCollapsed){
6874 return this.applyLayoutCollapsed(box);
6876 var sd = this.splitEl.dom, s = sd.style;
6877 var sh = sd.offsetHeight;
6878 this.panel.setPosition(box.x, box.y);
6879 s.left = (box.x)+'px';
6880 s.top = (box.y+box.height-sh)+'px';
6881 s.width = Math.max(0, box.width)+'px';
6882 this.panel.setSize(box.width, box.height-sh);
6884 south : function(box){
6885 if(this.isCollapsed){
6886 return this.applyLayoutCollapsed(box);
6888 var sd = this.splitEl.dom, s = sd.style;
6889 var sh = sd.offsetHeight;
6890 this.panel.setPosition(box.x, box.y+sh);
6891 s.left = (box.x)+'px';
6892 s.top = (box.y)+'px';
6893 s.width = Math.max(0, box.width)+'px';
6894 this.panel.setSize(box.width, box.height-sh);
6899 render : function(ct, p){
6900 Ext.layout.BorderLayout.SplitRegion.superclass.render.call(this, ct, p);
6902 var ps = this.position;
6904 this.splitEl = ct.createChild({
6905 cls: "x-layout-split x-layout-split-"+ps, html: " ",
6906 id: this.panel.id + '-xsplit'
6909 if(this.collapseMode == 'mini'){
6910 this.miniSplitEl = this.splitEl.createChild({
6911 cls: "x-layout-mini x-layout-mini-"+ps, html: " "
6913 this.miniSplitEl.addClassOnOver('x-layout-mini-over');
6914 this.miniSplitEl.on('click', this.onCollapseClick, this, {stopEvent:true});
6917 var s = this.splitSettings[ps];
6919 this.split = new Ext.SplitBar(this.splitEl.dom, p.el, s.orientation);
6920 this.split.tickSize = this.tickSize;
6921 this.split.placement = s.placement;
6922 this.split.getMaximumSize = this[s.maxFn].createDelegate(this);
6923 this.split.minSize = this.minSize || this[s.minProp];
6924 this.split.on("beforeapply", this.onSplitMove, this);
6925 this.split.useShim = this.useShim === true;
6926 this.maxSize = this.maxSize || this[s.maxProp];
6929 this.splitEl.hide();
6932 if(this.useSplitTips){
6933 this.splitEl.dom.title = this.collapsible ? this.collapsibleSplitTip : this.splitTip;
6935 if(this.collapsible){
6936 this.splitEl.on("dblclick", this.onCollapseClick, this);
6940 //docs inherit from superclass
6941 getSize : function(){
6942 if(this.isCollapsed){
6943 return this.collapsedEl.getSize();
6945 var s = this.panel.getSize();
6946 if(this.position == 'north' || this.position == 'south'){
6947 s.height += this.splitEl.dom.offsetHeight;
6949 s.width += this.splitEl.dom.offsetWidth;
6955 getHMaxSize : function(){
6956 var cmax = this.maxSize || 10000;
6957 var center = this.layout.center;
6958 return Math.min(cmax, (this.el.getWidth()+center.el.getWidth())-center.getMinWidth());
6962 getVMaxSize : function(){
6963 var cmax = this.maxSize || 10000;
6964 var center = this.layout.center;
6965 return Math.min(cmax, (this.el.getHeight()+center.el.getHeight())-center.getMinHeight());
6969 onSplitMove : function(split, newSize){
6970 var s = this.panel.getSize();
6971 this.lastSplitSize = newSize;
6972 if(this.position == 'north' || this.position == 'south'){
6973 this.panel.setSize(s.width, newSize);
6974 this.state.height = newSize;
6976 this.panel.setSize(newSize, s.height);
6977 this.state.width = newSize;
6979 this.layout.layout();
6980 this.panel.saveState();
6985 * Returns a reference to the split bar in use by this region.
6986 * @return {Ext.SplitBar} The split bar
6988 getSplitBar : function(){
6993 destroy : function() {
6994 Ext.destroy(this.miniSplitEl, this.split, this.splitEl);
6995 Ext.layout.BorderLayout.SplitRegion.superclass.destroy.call(this);
6999 Ext.Container.LAYOUTS['border'] = Ext.layout.BorderLayout;
7001 * @class Ext.layout.FormLayout
7002 * @extends Ext.layout.AnchorLayout
7003 * <p>This layout manager is specifically designed for rendering and managing child Components of
7004 * {@link Ext.form.FormPanel forms}. It is responsible for rendering the labels of
7005 * {@link Ext.form.Field Field}s.</p>
7007 * <p>This layout manager is used when a Container is configured with the <tt>layout:'form'</tt>
7008 * {@link Ext.Container#layout layout} config option, and should generally not need to be created directly
7009 * via the new keyword. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
7011 * <p>In an application, it will usually be preferrable to use a {@link Ext.form.FormPanel FormPanel}
7012 * (which is configured with FormLayout as its layout class by default) since it also provides built-in
7013 * functionality for {@link Ext.form.BasicForm#doAction loading, validating and submitting} the form.</p>
7015 * <p>A {@link Ext.Container Container} <i>using</i> the FormLayout layout manager (e.g.
7016 * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>) can also accept the following
7017 * layout-specific config properties:<div class="mdetail-params"><ul>
7018 * <li><b><tt>{@link Ext.form.FormPanel#hideLabels hideLabels}</tt></b></li>
7019 * <li><b><tt>{@link Ext.form.FormPanel#labelAlign labelAlign}</tt></b></li>
7020 * <li><b><tt>{@link Ext.form.FormPanel#labelPad labelPad}</tt></b></li>
7021 * <li><b><tt>{@link Ext.form.FormPanel#labelSeparator labelSeparator}</tt></b></li>
7022 * <li><b><tt>{@link Ext.form.FormPanel#labelWidth labelWidth}</tt></b></li>
7025 * <p>Any Component (including Fields) managed by FormLayout accepts the following as a config option:
7026 * <div class="mdetail-params"><ul>
7027 * <li><b><tt>{@link Ext.Component#anchor anchor}</tt></b></li>
7030 * <p>Any Component managed by FormLayout may be rendered as a form field (with an associated label) by
7031 * configuring it with a non-null <b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b>. Components configured
7032 * in this way may be configured with the following options which affect the way the FormLayout renders them:
7033 * <div class="mdetail-params"><ul>
7034 * <li><b><tt>{@link Ext.Component#clearCls clearCls}</tt></b></li>
7035 * <li><b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b></li>
7036 * <li><b><tt>{@link Ext.Component#hideLabel hideLabel}</tt></b></li>
7037 * <li><b><tt>{@link Ext.Component#itemCls itemCls}</tt></b></li>
7038 * <li><b><tt>{@link Ext.Component#labelSeparator labelSeparator}</tt></b></li>
7039 * <li><b><tt>{@link Ext.Component#labelStyle labelStyle}</tt></b></li>
7042 * <p>Example usage:</p>
7044 // Required if showing validation messages
7045 Ext.QuickTips.init();
7047 // While you can create a basic Panel with layout:'form', practically
7048 // you should usually use a FormPanel to also get its form functionality
7049 // since it already creates a FormLayout internally.
7050 var form = new Ext.form.FormPanel({
7051 title: 'Form Layout',
7052 bodyStyle: 'padding:15px',
7054 defaultType: 'textfield',
7056 // applied to each contained item
7061 fieldLabel: 'First Name',
7064 {@link Ext.Component#labelSeparator labelSeparator}: ':' // override labelSeparator layout config
7066 fieldLabel: 'Last Name',
7069 fieldLabel: 'Email',
7074 hideLabel: true, // override hideLabels layout config
7084 {@link #labelSeparator}: '~' // superseded by assignment below
7086 // config options applicable to container when layout='form':
7088 labelAlign: 'left', // or 'right' or 'top'
7089 {@link Ext.form.FormPanel#labelSeparator labelSeparator}: '>>', // takes precedence over layoutConfig value
7090 labelWidth: 65, // defaults to 100
7091 labelPad: 8 // defaults to 5, must specify labelWidth to be honored
7095 Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, {
7098 * @cfg {String} labelSeparator
7099 * See {@link Ext.form.FormPanel}.{@link Ext.form.FormPanel#labelSeparator labelSeparator}. Configuration
7100 * of this property at the <b>container</b> level takes precedence.
7102 labelSeparator : ':',
7105 * Read only. The CSS style specification string added to field labels in this layout if not
7106 * otherwise {@link Ext.Component#labelStyle specified by each contained field}.
7108 * @property labelStyle
7112 * @cfg {Boolean} trackLabels
7113 * True to show/hide the field label when the field is hidden. Defaults to <tt>true</tt>.
7119 onRemove: function(c){
7120 Ext.layout.FormLayout.superclass.onRemove.call(this, c);
7121 if(this.trackLabels){
7122 c.un('show', this.onFieldShow, this);
7123 c.un('hide', this.onFieldHide, this);
7125 // check for itemCt, since we may be removing a fieldset or something similar
7126 var el = c.getPositionEl(),
7127 ct = c.getItemCt && c.getItemCt();
7128 if (c.rendered && ct) {
7133 Ext.destroyMembers(c, 'label', 'itemCt');
7134 if (c.customItemCt) {
7135 Ext.destroyMembers(c, 'getItemCt', 'customItemCt');
7141 setContainer : function(ct){
7142 Ext.layout.FormLayout.superclass.setContainer.call(this, ct);
7144 ct.addClass('x-form-label-'+ct.labelAlign);
7149 labelStyle: 'display:none',
7150 elementStyle: 'padding-left:0;',
7154 this.labelSeparator = Ext.isDefined(ct.labelSeparator) ? ct.labelSeparator : this.labelSeparator;
7155 ct.labelWidth = ct.labelWidth || 100;
7156 if(Ext.isNumber(ct.labelWidth)){
7157 var pad = Ext.isNumber(ct.labelPad) ? ct.labelPad : 5;
7159 labelAdjust: ct.labelWidth + pad,
7160 labelStyle: 'width:' + ct.labelWidth + 'px;',
7161 elementStyle: 'padding-left:' + (ct.labelWidth + pad) + 'px'
7164 if(ct.labelAlign == 'top'){
7166 labelStyle: 'width:auto;',
7168 elementStyle: 'padding-left:0;'
7175 isHide: function(c){
7176 return c.hideLabel || this.container.hideLabels;
7179 onFieldShow: function(c){
7180 c.getItemCt().removeClass('x-hide-' + c.hideMode);
7182 // Composite fields will need to layout after the container is made visible
7183 if (c.isComposite) {
7188 onFieldHide: function(c){
7189 c.getItemCt().addClass('x-hide-' + c.hideMode);
7193 getLabelStyle: function(s){
7194 var ls = '', items = [this.labelStyle, s];
7195 for (var i = 0, len = items.length; i < len; ++i){
7198 if (ls.substr(-1, 1) != ';'){
7207 * @cfg {Ext.Template} fieldTpl
7208 * A {@link Ext.Template#compile compile}d {@link Ext.Template} for rendering
7209 * the fully wrapped, labeled and styled form Field. Defaults to:</p><pre><code>
7211 '<div class="x-form-item {itemCls}" tabIndex="-1">',
7212 '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{labelSeparator}</label>',
7213 '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
7214 '</div><div class="{clearCls}"></div>',
7218 * <p>This may be specified to produce a different DOM structure when rendering form Fields.</p>
7219 * <p>A description of the properties within the template follows:</p><div class="mdetail-params"><ul>
7220 * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper
7221 * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt>
7222 * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt>
7223 * supplied at the container level.</div></li>
7224 * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li>
7225 * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc">
7226 * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the
7227 * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li>
7228 * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this
7229 * field (defaults to <tt>''</tt>)</div></li>
7230 * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after
7231 * the text of the label for this field (defaults to a colon <tt>':'</tt> or the
7232 * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li>
7233 * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li>
7234 * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div
7235 * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li>
7237 * <p>Also see <tt>{@link #getTemplateArgs}</tt></p>
7244 renderItem : function(c, position, target){
7245 if(c && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){
7246 var args = this.getTemplateArgs(c);
7247 if(Ext.isNumber(position)){
7248 position = target.dom.childNodes[position] || null;
7251 c.itemCt = this.fieldTpl.insertBefore(position, args, true);
7253 c.itemCt = this.fieldTpl.append(target, args, true);
7256 // Non form fields don't have getItemCt, apply it here
7257 // This will get cleaned up in onRemove
7259 getItemCt: function(){
7265 c.label = c.getItemCt().child('label.x-form-item-label');
7267 c.render('x-form-el-' + c.id);
7268 }else if(!this.isValidParent(c, target)){
7269 Ext.fly('x-form-el-' + c.id).appendChild(c.getPositionEl());
7271 if(this.trackLabels){
7273 this.onFieldHide(c);
7277 show: this.onFieldShow,
7278 hide: this.onFieldHide
7281 this.configureItem(c);
7283 Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments);
7288 * <p>Provides template arguments for rendering the fully wrapped, labeled and styled form Field.</p>
7289 * <p>This method returns an object hash containing properties used by the layout's {@link #fieldTpl}
7290 * to create a correctly wrapped, labeled and styled form Field. This may be overriden to
7291 * create custom layouts. The properties which must be returned are:</p><div class="mdetail-params"><ul>
7292 * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper
7293 * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt>
7294 * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt>
7295 * supplied at the container level.</div></li>
7296 * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li>
7297 * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc">
7298 * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the
7299 * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li>
7300 * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this
7301 * field (defaults to the field's configured fieldLabel property)</div></li>
7302 * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after
7303 * the text of the label for this field (defaults to a colon <tt>':'</tt> or the
7304 * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li>
7305 * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li>
7306 * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div
7307 * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li>
7309 * @param (Ext.form.Field} field The {@link Ext.form.Field Field} being rendered.
7310 * @return {Object} An object hash containing the properties required to render the Field.
7312 getTemplateArgs: function(field) {
7313 var noLabelSep = !field.fieldLabel || field.hideLabel;
7317 label : field.fieldLabel,
7318 itemCls : (field.itemCls || this.container.itemCls || '') + (field.hideLabel ? ' x-hide-label' : ''),
7319 clearCls : field.clearCls || 'x-form-clear-left',
7320 labelStyle : this.getLabelStyle(field.labelStyle),
7321 elementStyle : this.elementStyle || '',
7322 labelSeparator: noLabelSep ? '' : (Ext.isDefined(field.labelSeparator) ? field.labelSeparator : this.labelSeparator)
7327 adjustWidthAnchor: function(value, c){
7328 if(c.label && !this.isHide(c) && (this.container.labelAlign != 'top')){
7329 var adjust = Ext.isIE6 || (Ext.isIE && !Ext.isStrict);
7330 return value - this.labelAdjust + (adjust ? -3 : 0);
7335 adjustHeightAnchor : function(value, c){
7336 if(c.label && !this.isHide(c) && (this.container.labelAlign == 'top')){
7337 return value - c.label.getHeight();
7343 isValidParent : function(c, target){
7344 return target && this.container.getEl().contains(c.getPositionEl());
7348 * @property activeItem
7353 Ext.Container.LAYOUTS['form'] = Ext.layout.FormLayout;
7355 * @class Ext.layout.AccordionLayout
7356 * @extends Ext.layout.FitLayout
7357 * <p>This is a layout that manages multiple Panels in an expandable accordion style such that only
7358 * <b>one Panel can be expanded at any given time</b>. Each Panel has built-in support for expanding and collapsing.</p>
7359 * <p>Note: Only Ext.Panels <b>and all subclasses of Ext.Panel</b> may be used in an accordion layout Container.</p>
7360 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
7361 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
7362 * <p>Example usage:</p>
7364 var accordion = new Ext.Panel({
7365 title: 'Accordion Layout',
7368 // applied to each contained panel
7369 bodyStyle: 'padding:15px'
7372 // layout-specific configs go here
7373 titleCollapse: false,
7379 html: '<p>Panel content!</p>'
7382 html: '<p>Panel content!</p>'
7385 html: '<p>Panel content!</p>'
7390 Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, {
7392 * @cfg {Boolean} fill
7393 * True to adjust the active item's height to fill the available space in the container, false to use the
7394 * item's current height, or auto height if not explicitly set (defaults to true).
7398 * @cfg {Boolean} autoWidth
7399 * True to set each contained item's width to 'auto', false to use the item's current width (defaults to true).
7400 * Note that some components, in particular the {@link Ext.grid.GridPanel grid}, will not function properly within
7401 * layouts if they have auto width, so in such cases this config should be set to false.
7405 * @cfg {Boolean} titleCollapse
7406 * True to allow expand/collapse of each contained panel by clicking anywhere on the title bar, false to allow
7407 * expand/collapse only when the toggle tool button is clicked (defaults to true). When set to false,
7408 * {@link #hideCollapseTool} should be false also.
7410 titleCollapse : true,
7412 * @cfg {Boolean} hideCollapseTool
7413 * True to hide the contained panels' collapse/expand toggle buttons, false to display them (defaults to false).
7414 * When set to true, {@link #titleCollapse} should be true also.
7416 hideCollapseTool : false,
7418 * @cfg {Boolean} collapseFirst
7419 * True to make sure the collapse/expand toggle button always renders first (to the left of) any other tools
7420 * in the contained panels' title bars, false to render it last (defaults to false).
7422 collapseFirst : false,
7424 * @cfg {Boolean} animate
7425 * True to slide the contained panels open and closed during expand/collapse using animation, false to open and
7426 * close directly with no animation (defaults to false). Note: to defer to the specific config setting of each
7427 * contained panel for this property, set this to undefined at the layout level.
7431 * @cfg {Boolean} sequence
7432 * <b>Experimental</b>. If animate is set to true, this will result in each animation running in sequence.
7436 * @cfg {Boolean} activeOnTop
7437 * True to swap the position of each panel as it is expanded so that it becomes the first item in the container,
7438 * false to keep the panels in the rendered order. <b>This is NOT compatible with "animate:true"</b> (defaults to false).
7440 activeOnTop : false,
7444 renderItem : function(c){
7445 if(this.animate === false){
7446 c.animCollapse = false;
7448 c.collapsible = true;
7452 if(this.titleCollapse){
7453 c.titleCollapse = true;
7455 if(this.hideCollapseTool){
7456 c.hideCollapseTool = true;
7458 if(this.collapseFirst !== undefined){
7459 c.collapseFirst = this.collapseFirst;
7461 if(!this.activeItem && !c.collapsed){
7462 this.setActiveItem(c, true);
7463 }else if(this.activeItem && this.activeItem != c){
7466 Ext.layout.AccordionLayout.superclass.renderItem.apply(this, arguments);
7467 c.header.addClass('x-accordion-hd');
7468 c.on('beforeexpand', this.beforeExpand, this);
7471 onRemove: function(c){
7472 Ext.layout.AccordionLayout.superclass.onRemove.call(this, c);
7474 c.header.removeClass('x-accordion-hd');
7476 c.un('beforeexpand', this.beforeExpand, this);
7480 beforeExpand : function(p, anim){
7481 var ai = this.activeItem;
7484 delete this.activeItem;
7486 ai.collapse({callback:function(){
7487 p.expand(anim || true);
7492 ai.collapse(this.animate);
7496 if(this.activeOnTop){
7497 p.el.dom.parentNode.insertBefore(p.el.dom, p.el.dom.parentNode.firstChild);
7499 // Items have been hidden an possibly rearranged, we need to get the container size again.
7504 setItemSize : function(item, size){
7505 if(this.fill && item){
7506 var hh = 0, i, ct = this.getRenderedItems(this.container), len = ct.length, p;
7507 // Add up all the header heights
7508 for (i = 0; i < len; i++) {
7509 if((p = ct[i]) != item && !p.hidden){
7510 hh += p.header.getHeight();
7513 // Subtract the header heights from the container size
7515 // Call setSize on the container to set the correct height. For Panels, deferedHeight
7516 // will simply store this size for when the expansion is done.
7522 * Sets the active (expanded) item in the layout.
7523 * @param {String/Number} item The string component id or numeric index of the item to activate
7525 setActiveItem : function(item){
7526 this.setActive(item, true);
7530 setActive : function(item, expand){
7531 var ai = this.activeItem;
7532 item = this.container.getComponent(item);
7534 if(item.rendered && item.collapsed && expand){
7538 ai.fireEvent('deactivate', ai);
7540 this.activeItem = item;
7541 item.fireEvent('activate', item);
7546 Ext.Container.LAYOUTS.accordion = Ext.layout.AccordionLayout;
7549 Ext.layout.Accordion = Ext.layout.AccordionLayout;/**
7550 * @class Ext.layout.TableLayout
7551 * @extends Ext.layout.ContainerLayout
7552 * <p>This layout allows you to easily render content into an HTML table. The total number of columns can be
7553 * specified, and rowspan and colspan can be used to create complex layouts within the table.
7554 * This class is intended to be extended or created via the layout:'table' {@link Ext.Container#layout} config,
7555 * and should generally not need to be created directly via the new keyword.</p>
7556 * <p>Note that when creating a layout via config, the layout-specific config properties must be passed in via
7557 * the {@link Ext.Container#layoutConfig} object which will then be applied internally to the layout. In the
7558 * case of TableLayout, the only valid layout config property is {@link #columns}. However, the items added to a
7559 * TableLayout can supply the following table-specific config properties:</p>
7561 * <li><b>rowspan</b> Applied to the table cell containing the item.</li>
7562 * <li><b>colspan</b> Applied to the table cell containing the item.</li>
7563 * <li><b>cellId</b> An id applied to the table cell containing the item.</li>
7564 * <li><b>cellCls</b> A CSS class name added to the table cell containing the item.</li>
7566 * <p>The basic concept of building up a TableLayout is conceptually very similar to building up a standard
7567 * HTML table. You simply add each panel (or "cell") that you want to include along with any span attributes
7568 * specified as the special config properties of rowspan and colspan which work exactly like their HTML counterparts.
7569 * Rather than explicitly creating and nesting rows and columns as you would in HTML, you simply specify the
7570 * total column count in the layoutConfig and start adding panels in their natural order from left to right,
7571 * top to bottom. The layout will automatically figure out, based on the column count, rowspans and colspans,
7572 * how to position each panel within the table. Just like with HTML tables, your rowspans and colspans must add
7573 * up correctly in your overall layout or you'll end up with missing and/or extra cells! Example usage:</p>
7575 // This code will generate a layout table that is 3 columns by 2 rows
7576 // with some spanning included. The basic layout will be:
7577 // +--------+-----------------+
7579 // | |--------+--------|
7581 // +--------+--------+--------+
7582 var table = new Ext.Panel({
7583 title: 'Table Layout',
7586 // applied to each contained panel
7587 bodyStyle:'padding:20px'
7590 // The total column count must be specified here
7594 html: '<p>Cell A content</p>',
7597 html: '<p>Cell B content</p>',
7600 html: '<p>Cell C content</p>',
7601 cellCls: 'highlight'
7603 html: '<p>Cell D content</p>'
7608 Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, {
7610 * @cfg {Number} columns
7611 * The total number of columns to create in the table for this layout. If not specified, all Components added to
7612 * this layout will be rendered into a single row using one column per Component.
7616 monitorResize:false,
7620 targetCls: 'x-table-layout-ct',
7623 * @cfg {Object} tableAttrs
7624 * <p>An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification
7625 * used to create the layout's <tt><table></tt> element. Example:</p><pre><code>
7642 setContainer : function(ct){
7643 Ext.layout.TableLayout.superclass.setContainer.call(this, ct);
7645 this.currentRow = 0;
7646 this.currentColumn = 0;
7651 onLayout : function(ct, target){
7652 var cs = ct.items.items, len = cs.length, c, i;
7655 target.addClass('x-table-layout-ct');
7657 this.table = target.createChild(
7658 Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true);
7660 this.renderAll(ct, target);
7664 getRow : function(index){
7665 var row = this.table.tBodies[0].childNodes[index];
7667 row = document.createElement('tr');
7668 this.table.tBodies[0].appendChild(row);
7674 getNextCell : function(c){
7675 var cell = this.getNextNonSpan(this.currentColumn, this.currentRow);
7676 var curCol = this.currentColumn = cell[0], curRow = this.currentRow = cell[1];
7677 for(var rowIndex = curRow; rowIndex < curRow + (c.rowspan || 1); rowIndex++){
7678 if(!this.cells[rowIndex]){
7679 this.cells[rowIndex] = [];
7681 for(var colIndex = curCol; colIndex < curCol + (c.colspan || 1); colIndex++){
7682 this.cells[rowIndex][colIndex] = true;
7685 var td = document.createElement('td');
7689 var cls = 'x-table-layout-cell';
7691 cls += ' ' + c.cellCls;
7695 td.colSpan = c.colspan;
7698 td.rowSpan = c.rowspan;
7700 this.getRow(curRow).appendChild(td);
7705 getNextNonSpan: function(colIndex, rowIndex){
7706 var cols = this.columns;
7707 while((cols && colIndex >= cols) || (this.cells[rowIndex] && this.cells[rowIndex][colIndex])) {
7708 if(cols && colIndex >= cols){
7715 return [colIndex, rowIndex];
7719 renderItem : function(c, position, target){
7720 // Ensure we have our inner table to get cells to render into.
7722 this.table = target.createChild(
7723 Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true);
7725 if(c && !c.rendered){
7726 c.render(this.getNextCell(c));
7727 this.configureItem(c);
7728 }else if(c && !this.isValidParent(c, target)){
7729 var container = this.getNextCell(c);
7730 container.insertBefore(c.getPositionEl().dom, null);
7731 c.container = Ext.get(container);
7732 this.configureItem(c);
7737 isValidParent : function(c, target){
7738 return c.getPositionEl().up('table', 5).dom.parentNode === (target.dom || target);
7741 destroy: function(){
7743 Ext.layout.TableLayout.superclass.destroy.call(this);
7747 * @property activeItem
7752 Ext.Container.LAYOUTS['table'] = Ext.layout.TableLayout;/**
7753 * @class Ext.layout.AbsoluteLayout
7754 * @extends Ext.layout.AnchorLayout
7755 * <p>This is a layout that inherits the anchoring of <b>{@link Ext.layout.AnchorLayout}</b> and adds the
7756 * ability for x/y positioning using the standard x and y component config options.</p>
7757 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
7758 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
7759 * <p>Example usage:</p>
7761 var form = new Ext.form.FormPanel({
7762 title: 'Absolute Layout',
7765 // layout-specific configs go here
7766 extraCls: 'x-abs-layout-item',
7769 url:'save-form.php',
7770 defaultType: 'textfield',
7780 anchor:'100%' // anchor width by percentage
7790 anchor: '100%' // anchor width by percentage
7796 anchor: '100% 100%' // anchor width and height
7801 Ext.layout.AbsoluteLayout = Ext.extend(Ext.layout.AnchorLayout, {
7803 extraCls: 'x-abs-layout-item',
7807 onLayout : function(ct, target){
7809 this.paddingLeft = target.getPadding('l');
7810 this.paddingTop = target.getPadding('t');
7811 Ext.layout.AbsoluteLayout.superclass.onLayout.call(this, ct, target);
7815 adjustWidthAnchor : function(value, comp){
7816 return value ? value - comp.getPosition(true)[0] + this.paddingLeft : value;
7820 adjustHeightAnchor : function(value, comp){
7821 return value ? value - comp.getPosition(true)[1] + this.paddingTop : value;
7824 * @property activeItem
7828 Ext.Container.LAYOUTS['absolute'] = Ext.layout.AbsoluteLayout;
7830 * @class Ext.layout.BoxLayout
7831 * @extends Ext.layout.ContainerLayout
7832 * <p>Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.</p>
7834 Ext.layout.BoxLayout = Ext.extend(Ext.layout.ContainerLayout, {
7836 * @cfg {Object} defaultMargins
7837 * <p>If the individual contained items do not have a <tt>margins</tt>
7838 * property specified, the default margins from this property will be
7839 * applied to each item.</p>
7840 * <br><p>This property may be specified as an object containing margins
7841 * to apply in the format:</p><pre><code>
7844 right: (right margin),
7845 bottom: (bottom margin),
7848 * <p>This property may also be specified as a string containing
7849 * space-separated, numeric margin values. The order of the sides associated
7850 * with each value matches the way CSS processes margin values:</p>
7851 * <div class="mdetail-params"><ul>
7852 * <li>If there is only one value, it applies to all sides.</li>
7853 * <li>If there are two values, the top and bottom borders are set to the
7854 * first value and the right and left are set to the second.</li>
7855 * <li>If there are three values, the top is set to the first value, the left
7856 * and right are set to the second, and the bottom is set to the third.</li>
7857 * <li>If there are four values, they apply to the top, right, bottom, and
7858 * left, respectively.</li>
7860 * <p>Defaults to:</p><pre><code>
7861 * {top:0, right:0, bottom:0, left:0}
7864 defaultMargins : {left:0,top:0,right:0,bottom:0},
7866 * @cfg {String} padding
7867 * <p>Sets the padding to be applied to all child items managed by this layout.</p>
7868 * <p>This property must be specified as a string containing
7869 * space-separated, numeric padding values. The order of the sides associated
7870 * with each value matches the way CSS processes padding values:</p>
7871 * <div class="mdetail-params"><ul>
7872 * <li>If there is only one value, it applies to all sides.</li>
7873 * <li>If there are two values, the top and bottom borders are set to the
7874 * first value and the right and left are set to the second.</li>
7875 * <li>If there are three values, the top is set to the first value, the left
7876 * and right are set to the second, and the bottom is set to the third.</li>
7877 * <li>If there are four values, they apply to the top, right, bottom, and
7878 * left, respectively.</li>
7880 * <p>Defaults to: <code>"0"</code></p>
7883 // documented in subclasses
7887 monitorResize : true,
7890 extraCls : 'x-box-item',
7891 targetCls : 'x-box-layout-ct',
7892 innerCls : 'x-box-inner',
7894 constructor : function(config){
7895 Ext.layout.BoxLayout.superclass.constructor.call(this, config);
7897 if (Ext.isString(this.defaultMargins)) {
7898 this.defaultMargins = this.parseMargins(this.defaultMargins);
7901 var handler = this.overflowHandler;
7903 if (typeof handler == 'string') {
7909 var handlerType = 'none';
7910 if (handler && handler.type != undefined) {
7911 handlerType = handler.type;
7914 var constructor = Ext.layout.boxOverflow[handlerType];
7915 if (constructor[this.type]) {
7916 constructor = constructor[this.type];
7919 this.overflowHandler = new constructor(this, handler);
7924 * Runs the child box calculations and caches them in childBoxCache. Subclasses can used these cached values
7927 onLayout: function(container, target) {
7928 Ext.layout.BoxLayout.superclass.onLayout.call(this, container, target);
7930 var tSize = this.getLayoutTargetSize(),
7931 items = this.getVisibleItems(container),
7932 calcs = this.calculateChildBoxes(items, tSize),
7933 boxes = calcs.boxes,
7936 //invoke the overflow handler, if one is configured
7937 if (tSize.width > 0) {
7938 var handler = this.overflowHandler,
7939 method = meta.tooNarrow ? 'handleOverflow' : 'clearOverflow';
7941 var results = handler[method](calcs, tSize);
7944 if (results.targetSize) {
7945 tSize = results.targetSize;
7948 if (results.recalculate) {
7949 items = this.getVisibleItems(container);
7950 calcs = this.calculateChildBoxes(items, tSize);
7951 boxes = calcs.boxes;
7958 * @property layoutTargetLastSize
7960 * Private cache of the last measured size of the layout target. This should never be used except by
7961 * BoxLayout subclasses during their onLayout run.
7963 this.layoutTargetLastSize = tSize;
7967 * @property childBoxCache
7969 * Array of the last calculated height, width, top and left positions of each visible rendered component
7970 * within the Box layout.
7972 this.childBoxCache = calcs;
7974 this.updateInnerCtSize(tSize, calcs);
7975 this.updateChildBoxes(boxes);
7977 // Putting a box layout into an overflowed container is NOT correct and will make a second layout pass necessary.
7978 this.handleTargetOverflow(tSize, container, target);
7982 * Resizes and repositions each child component
7983 * @param {Array} boxes The box measurements
7985 updateChildBoxes: function(boxes) {
7986 for (var i = 0, length = boxes.length; i < length; i++) {
7988 comp = box.component;
7990 if (box.dirtySize) {
7991 comp.setSize(box.width, box.height);
7993 // Don't set positions to NaN
7994 if (isNaN(box.left) || isNaN(box.top)) {
7998 comp.setPosition(box.left, box.top);
8004 * Called by onRender just before the child components are sized and positioned. This resizes the innerCt
8005 * to make sure all child items fit within it. We call this before sizing the children because if our child
8006 * items are larger than the previous innerCt size the browser will insert scrollbars and then remove them
8007 * again immediately afterwards, giving a performance hit.
8008 * Subclasses should provide an implementation.
8009 * @param {Object} currentSize The current height and width of the innerCt
8010 * @param {Array} calculations The new box calculations of all items to be laid out
8012 updateInnerCtSize: function(tSize, calcs) {
8013 var align = this.align,
8014 padding = this.padding,
8015 width = tSize.width,
8016 height = tSize.height;
8018 if (this.type == 'hbox') {
8019 var innerCtWidth = width,
8020 innerCtHeight = calcs.meta.maxHeight + padding.top + padding.bottom;
8022 if (align == 'stretch') {
8023 innerCtHeight = height;
8024 } else if (align == 'middle') {
8025 innerCtHeight = Math.max(height, innerCtHeight);
8028 var innerCtHeight = height,
8029 innerCtWidth = calcs.meta.maxWidth + padding.left + padding.right;
8031 if (align == 'stretch') {
8032 innerCtWidth = width;
8033 } else if (align == 'center') {
8034 innerCtWidth = Math.max(width, innerCtWidth);
8038 this.innerCt.setSize(innerCtWidth || undefined, innerCtHeight || undefined);
8043 * This should be called after onLayout of any BoxLayout subclass. If the target's overflow is not set to 'hidden',
8044 * we need to lay out a second time because the scrollbars may have modified the height and width of the layout
8045 * target. Having a Box layout inside such a target is therefore not recommended.
8046 * @param {Object} previousTargetSize The size and height of the layout target before we just laid out
8047 * @param {Ext.Container} container The container
8048 * @param {Ext.Element} target The target element
8050 handleTargetOverflow: function(previousTargetSize, container, target) {
8051 var overflow = target.getStyle('overflow');
8053 if (overflow && overflow != 'hidden' &&!this.adjustmentPass) {
8054 var newTargetSize = this.getLayoutTargetSize();
8055 if (newTargetSize.width != previousTargetSize.width || newTargetSize.height != previousTargetSize.height){
8056 this.adjustmentPass = true;
8057 this.onLayout(container, target);
8061 delete this.adjustmentPass;
8065 isValidParent : function(c, target) {
8066 return this.innerCt && c.getPositionEl().dom.parentNode == this.innerCt.dom;
8071 * Returns all items that are both rendered and visible
8072 * @return {Array} All matching items
8074 getVisibleItems: function(ct) {
8075 var ct = ct || this.container,
8076 t = ct.getLayoutTarget(),
8077 cti = ct.items.items,
8082 for (i = 0; i < len; i++) {
8083 if((c = cti[i]).rendered && this.isValidParent(c, t) && c.hidden !== true && c.collapsed !== true && c.shouldLayout !== false){
8092 renderAll : function(ct, target) {
8093 if (!this.innerCt) {
8094 // the innerCt prevents wrapping and shuffling while the container is resizing
8095 this.innerCt = target.createChild({cls:this.innerCls});
8096 this.padding = this.parseMargins(this.padding);
8098 Ext.layout.BoxLayout.superclass.renderAll.call(this, ct, this.innerCt);
8101 getLayoutTargetSize : function() {
8102 var target = this.container.getLayoutTarget(), ret;
8105 ret = target.getViewSize();
8107 // IE in strict mode will return a width of 0 on the 1st pass of getViewSize.
8108 // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly
8110 if (Ext.isIE && Ext.isStrict && ret.width == 0){
8111 ret = target.getStyleSize();
8114 ret.width -= target.getPadding('lr');
8115 ret.height -= target.getPadding('tb');
8122 renderItem : function(c) {
8123 if(Ext.isString(c.margins)){
8124 c.margins = this.parseMargins(c.margins);
8125 }else if(!c.margins){
8126 c.margins = this.defaultMargins;
8128 Ext.layout.BoxLayout.superclass.renderItem.apply(this, arguments);
8134 destroy: function() {
8135 Ext.destroy(this.overflowHandler);
8137 Ext.layout.BoxLayout.superclass.destroy.apply(this, arguments);
8143 Ext.ns('Ext.layout.boxOverflow');
8146 * @class Ext.layout.boxOverflow.None
8148 * Base class for Box Layout overflow handlers. These specialized classes are invoked when a Box Layout
8149 * (either an HBox or a VBox) has child items that are either too wide (for HBox) or too tall (for VBox)
8150 * for its container.
8153 Ext.layout.boxOverflow.None = Ext.extend(Object, {
8154 constructor: function(layout, config) {
8155 this.layout = layout;
8157 Ext.apply(this, config || {});
8160 handleOverflow: Ext.emptyFn,
8162 clearOverflow: Ext.emptyFn
8166 Ext.layout.boxOverflow.none = Ext.layout.boxOverflow.None;
8168 * @class Ext.layout.boxOverflow.Menu
8169 * @extends Ext.layout.boxOverflow.None
8172 Ext.layout.boxOverflow.Menu = Ext.extend(Ext.layout.boxOverflow.None, {
8176 * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers,
8177 * which must always be present at the rightmost edge of the Container
8179 afterCls: 'x-strip-right',
8182 * @property noItemsMenuText
8184 * HTML fragment to render into the toolbar overflow menu if there are no items to display
8186 noItemsMenuText : '<div class="x-toolbar-no-items">(None)</div>',
8188 constructor: function(layout) {
8189 Ext.layout.boxOverflow.Menu.superclass.constructor.apply(this, arguments);
8192 * @property menuItems
8194 * Array of all items that are currently hidden and should go into the dropdown menu
8196 this.menuItems = [];
8201 * Creates the beforeCt, innerCt and afterCt elements if they have not already been created
8202 * @param {Ext.Container} container The Container attached to this Layout instance
8203 * @param {Ext.Element} target The target Element
8205 createInnerElements: function() {
8206 if (!this.afterCt) {
8207 this.afterCt = this.layout.innerCt.insertSibling({cls: this.afterCls}, 'before');
8214 clearOverflow: function(calculations, targetSize) {
8215 var newWidth = targetSize.width + (this.afterCt ? this.afterCt.getWidth() : 0),
8216 items = this.menuItems;
8220 for (var index = 0, length = items.length; index < length; index++) {
8221 items.pop().component.show();
8226 height: targetSize.height,
8235 showTrigger: function() {
8237 this.menuTrigger.show();
8243 hideTrigger: function() {
8244 if (this.menuTrigger != undefined) {
8245 this.menuTrigger.hide();
8251 * Called before the overflow menu is shown. This constructs the menu's items, caching them for as long as it can.
8253 beforeMenuShow: function(menu) {
8254 var items = this.menuItems,
8259 var needsSep = function(group, item){
8260 return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator);
8266 for (var i = 0; i < len; i++) {
8267 item = items[i].component;
8269 if (prev && (needsSep(item, prev) || needsSep(prev, item))) {
8273 this.addComponentToMenu(menu, item);
8277 // put something so the menu isn't empty if no compatible items found
8278 if (menu.items.length < 1) {
8279 menu.add(this.noItemsMenuText);
8285 * Returns a menu config for a given component. This config is used to create a menu item
8286 * to be added to the expander menu
8287 * @param {Ext.Component} component The component to create the config for
8288 * @param {Boolean} hideOnClick Passed through to the menu item
8290 createMenuConfig : function(component, hideOnClick){
8291 var config = Ext.apply({}, component.initialConfig),
8292 group = component.toggleGroup;
8294 Ext.copyTo(config, component, [
8295 'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu'
8299 text : component.overflowText || component.text,
8300 hideOnClick: hideOnClick
8303 if (group || component.enableToggle) {
8306 checked: component.pressed,
8308 checkchange: function(item, checked){
8309 component.toggle(checked);
8315 delete config.ownerCt;
8316 delete config.xtype;
8324 * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually.
8325 * @param {Ext.menu.Menu} menu The menu to add to
8326 * @param {Ext.Component} component The component to add
8328 addComponentToMenu : function(menu, component) {
8329 if (component instanceof Ext.Toolbar.Separator) {
8332 } else if (Ext.isFunction(component.isXType)) {
8333 if (component.isXType('splitbutton')) {
8334 menu.add(this.createMenuConfig(component, true));
8336 } else if (component.isXType('button')) {
8337 menu.add(this.createMenuConfig(component, !component.menu));
8339 } else if (component.isXType('buttongroup')) {
8340 component.items.each(function(item){
8341 this.addComponentToMenu(menu, item);
8349 * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as
8350 * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item
8352 clearMenu : function(){
8353 var menu = this.moreMenu;
8354 if (menu && menu.items) {
8355 menu.items.each(function(item){
8363 * Creates the overflow trigger and menu used when enableOverflow is set to true and the items
8364 * in the layout are too wide to fit in the space available
8366 createMenu: function() {
8367 if (!this.menuTrigger) {
8368 this.createInnerElements();
8373 * @type Ext.menu.Menu
8374 * The expand menu - holds items for every item that cannot be shown
8375 * because the container is currently not large enough.
8377 this.menu = new Ext.menu.Menu({
8378 ownerCt : this.layout.container,
8381 beforeshow: this.beforeMenuShow
8387 * @property menuTrigger
8389 * The expand button which triggers the overflow menu to be shown
8391 this.menuTrigger = new Ext.Button({
8392 iconCls : 'x-toolbar-more-icon',
8393 cls : 'x-toolbar-more',
8395 renderTo: this.afterCt
8403 destroy: function() {
8404 Ext.destroy(this.menu, this.menuTrigger);
8408 Ext.layout.boxOverflow.menu = Ext.layout.boxOverflow.Menu;
8412 * @class Ext.layout.boxOverflow.HorizontalMenu
8413 * @extends Ext.layout.boxOverflow.Menu
8416 Ext.layout.boxOverflow.HorizontalMenu = Ext.extend(Ext.layout.boxOverflow.Menu, {
8418 constructor: function() {
8419 Ext.layout.boxOverflow.HorizontalMenu.superclass.constructor.apply(this, arguments);
8423 origFunction = layout.calculateChildBoxes;
8425 layout.calculateChildBoxes = function(visibleItems, targetSize) {
8426 var calcs = origFunction.apply(layout, arguments),
8428 items = me.menuItems;
8430 //calculate the width of the items currently hidden solely because there is not enough space
8432 var hiddenWidth = 0;
8433 for (var index = 0, length = items.length; index < length; index++) {
8434 hiddenWidth += items[index].width;
8437 meta.minimumWidth += hiddenWidth;
8438 meta.tooNarrow = meta.minimumWidth > targetSize.width;
8444 handleOverflow: function(calculations, targetSize) {
8447 var newWidth = targetSize.width - this.afterCt.getWidth(),
8448 boxes = calculations.boxes,
8450 recalculate = false;
8452 //calculate the width of all visible items and any spare width
8453 for (var index = 0, length = boxes.length; index < length; index++) {
8454 usedWidth += boxes[index].width;
8457 var spareWidth = newWidth - usedWidth,
8460 //see if we can re-show any of the hidden components
8461 for (var index = 0, length = this.menuItems.length; index < length; index++) {
8462 var hidden = this.menuItems[index],
8463 comp = hidden.component,
8464 width = hidden.width;
8466 if (width < spareWidth) {
8469 spareWidth -= width;
8478 this.menuItems = this.menuItems.slice(showCount);
8480 for (var i = boxes.length - 1; i >= 0; i--) {
8481 var item = boxes[i].component,
8482 right = boxes[i].left + boxes[i].width;
8484 if (right >= newWidth) {
8485 this.menuItems.unshift({
8487 width : boxes[i].width
8497 if (this.menuItems.length == 0) {
8503 height: targetSize.height,
8506 recalculate: recalculate
8511 Ext.layout.boxOverflow.menu.hbox = Ext.layout.boxOverflow.HorizontalMenu;/**
8512 * @class Ext.layout.boxOverflow.Scroller
8513 * @extends Ext.layout.boxOverflow.None
8516 Ext.layout.boxOverflow.Scroller = Ext.extend(Ext.layout.boxOverflow.None, {
8518 * @cfg animateScroll
8520 * True to animate the scrolling of items within the layout (defaults to true, ignored if enableScroll is false)
8522 animateScroll: true,
8525 * @cfg scrollIncrement
8527 * The number of pixels to scroll by on scroller click (defaults to 100)
8529 scrollIncrement: 100,
8532 * @cfg wheelIncrement
8534 * The number of pixels to increment on mouse wheel scrolling (defaults to <tt>3</tt>).
8539 * @cfg scrollRepeatInterval
8541 * Number of milliseconds between each scroll while a scroller button is held down (defaults to 400)
8543 scrollRepeatInterval: 400,
8546 * @cfg scrollDuration
8548 * Number of seconds that each scroll animation lasts (defaults to 0.4)
8550 scrollDuration: 0.4,
8555 * CSS class added to the beforeCt element. This is the element that holds any special items such as scrollers,
8556 * which must always be present at the leftmost edge of the Container
8558 beforeCls: 'x-strip-left',
8563 * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers,
8564 * which must always be present at the rightmost edge of the Container
8566 afterCls: 'x-strip-right',
8571 * CSS class added to both scroller elements if enableScroll is used
8573 scrollerCls: 'x-strip-scroller',
8576 * @cfg beforeScrollerCls
8578 * CSS class added to the left scroller element if enableScroll is used
8580 beforeScrollerCls: 'x-strip-scroller-left',
8583 * @cfg afterScrollerCls
8585 * CSS class added to the right scroller element if enableScroll is used
8587 afterScrollerCls: 'x-strip-scroller-right',
8591 * Sets up an listener to scroll on the layout's innerCt mousewheel event
8593 createWheelListener: function() {
8594 this.layout.innerCt.on({
8596 mousewheel: function(e) {
8599 this.scrollBy(e.getWheelDelta() * this.wheelIncrement * -1, false);
8606 * Most of the heavy lifting is done in the subclasses
8608 handleOverflow: function(calculations, targetSize) {
8609 this.createInnerElements();
8610 this.showScrollers();
8616 clearOverflow: function() {
8617 this.hideScrollers();
8622 * Shows the scroller elements in the beforeCt and afterCt. Creates the scrollers first if they are not already
8625 showScrollers: function() {
8626 this.createScrollers();
8628 this.beforeScroller.show();
8629 this.afterScroller.show();
8631 this.updateScrollButtons();
8636 * Hides the scroller elements in the beforeCt and afterCt
8638 hideScrollers: function() {
8639 if (this.beforeScroller != undefined) {
8640 this.beforeScroller.hide();
8641 this.afterScroller.hide();
8647 * Creates the clickable scroller elements and places them into the beforeCt and afterCt
8649 createScrollers: function() {
8650 if (!this.beforeScroller && !this.afterScroller) {
8651 var before = this.beforeCt.createChild({
8652 cls: String.format("{0} {1} ", this.scrollerCls, this.beforeScrollerCls)
8655 var after = this.afterCt.createChild({
8656 cls: String.format("{0} {1}", this.scrollerCls, this.afterScrollerCls)
8659 before.addClassOnOver(this.beforeScrollerCls + '-hover');
8660 after.addClassOnOver(this.afterScrollerCls + '-hover');
8662 before.setVisibilityMode(Ext.Element.DISPLAY);
8663 after.setVisibilityMode(Ext.Element.DISPLAY);
8665 this.beforeRepeater = new Ext.util.ClickRepeater(before, {
8666 interval: this.scrollRepeatInterval,
8667 handler : this.scrollLeft,
8671 this.afterRepeater = new Ext.util.ClickRepeater(after, {
8672 interval: this.scrollRepeatInterval,
8673 handler : this.scrollRight,
8678 * @property beforeScroller
8680 * The left scroller element. Only created when needed.
8682 this.beforeScroller = before;
8685 * @property afterScroller
8687 * The left scroller element. Only created when needed.
8689 this.afterScroller = after;
8696 destroy: function() {
8697 Ext.destroy(this.beforeScroller, this.afterScroller, this.beforeRepeater, this.afterRepeater, this.beforeCt, this.afterCt);
8702 * Scrolls left or right by the number of pixels specified
8703 * @param {Number} delta Number of pixels to scroll to the right by. Use a negative number to scroll left
8705 scrollBy: function(delta, animate) {
8706 this.scrollTo(this.getScrollPosition() + delta, animate);
8711 * Normalizes an item reference, string id or numerical index into a reference to the item
8712 * @param {Ext.Component|String|Number} item The item reference, id or index
8713 * @return {Ext.Component} The item
8715 getItem: function(item) {
8716 if (Ext.isString(item)) {
8717 item = Ext.getCmp(item);
8718 } else if (Ext.isNumber(item)) {
8719 item = this.items[item];
8727 * @return {Object} Object passed to scrollTo when scrolling
8729 getScrollAnim: function() {
8731 duration: this.scrollDuration,
8732 callback: this.updateScrollButtons,
8739 * Enables or disables each scroller button based on the current scroll position
8741 updateScrollButtons: function() {
8742 if (this.beforeScroller == undefined || this.afterScroller == undefined) {
8746 var beforeMeth = this.atExtremeBefore() ? 'addClass' : 'removeClass',
8747 afterMeth = this.atExtremeAfter() ? 'addClass' : 'removeClass',
8748 beforeCls = this.beforeScrollerCls + '-disabled',
8749 afterCls = this.afterScrollerCls + '-disabled';
8751 this.beforeScroller[beforeMeth](beforeCls);
8752 this.afterScroller[afterMeth](afterCls);
8753 this.scrolling = false;
8758 * Returns true if the innerCt scroll is already at its left-most point
8759 * @return {Boolean} True if already at furthest left point
8761 atExtremeBefore: function() {
8762 return this.getScrollPosition() === 0;
8767 * Scrolls to the left by the configured amount
8769 scrollLeft: function(animate) {
8770 this.scrollBy(-this.scrollIncrement, animate);
8775 * Scrolls to the right by the configured amount
8777 scrollRight: function(animate) {
8778 this.scrollBy(this.scrollIncrement, animate);
8782 * Scrolls to the given component.
8783 * @param {String|Number|Ext.Component} item The item to scroll to. Can be a numerical index, component id
8784 * or a reference to the component itself.
8785 * @param {Boolean} animate True to animate the scrolling
8787 scrollToItem: function(item, animate) {
8788 item = this.getItem(item);
8790 if (item != undefined) {
8791 var visibility = this.getItemVisibility(item);
8793 if (!visibility.fullyVisible) {
8794 var box = item.getBox(true, true),
8797 if (visibility.hiddenRight) {
8798 newX -= (this.layout.innerCt.getWidth() - box.width);
8801 this.scrollTo(newX, animate);
8808 * For a given item in the container, return an object with information on whether the item is visible
8809 * with the current innerCt scroll value.
8810 * @param {Ext.Component} item The item
8811 * @return {Object} Values for fullyVisible, hiddenLeft and hiddenRight
8813 getItemVisibility: function(item) {
8814 var box = this.getItem(item).getBox(true, true),
8816 itemRight = box.x + box.width,
8817 scrollLeft = this.getScrollPosition(),
8818 scrollRight = this.layout.innerCt.getWidth() + scrollLeft;
8821 hiddenLeft : itemLeft < scrollLeft,
8822 hiddenRight : itemRight > scrollRight,
8823 fullyVisible: itemLeft > scrollLeft && itemRight < scrollRight
8828 Ext.layout.boxOverflow.scroller = Ext.layout.boxOverflow.Scroller;
8832 * @class Ext.layout.boxOverflow.VerticalScroller
\r
8833 * @extends Ext.layout.boxOverflow.Scroller
\r
8836 Ext.layout.boxOverflow.VerticalScroller = Ext.extend(Ext.layout.boxOverflow.Scroller, {
8837 scrollIncrement: 75,
8840 handleOverflow: function(calculations, targetSize) {
8841 Ext.layout.boxOverflow.VerticalScroller.superclass.handleOverflow.apply(this, arguments);
8845 height: targetSize.height - (this.beforeCt.getHeight() + this.afterCt.getHeight()),
8846 width : targetSize.width
8853 * Creates the beforeCt and afterCt elements if they have not already been created
8855 createInnerElements: function() {
8856 var target = this.layout.innerCt;
8858 //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of
8859 //special items such as scrollers or dropdown menu triggers
8860 if (!this.beforeCt) {
8861 this.beforeCt = target.insertSibling({cls: this.beforeCls}, 'before');
8862 this.afterCt = target.insertSibling({cls: this.afterCls}, 'after');
8864 this.createWheelListener();
8870 * Scrolls to the given position. Performs bounds checking.
8871 * @param {Number} position The position to scroll to. This is constrained.
8872 * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll
8874 scrollTo: function(position, animate) {
8875 var oldPosition = this.getScrollPosition(),
8876 newPosition = position.constrain(0, this.getMaxScrollBottom());
8878 if (newPosition != oldPosition && !this.scrolling) {
8879 if (animate == undefined) {
8880 animate = this.animateScroll;
8883 this.layout.innerCt.scrollTo('top', newPosition, animate ? this.getScrollAnim() : false);
8886 this.scrolling = true;
8888 this.scrolling = false;
8889 this.updateScrollButtons();
8895 * Returns the current scroll position of the innerCt element
8896 * @return {Number} The current scroll position
8898 getScrollPosition: function(){
8899 return parseInt(this.layout.innerCt.dom.scrollTop, 10) || 0;
8904 * Returns the maximum value we can scrollTo
8905 * @return {Number} The max scroll value
8907 getMaxScrollBottom: function() {
8908 return this.layout.innerCt.dom.scrollHeight - this.layout.innerCt.getHeight();
8913 * Returns true if the innerCt scroll is already at its right-most point
8914 * @return {Boolean} True if already at furthest right point
8916 atExtremeAfter: function() {
8917 return this.getScrollPosition() >= this.getMaxScrollBottom();
8921 Ext.layout.boxOverflow.scroller.vbox = Ext.layout.boxOverflow.VerticalScroller;
8925 * @class Ext.layout.boxOverflow.HorizontalScroller
8926 * @extends Ext.layout.boxOverflow.Scroller
8929 Ext.layout.boxOverflow.HorizontalScroller = Ext.extend(Ext.layout.boxOverflow.Scroller, {
8930 handleOverflow: function(calculations, targetSize) {
8931 Ext.layout.boxOverflow.HorizontalScroller.superclass.handleOverflow.apply(this, arguments);
8935 height: targetSize.height,
8936 width : targetSize.width - (this.beforeCt.getWidth() + this.afterCt.getWidth())
8943 * Creates the beforeCt and afterCt elements if they have not already been created
8945 createInnerElements: function() {
8946 var target = this.layout.innerCt;
8948 //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of
8949 //special items such as scrollers or dropdown menu triggers
8950 if (!this.beforeCt) {
8951 this.afterCt = target.insertSibling({cls: this.afterCls}, 'before');
8952 this.beforeCt = target.insertSibling({cls: this.beforeCls}, 'before');
8954 this.createWheelListener();
8960 * Scrolls to the given position. Performs bounds checking.
8961 * @param {Number} position The position to scroll to. This is constrained.
8962 * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll
8964 scrollTo: function(position, animate) {
8965 var oldPosition = this.getScrollPosition(),
8966 newPosition = position.constrain(0, this.getMaxScrollRight());
8968 if (newPosition != oldPosition && !this.scrolling) {
8969 if (animate == undefined) {
8970 animate = this.animateScroll;
8973 this.layout.innerCt.scrollTo('left', newPosition, animate ? this.getScrollAnim() : false);
8976 this.scrolling = true;
8978 this.scrolling = false;
8979 this.updateScrollButtons();
8985 * Returns the current scroll position of the innerCt element
8986 * @return {Number} The current scroll position
8988 getScrollPosition: function(){
8989 return parseInt(this.layout.innerCt.dom.scrollLeft, 10) || 0;
8994 * Returns the maximum value we can scrollTo
8995 * @return {Number} The max scroll value
8997 getMaxScrollRight: function() {
8998 return this.layout.innerCt.dom.scrollWidth - this.layout.innerCt.getWidth();
9003 * Returns true if the innerCt scroll is already at its right-most point
9004 * @return {Boolean} True if already at furthest right point
9006 atExtremeAfter: function() {
9007 return this.getScrollPosition() >= this.getMaxScrollRight();
9011 Ext.layout.boxOverflow.scroller.hbox = Ext.layout.boxOverflow.HorizontalScroller;/**
9012 * @class Ext.layout.HBoxLayout
9013 * @extends Ext.layout.BoxLayout
9014 * <p>A layout that arranges items horizontally across a Container. This layout optionally divides available horizontal
9015 * space between child items containing a numeric <code>flex</code> configuration.</p>
9016 * This layout may also be used to set the heights of child items by configuring it with the {@link #align} option.
9018 Ext.layout.HBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
9020 * @cfg {String} align
9021 * Controls how the child items of the container are aligned. Acceptable configuration values for this
9023 * <div class="mdetail-params"><ul>
9024 * <li><b><tt>top</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned vertically
9025 * at the <b>top</b> of the container</div></li>
9026 * <li><b><tt>middle</tt></b> : <div class="sub-desc">child items are aligned vertically in the
9027 * <b>middle</b> of the container</div></li>
9028 * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched vertically to fill
9029 * the height of the container</div></li>
9030 * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched vertically to
9031 * the height of the largest item.</div></li>
9033 align: 'top', // top, middle, stretch, strechmax
9038 * @cfg {String} pack
9039 * Controls how the child items of the container are packed together. Acceptable configuration values
9040 * for this property are:
9041 * <div class="mdetail-params"><ul>
9042 * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
9043 * <b>left</b> side of container</div></li>
9044 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
9045 * <b>mid-width</b> of container</div></li>
9046 * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>right</b>
9047 * side of container</div></li>
9051 * @cfg {Number} flex
9052 * This configuation option is to be applied to <b>child <tt>items</tt></b> of the container managed
9053 * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>horizontally</b>
9054 * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
9055 * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
9056 * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
9061 * Calculates the size and positioning of each item in the HBox. This iterates over all of the rendered,
9062 * visible items and returns a height, width, top and left for each, as well as a reference to each. Also
9063 * returns meta data such as maxHeight which are useful when resizing layout wrappers such as this.innerCt.
9064 * @param {Array} visibleItems The array of all rendered, visible items to be calculated for
9065 * @param {Object} targetSize Object containing target size and height
9066 * @return {Object} Object containing box measurements for each child, plus meta data
9068 calculateChildBoxes: function(visibleItems, targetSize) {
9069 var visibleCount = visibleItems.length,
9071 padding = this.padding,
9072 topOffset = padding.top,
9073 leftOffset = padding.left,
9074 paddingVert = topOffset + padding.bottom,
9075 paddingHoriz = leftOffset + padding.right,
9077 width = targetSize.width - this.scrollOffset,
9078 height = targetSize.height,
9079 availHeight = Math.max(0, height - paddingVert),
9081 isStart = this.pack == 'start',
9082 isCenter = this.pack == 'center',
9083 isEnd = this.pack == 'end',
9091 //used to cache the calculated size and position values for each child item
9094 //used in the for loops below, just declared here for brevity
9095 child, childWidth, childHeight, childSize, childMargins, canLayout, i, calcs, flexedWidth,
9096 horizMargins, vertMargins, stretchHeight;
9098 //gather the total flex of all flexed items and the width taken up by fixed width items
9099 for (i = 0; i < visibleCount; i++) {
9100 child = visibleItems[i];
9101 childHeight = child.height;
9102 childWidth = child.width;
9103 canLayout = !child.hasLayout && typeof child.doLayout == 'function';
9105 // Static width (numeric) requires no calcs
9106 if (typeof childWidth != 'number') {
9108 // flex and not 'auto' width
9109 if (child.flex && !childWidth) {
9110 totalFlex += child.flex;
9112 // Not flexed or 'auto' width or undefined width
9114 //Render and layout sub-containers without a flex or width defined, as otherwise we
9115 //don't know how wide the sub-container should be and cannot calculate flexed widths
9116 if (!childWidth && canLayout) {
9120 childSize = child.getSize();
9121 childWidth = childSize.width;
9122 childHeight = childSize.height;
9126 childMargins = child.margins;
9127 horizMargins = childMargins.left + childMargins.right;
9129 nonFlexWidth += horizMargins + (childWidth || 0);
9130 desiredWidth += horizMargins + (child.flex ? child.minWidth || 0 : childWidth);
9131 minimumWidth += horizMargins + (child.minWidth || childWidth || 0);
9133 // Max height for align - force layout of non-laid out subcontainers without a numeric height
9134 if (typeof childHeight != 'number') {
9138 childHeight = child.getHeight();
9141 maxHeight = Math.max(maxHeight, childHeight + childMargins.top + childMargins.bottom);
9143 //cache the size of each child component. Don't set height or width to 0, keep undefined instead
9146 height : childHeight || undefined,
9147 width : childWidth || undefined
9151 var shortfall = desiredWidth - width,
9152 tooNarrow = minimumWidth > width;
9154 //the width available to the flexed items
9155 var availableWidth = Math.max(0, width - nonFlexWidth - paddingHoriz);
9158 for (i = 0; i < visibleCount; i++) {
9159 boxes[i].width = visibleItems[i].minWidth || visibleItems[i].width || boxes[i].width;
9162 //all flexed items should be sized to their minimum width, other items should be shrunk down until
9163 //the shortfall has been accounted for
9164 if (shortfall > 0) {
9168 * When we have a shortfall but are not tooNarrow, we need to shrink the width of each non-flexed item.
9169 * Flexed items are immediately reduced to their minWidth and anything already at minWidth is ignored.
9170 * The remaining items are collected into the minWidths array, which is later used to distribute the shortfall.
9172 for (var index = 0, length = visibleCount; index < length; index++) {
9173 var item = visibleItems[index],
9174 minWidth = item.minWidth || 0;
9176 //shrink each non-flex tab by an equal amount to make them all fit. Flexed items are all
9177 //shrunk to their minWidth because they're flexible and should be the first to lose width
9179 boxes[index].width = minWidth;
9182 minWidth : minWidth,
9183 available: boxes[index].width - minWidth,
9189 //sort by descending amount of width remaining before minWidth is reached
9190 minWidths.sort(function(a, b) {
9191 return a.available > b.available ? 1 : -1;
9195 * Distribute the shortfall (difference between total desired with of all items and actual width available)
9196 * between the non-flexed items. We try to distribute the shortfall evenly, but apply it to items with the
9197 * smallest difference between their width and minWidth first, so that if reducing the width by the average
9198 * amount would make that item less than its minWidth, we carry the remainder over to the next item.
9200 for (var i = 0, length = minWidths.length; i < length; i++) {
9201 var itemIndex = minWidths[i].index;
9203 if (itemIndex == undefined) {
9207 var item = visibleItems[itemIndex],
9208 box = boxes[itemIndex],
9209 oldWidth = box.width,
9210 minWidth = item.minWidth,
9211 newWidth = Math.max(minWidth, oldWidth - Math.ceil(shortfall / (length - i))),
9212 reduction = oldWidth - newWidth;
9214 boxes[itemIndex].width = newWidth;
9215 shortfall -= reduction;
9218 //temporary variables used in the flex width calculations below
9219 var remainingWidth = availableWidth,
9220 remainingFlex = totalFlex;
9222 //calculate the widths of each flexed item
9223 for (i = 0; i < visibleCount; i++) {
9224 child = visibleItems[i];
9227 childMargins = child.margins;
9228 vertMargins = childMargins.top + childMargins.bottom;
9230 if (isStart && child.flex && !child.width) {
9231 flexedWidth = Math.ceil((child.flex / remainingFlex) * remainingWidth);
9232 remainingWidth -= flexedWidth;
9233 remainingFlex -= child.flex;
9235 calcs.width = flexedWidth;
9236 calcs.dirtySize = true;
9243 leftOffset += availableWidth / 2;
9245 leftOffset += availableWidth;
9248 //finally, calculate the left and top position of each item
9249 for (i = 0; i < visibleCount; i++) {
9250 child = visibleItems[i];
9253 childMargins = child.margins;
9254 leftOffset += childMargins.left;
9255 vertMargins = childMargins.top + childMargins.bottom;
9257 calcs.left = leftOffset;
9258 calcs.top = topOffset + childMargins.top;
9260 switch (this.align) {
9262 stretchHeight = availHeight - vertMargins;
9263 calcs.height = stretchHeight.constrain(child.minHeight || 0, child.maxHeight || 1000000);
9264 calcs.dirtySize = true;
9267 stretchHeight = maxHeight - vertMargins;
9268 calcs.height = stretchHeight.constrain(child.minHeight || 0, child.maxHeight || 1000000);
9269 calcs.dirtySize = true;
9272 var diff = availHeight - calcs.height - vertMargins;
9274 calcs.top = topOffset + vertMargins + (diff / 2);
9278 leftOffset += calcs.width + childMargins.right;
9284 maxHeight : maxHeight,
9285 nonFlexWidth: nonFlexWidth,
9286 desiredWidth: desiredWidth,
9287 minimumWidth: minimumWidth,
9288 shortfall : desiredWidth - width,
9289 tooNarrow : tooNarrow
9295 Ext.Container.LAYOUTS.hbox = Ext.layout.HBoxLayout;/**
9296 * @class Ext.layout.VBoxLayout
9297 * @extends Ext.layout.BoxLayout
9298 * <p>A layout that arranges items vertically down a Container. This layout optionally divides available vertical
9299 * space between child items containing a numeric <code>flex</code> configuration.</p>
9300 * This layout may also be used to set the widths of child items by configuring it with the {@link #align} option.
9302 Ext.layout.VBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
9304 * @cfg {String} align
9305 * Controls how the child items of the container are aligned. Acceptable configuration values for this
9307 * <div class="mdetail-params"><ul>
9308 * <li><b><tt>left</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned horizontally
9309 * at the <b>left</b> side of the container</div></li>
9310 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are aligned horizontally at the
9311 * <b>mid-width</b> of the container</div></li>
9312 * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched horizontally to fill
9313 * the width of the container</div></li>
9314 * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched horizontally to
9315 * the size of the largest item.</div></li>
9318 align : 'left', // left, center, stretch, strechmax
9322 * @cfg {String} pack
9323 * Controls how the child items of the container are packed together. Acceptable configuration values
9324 * for this property are:
9325 * <div class="mdetail-params"><ul>
9326 * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
9327 * <b>top</b> side of container</div></li>
9328 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
9329 * <b>mid-height</b> of container</div></li>
9330 * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>bottom</b>
9331 * side of container</div></li>
9336 * @cfg {Number} flex
9337 * This configuation option is to be applied to <b>child <tt>items</tt></b> of the container managed
9338 * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>vertically</b>
9339 * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
9340 * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
9341 * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
9346 * Calculates the size and positioning of each item in the VBox. This iterates over all of the rendered,
9347 * visible items and returns a height, width, top and left for each, as well as a reference to each. Also
9348 * returns meta data such as maxHeight which are useful when resizing layout wrappers such as this.innerCt.
9349 * @param {Array} visibleItems The array of all rendered, visible items to be calculated for
9350 * @param {Object} targetSize Object containing target size and height
9351 * @return {Object} Object containing box measurements for each child, plus meta data
9353 calculateChildBoxes: function(visibleItems, targetSize) {
9354 var visibleCount = visibleItems.length,
9356 padding = this.padding,
9357 topOffset = padding.top,
9358 leftOffset = padding.left,
9359 paddingVert = topOffset + padding.bottom,
9360 paddingHoriz = leftOffset + padding.right,
9362 width = targetSize.width - this.scrollOffset,
9363 height = targetSize.height,
9364 availWidth = Math.max(0, width - paddingHoriz),
9366 isStart = this.pack == 'start',
9367 isCenter = this.pack == 'center',
9368 isEnd = this.pack == 'end',
9376 //used to cache the calculated size and position values for each child item
9379 //used in the for loops below, just declared here for brevity
9380 child, childWidth, childHeight, childSize, childMargins, canLayout, i, calcs, flexedWidth,
9381 horizMargins, vertMargins, stretchWidth;
9383 //gather the total flex of all flexed items and the width taken up by fixed width items
9384 for (i = 0; i < visibleCount; i++) {
9385 child = visibleItems[i];
9386 childHeight = child.height;
9387 childWidth = child.width;
9388 canLayout = !child.hasLayout && typeof child.doLayout == 'function';
9390 // Static height (numeric) requires no calcs
9391 if (typeof childHeight != 'number') {
9393 // flex and not 'auto' height
9394 if (child.flex && !childHeight) {
9395 totalFlex += child.flex;
9397 // Not flexed or 'auto' height or undefined height
9399 //Render and layout sub-containers without a flex or width defined, as otherwise we
9400 //don't know how wide the sub-container should be and cannot calculate flexed widths
9401 if (!childHeight && canLayout) {
9405 childSize = child.getSize();
9406 childWidth = childSize.width;
9407 childHeight = childSize.height;
9411 childMargins = child.margins;
9412 vertMargins = childMargins.top + childMargins.bottom;
9414 nonFlexHeight += vertMargins + (childHeight || 0);
9415 desiredHeight += vertMargins + (child.flex ? child.minHeight || 0 : childHeight);
9416 minimumHeight += vertMargins + (child.minHeight || childHeight || 0);
9418 // Max width for align - force layout of non-layed out subcontainers without a numeric width
9419 if (typeof childWidth != 'number') {
9423 childWidth = child.getWidth();
9426 maxWidth = Math.max(maxWidth, childWidth + childMargins.left + childMargins.right);
9428 //cache the size of each child component
9431 height : childHeight || undefined,
9432 width : childWidth || undefined
9436 var shortfall = desiredHeight - height,
9437 tooNarrow = minimumHeight > height;
9439 //the height available to the flexed items
9440 var availableHeight = Math.max(0, (height - nonFlexHeight - paddingVert));
9443 for (i = 0, length = visibleCount; i < length; i++) {
9444 boxes[i].height = visibleItems[i].minHeight || visibleItems[i].height || boxes[i].height;
9447 //all flexed items should be sized to their minimum width, other items should be shrunk down until
9448 //the shortfall has been accounted for
9449 if (shortfall > 0) {
9450 var minHeights = [];
9453 * When we have a shortfall but are not tooNarrow, we need to shrink the height of each non-flexed item.
9454 * Flexed items are immediately reduced to their minHeight and anything already at minHeight is ignored.
9455 * The remaining items are collected into the minHeights array, which is later used to distribute the shortfall.
9457 for (var index = 0, length = visibleCount; index < length; index++) {
9458 var item = visibleItems[index],
9459 minHeight = item.minHeight || 0;
9461 //shrink each non-flex tab by an equal amount to make them all fit. Flexed items are all
9462 //shrunk to their minHeight because they're flexible and should be the first to lose height
9464 boxes[index].height = minHeight;
9467 minHeight: minHeight,
9468 available: boxes[index].height - minHeight,
9474 //sort by descending minHeight value
9475 minHeights.sort(function(a, b) {
9476 return a.available > b.available ? 1 : -1;
9480 * Distribute the shortfall (difference between total desired with of all items and actual height available)
9481 * between the non-flexed items. We try to distribute the shortfall evenly, but apply it to items with the
9482 * smallest difference between their height and minHeight first, so that if reducing the height by the average
9483 * amount would make that item less than its minHeight, we carry the remainder over to the next item.
9485 for (var i = 0, length = minHeights.length; i < length; i++) {
9486 var itemIndex = minHeights[i].index;
9488 if (itemIndex == undefined) {
9492 var item = visibleItems[itemIndex],
9493 box = boxes[itemIndex],
9494 oldHeight = box.height,
9495 minHeight = item.minHeight,
9496 newHeight = Math.max(minHeight, oldHeight - Math.ceil(shortfall / (length - i))),
9497 reduction = oldHeight - newHeight;
9499 boxes[itemIndex].height = newHeight;
9500 shortfall -= reduction;
9503 //temporary variables used in the flex height calculations below
9504 var remainingHeight = availableHeight,
9505 remainingFlex = totalFlex;
9507 //calculate the height of each flexed item
9508 for (i = 0; i < visibleCount; i++) {
9509 child = visibleItems[i];
9512 childMargins = child.margins;
9513 horizMargins = childMargins.left + childMargins.right;
9515 if (isStart && child.flex && !child.height) {
9516 flexedHeight = Math.ceil((child.flex / remainingFlex) * remainingHeight);
9517 remainingHeight -= flexedHeight;
9518 remainingFlex -= child.flex;
9520 calcs.height = flexedHeight;
9521 calcs.dirtySize = true;
9528 topOffset += availableHeight / 2;
9530 topOffset += availableHeight;
9533 //finally, calculate the left and top position of each item
9534 for (i = 0; i < visibleCount; i++) {
9535 child = visibleItems[i];
9538 childMargins = child.margins;
9539 topOffset += childMargins.top;
9540 horizMargins = childMargins.left + childMargins.right;
9543 calcs.left = leftOffset + childMargins.left;
9544 calcs.top = topOffset;
9546 switch (this.align) {
9548 stretchWidth = availWidth - horizMargins;
9549 calcs.width = stretchWidth.constrain(child.minWidth || 0, child.maxWidth || 1000000);
9550 calcs.dirtySize = true;
9553 stretchWidth = maxWidth - horizMargins;
9554 calcs.width = stretchWidth.constrain(child.minWidth || 0, child.maxWidth || 1000000);
9555 calcs.dirtySize = true;
9558 var diff = availWidth - calcs.width - horizMargins;
9560 calcs.left = leftOffset + horizMargins + (diff / 2);
9564 topOffset += calcs.height + childMargins.bottom;
9570 maxWidth : maxWidth,
9571 nonFlexHeight: nonFlexHeight,
9572 desiredHeight: desiredHeight,
9573 minimumHeight: minimumHeight,
9574 shortfall : desiredHeight - height,
9575 tooNarrow : tooNarrow
9581 Ext.Container.LAYOUTS.vbox = Ext.layout.VBoxLayout;
9583 * @class Ext.layout.ToolbarLayout
9584 * @extends Ext.layout.ContainerLayout
9585 * Layout manager used by Ext.Toolbar. This is highly specialised for use by Toolbars and would not
9586 * usually be used by any other class.
9588 Ext.layout.ToolbarLayout = Ext.extend(Ext.layout.ContainerLayout, {
9589 monitorResize : true,
9594 * @property triggerWidth
9596 * The width allocated for the menu trigger at the extreme right end of the Toolbar
9601 * @property noItemsMenuText
9603 * HTML fragment to render into the toolbar overflow menu if there are no items to display
9605 noItemsMenuText : '<div class="x-toolbar-no-items">(None)</div>',
9609 * @property lastOverflow
9611 * Used internally to record whether the last layout caused an overflow or not
9613 lastOverflow: false,
9617 * @property tableHTML
9619 * String used to build the HTML injected to support the Toolbar's layout. The align property is
9620 * injected into this string inside the td.x-toolbar-left element during onLayout.
9623 '<table cellspacing="0" class="x-toolbar-ct">',
9626 '<td class="x-toolbar-left" align="{0}">',
9627 '<table cellspacing="0">',
9629 '<tr class="x-toolbar-left-row"></tr>',
9633 '<td class="x-toolbar-right" align="right">',
9634 '<table cellspacing="0" class="x-toolbar-right-ct">',
9638 '<table cellspacing="0">',
9640 '<tr class="x-toolbar-right-row"></tr>',
9645 '<table cellspacing="0">',
9647 '<tr class="x-toolbar-extras-row"></tr>',
9662 * Create the wrapping Toolbar HTML and render/move all the items into the correct places
9664 onLayout : function(ct, target) {
9665 //render the Toolbar <table> HTML if it's not already present
9667 var align = ct.buttonAlign == 'center' ? 'center' : 'left';
9669 target.addClass('x-toolbar-layout-ct');
9670 target.insertHtml('beforeEnd', String.format(this.tableHTML, align));
9672 this.leftTr = target.child('tr.x-toolbar-left-row', true);
9673 this.rightTr = target.child('tr.x-toolbar-right-row', true);
9674 this.extrasTr = target.child('tr.x-toolbar-extras-row', true);
9676 if (this.hiddenItem == undefined) {
9678 * @property hiddenItems
9680 * Holds all items that are currently hidden due to there not being enough space to render them
9681 * These items will appear on the expand menu.
9683 this.hiddenItems = [];
9687 var side = ct.buttonAlign == 'right' ? this.rightTr : this.leftTr,
9688 items = ct.items.items,
9691 //render each item if not already rendered, place it into the correct (left or right) target
9692 for (var i = 0, len = items.length, c; i < len; i++, position++) {
9696 side = this.rightTr;
9698 } else if (!c.rendered) {
9699 c.render(this.insertCell(c, side, position));
9700 this.configureItem(c);
9702 if (!c.xtbHidden && !this.isValidParent(c, side.childNodes[position])) {
9703 var td = this.insertCell(c, side, position);
9704 td.appendChild(c.getPositionEl().dom);
9705 c.container = Ext.get(td);
9710 //strip extra empty cells
9711 this.cleanup(this.leftTr);
9712 this.cleanup(this.rightTr);
9713 this.cleanup(this.extrasTr);
9714 this.fitToSize(target);
9719 * Removes any empty nodes from the given element
9720 * @param {Ext.Element} el The element to clean up
9722 cleanup : function(el) {
9723 var cn = el.childNodes, i, c;
9725 for (i = cn.length-1; i >= 0 && (c = cn[i]); i--) {
9726 if (!c.firstChild) {
9734 * Inserts the given Toolbar item into the given element
9735 * @param {Ext.Component} c The component to add
9736 * @param {Ext.Element} target The target to add the component to
9737 * @param {Number} position The position to add the component at
9739 insertCell : function(c, target, position) {
9740 var td = document.createElement('td');
9741 td.className = 'x-toolbar-cell';
9743 target.insertBefore(td, target.childNodes[position] || null);
9750 * Hides an item because it will not fit in the available width. The item will be unhidden again
9751 * if the Toolbar is resized to be large enough to show it
9752 * @param {Ext.Component} item The item to hide
9754 hideItem : function(item) {
9755 this.hiddenItems.push(item);
9757 item.xtbHidden = true;
9758 item.xtbWidth = item.getPositionEl().dom.parentNode.offsetWidth;
9764 * Unhides an item that was previously hidden due to there not being enough space left on the Toolbar
9765 * @param {Ext.Component} item The item to show
9767 unhideItem : function(item) {
9769 item.xtbHidden = false;
9770 this.hiddenItems.remove(item);
9775 * Returns the width of the given toolbar item. If the item is currently hidden because there
9776 * is not enough room to render it, its previous width is returned
9777 * @param {Ext.Component} c The component to measure
9778 * @return {Number} The width of the item
9780 getItemWidth : function(c) {
9781 return c.hidden ? (c.xtbWidth || 0) : c.getPositionEl().dom.parentNode.offsetWidth;
9786 * Called at the end of onLayout. At this point the Toolbar has already been resized, so we need
9787 * to fit the items into the available width. We add up the width required by all of the items in
9788 * the toolbar - if we don't have enough space we hide the extra items and render the expand menu
9790 * @param {Ext.Element} target The Element the Toolbar is currently laid out within
9792 fitToSize : function(target) {
9793 if (this.container.enableOverflow === false) {
9797 var width = target.dom.clientWidth,
9798 tableWidth = target.dom.firstChild.offsetWidth,
9799 clipWidth = width - this.triggerWidth,
9800 lastWidth = this.lastWidth || 0,
9802 hiddenItems = this.hiddenItems,
9803 hasHiddens = hiddenItems.length != 0,
9804 isLarger = width >= lastWidth;
9806 this.lastWidth = width;
9808 if (tableWidth > width || (hasHiddens && isLarger)) {
9809 var items = this.container.items.items,
9814 for (var i = 0; i < len; i++) {
9818 loopWidth += this.getItemWidth(item);
9819 if (loopWidth > clipWidth) {
9820 if (!(item.hidden || item.xtbHidden)) {
9821 this.hideItem(item);
9823 } else if (item.xtbHidden) {
9824 this.unhideItem(item);
9830 //test for number of hidden items again here because they may have changed above
9831 hasHiddens = hiddenItems.length != 0;
9836 if (!this.lastOverflow) {
9837 this.container.fireEvent('overflowchange', this.container, true);
9838 this.lastOverflow = true;
9840 } else if (this.more) {
9842 this.more.destroy();
9845 if (this.lastOverflow) {
9846 this.container.fireEvent('overflowchange', this.container, false);
9847 this.lastOverflow = false;
9854 * Returns a menu config for a given component. This config is used to create a menu item
9855 * to be added to the expander menu
9856 * @param {Ext.Component} component The component to create the config for
9857 * @param {Boolean} hideOnClick Passed through to the menu item
9859 createMenuConfig : function(component, hideOnClick){
9860 var config = Ext.apply({}, component.initialConfig),
9861 group = component.toggleGroup;
9863 Ext.copyTo(config, component, [
9864 'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu'
9868 text : component.overflowText || component.text,
9869 hideOnClick: hideOnClick
9872 if (group || component.enableToggle) {
9875 checked: component.pressed,
9877 checkchange: function(item, checked){
9878 component.toggle(checked);
9884 delete config.ownerCt;
9885 delete config.xtype;
9893 * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually.
9894 * @param {Ext.menu.Menu} menu The menu to add to
9895 * @param {Ext.Component} component The component to add
9897 addComponentToMenu : function(menu, component) {
9898 if (component instanceof Ext.Toolbar.Separator) {
9901 } else if (Ext.isFunction(component.isXType)) {
9902 if (component.isXType('splitbutton')) {
9903 menu.add(this.createMenuConfig(component, true));
9905 } else if (component.isXType('button')) {
9906 menu.add(this.createMenuConfig(component, !component.menu));
9908 } else if (component.isXType('buttongroup')) {
9909 component.items.each(function(item){
9910 this.addComponentToMenu(menu, item);
9918 * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as
9919 * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item
9921 clearMenu : function(){
9922 var menu = this.moreMenu;
9923 if (menu && menu.items) {
9924 menu.items.each(function(item){
9932 * Called before the expand menu is shown, this rebuilds the menu since it was last shown because
9933 * it is possible that the items hidden due to space limitations on the Toolbar have changed since.
9934 * @param {Ext.menu.Menu} m The menu
9936 beforeMoreShow : function(menu) {
9937 var items = this.container.items.items,
9942 var needsSep = function(group, item){
9943 return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator);
9948 for (var i = 0; i < len; i++) {
9950 if (item.xtbHidden) {
9951 if (prev && (needsSep(item, prev) || needsSep(prev, item))) {
9954 this.addComponentToMenu(menu, item);
9959 // put something so the menu isn't empty if no compatible items found
9960 if (menu.items.length < 1) {
9961 menu.add(this.noItemsMenuText);
9967 * Creates the expand trigger and menu, adding them to the <tr> at the extreme right of the
9970 initMore : function(){
9974 * @property moreMenu
9975 * @type Ext.menu.Menu
9976 * The expand menu - holds items for every Toolbar item that cannot be shown
9977 * because the Toolbar is currently not wide enough.
9979 this.moreMenu = new Ext.menu.Menu({
9980 ownerCt : this.container,
9982 beforeshow: this.beforeMoreShow,
9991 * The expand button which triggers the overflow menu to be shown
9993 this.more = new Ext.Button({
9994 iconCls: 'x-toolbar-more-icon',
9995 cls : 'x-toolbar-more',
9996 menu : this.moreMenu,
9997 ownerCt: this.container
10000 var td = this.insertCell(this.more, this.extrasTr, 100);
10001 this.more.render(td);
10005 destroy : function(){
10006 Ext.destroy(this.more, this.moreMenu);
10007 delete this.leftTr;
10008 delete this.rightTr;
10009 delete this.extrasTr;
10010 Ext.layout.ToolbarLayout.superclass.destroy.call(this);
10014 Ext.Container.LAYOUTS.toolbar = Ext.layout.ToolbarLayout;
10016 * @class Ext.layout.MenuLayout
10017 * @extends Ext.layout.ContainerLayout
10018 * <p>Layout manager used by {@link Ext.menu.Menu}. Generally this class should not need to be used directly.</p>
10020 Ext.layout.MenuLayout = Ext.extend(Ext.layout.ContainerLayout, {
10021 monitorResize : true,
10025 setContainer : function(ct){
10026 this.monitorResize = !ct.floating;
10027 // This event is only fired by the menu in IE, used so we don't couple
10028 // the menu with the layout.
10029 ct.on('autosize', this.doAutoSize, this);
10030 Ext.layout.MenuLayout.superclass.setContainer.call(this, ct);
10033 renderItem : function(c, position, target){
10034 if (!this.itemTpl) {
10035 this.itemTpl = Ext.layout.MenuLayout.prototype.itemTpl = new Ext.XTemplate(
10036 '<li id="{itemId}" class="{itemCls}">',
10037 '<tpl if="needsIcon">',
10038 '<img alt="{altText}" src="{icon}" class="{iconCls}"/>',
10044 if(c && !c.rendered){
10045 if(Ext.isNumber(position)){
10046 position = target.dom.childNodes[position];
10048 var a = this.getItemArgs(c);
10050 // The Component's positionEl is the <li> it is rendered into
10051 c.render(c.positionEl = position ?
10052 this.itemTpl.insertBefore(position, a, true) :
10053 this.itemTpl.append(target, a, true));
10055 // Link the containing <li> to the item.
10056 c.positionEl.menuItemId = c.getItemId();
10058 // If rendering a regular Component, and it needs an icon,
10059 // move the Component rightwards.
10060 if (!a.isMenuItem && a.needsIcon) {
10061 c.positionEl.addClass('x-menu-list-item-indent');
10063 this.configureItem(c);
10064 }else if(c && !this.isValidParent(c, target)){
10065 if(Ext.isNumber(position)){
10066 position = target.dom.childNodes[position];
10068 target.dom.insertBefore(c.getActionEl().dom, position || null);
10072 getItemArgs : function(c) {
10073 var isMenuItem = c instanceof Ext.menu.Item,
10074 canHaveIcon = !(isMenuItem || c instanceof Ext.menu.Separator);
10077 isMenuItem: isMenuItem,
10078 needsIcon: canHaveIcon && (c.icon || c.iconCls),
10079 icon: c.icon || Ext.BLANK_IMAGE_URL,
10080 iconCls: 'x-menu-item-icon ' + (c.iconCls || ''),
10081 itemId: 'x-menu-el-' + c.id,
10082 itemCls: 'x-menu-list-item ',
10083 altText: c.altText || ''
10087 // Valid if the Component is in a <li> which is part of our target <ul>
10088 isValidParent : function(c, target) {
10089 return c.el.up('li.x-menu-list-item', 5).dom.parentNode === (target.dom || target);
10092 onLayout : function(ct, target){
10093 Ext.layout.MenuLayout.superclass.onLayout.call(this, ct, target);
10097 doAutoSize : function(){
10098 var ct = this.container, w = ct.width;
10102 }else if(Ext.isIE){
10103 ct.setWidth(Ext.isStrict && (Ext.isIE7 || Ext.isIE8) ? 'auto' : ct.minWidth);
10104 var el = ct.getEl(), t = el.dom.offsetWidth; // force recalc
10105 ct.setWidth(ct.getLayoutTarget().getWidth() + el.getFrameWidth('lr'));
10110 Ext.Container.LAYOUTS['menu'] = Ext.layout.MenuLayout;
10112 * @class Ext.Viewport
10113 * @extends Ext.Container
10114 * <p>A specialized container representing the viewable application area (the browser viewport).</p>
10115 * <p>The Viewport renders itself to the document body, and automatically sizes itself to the size of
10116 * the browser viewport and manages window resizing. There may only be one Viewport created
10117 * in a page. Inner layouts are available by virtue of the fact that all {@link Ext.Panel Panel}s
10118 * added to the Viewport, either through its {@link #items}, or through the items, or the {@link #add}
10119 * method of any of its child Panels may themselves have a layout.</p>
10120 * <p>The Viewport does not provide scrolling, so child Panels within the Viewport should provide
10121 * for scrolling if needed using the {@link #autoScroll} config.</p>
10122 * <p>An example showing a classic application border layout:</p><pre><code>
10127 html: '<h1 class="x-panel-header">Page Title</h1>',
10134 title: 'Navigation',
10136 // the west region might typically utilize a {@link Ext.tree.TreePanel TreePanel} or a Panel with {@link Ext.layout.AccordionLayout Accordion layout}
10139 title: 'Title for Panel',
10141 html: 'Information goes here',
10147 title: 'Title for the Grid Panel',
10152 // remaining grid configuration not shown ...
10153 // notice that the GridPanel is added directly as the region
10154 // it is not "overnested" inside another Panel
10157 xtype: 'tabpanel', // TabPanel itself has no title
10159 title: 'Default Tab',
10160 html: 'The first tab\'s content. Others may be added dynamically'
10166 * Create a new Viewport
10167 * @param {Object} config The config object
10170 Ext.Viewport = Ext.extend(Ext.Container, {
10172 * Privatize config options which, if used, would interfere with the
10173 * correct operation of the Viewport as the sole manager of the
10174 * layout of the document body.
10177 * @cfg {Mixed} applyTo @hide
10180 * @cfg {Boolean} allowDomMove @hide
10183 * @cfg {Boolean} hideParent @hide
10186 * @cfg {Mixed} renderTo @hide
10189 * @cfg {Boolean} hideParent @hide
10192 * @cfg {Number} height @hide
10195 * @cfg {Number} width @hide
10198 * @cfg {Boolean} autoHeight @hide
10201 * @cfg {Boolean} autoWidth @hide
10204 * @cfg {Boolean} deferHeight @hide
10207 * @cfg {Boolean} monitorResize @hide
10210 initComponent : function() {
10211 Ext.Viewport.superclass.initComponent.call(this);
10212 document.getElementsByTagName('html')[0].className += ' x-viewport';
10213 this.el = Ext.getBody();
10214 this.el.setHeight = Ext.emptyFn;
10215 this.el.setWidth = Ext.emptyFn;
10216 this.el.setSize = Ext.emptyFn;
10217 this.el.dom.scroll = 'no';
10218 this.allowDomMove = false;
10219 this.autoWidth = true;
10220 this.autoHeight = true;
10221 Ext.EventManager.onWindowResize(this.fireResize, this);
10222 this.renderTo = this.el;
10225 fireResize : function(w, h){
10226 this.fireEvent('resize', this, w, h, w, h);
10229 Ext.reg('viewport', Ext.Viewport);
10232 * @extends Ext.Container
10233 * <p>Panel is a container that has specific functionality and structural components that make
10234 * it the perfect building block for application-oriented user interfaces.</p>
10235 * <p>Panels are, by virtue of their inheritance from {@link Ext.Container}, capable
10236 * of being configured with a {@link Ext.Container#layout layout}, and containing child Components.</p>
10237 * <p>When either specifying child {@link Ext.Component#items items} of a Panel, or dynamically {@link Ext.Container#add adding} Components
10238 * to a Panel, remember to consider how you wish the Panel to arrange those child elements, and whether
10239 * 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
10240 * default, Panels use the {@link Ext.layout.ContainerLayout ContainerLayout} scheme. This simply renders
10241 * child components, appending them one after the other inside the Container, and <b>does not apply any sizing</b>
10243 * <p>A Panel may also contain {@link #bbar bottom} and {@link #tbar top} toolbars, along with separate
10244 * {@link #header}, {@link #footer} and {@link #body} sections (see {@link #frame} for additional
10245 * information).</p>
10246 * <p>Panel also provides built-in {@link #collapsible expandable and collapsible behavior}, along with
10247 * a variety of {@link #tools prebuilt tool buttons} that can be wired up to provide other customized
10248 * behavior. Panels can be easily dropped into any {@link Ext.Container Container} or layout, and the
10249 * layout and rendering pipeline is {@link Ext.Container#add completely managed by the framework}.</p>
10251 * @param {Object} config The config object
10254 Ext.Panel = Ext.extend(Ext.Container, {
10256 * The Panel's header {@link Ext.Element Element}. Read-only.
10257 * <p>This Element is used to house the {@link #title} and {@link #tools}</p>
10258 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
10259 * @type Ext.Element
10263 * The Panel's body {@link Ext.Element Element} which may be used to contain HTML content.
10264 * The content may be specified in the {@link #html} config, or it may be loaded using the
10265 * {@link autoLoad} config, or through the Panel's {@link #getUpdater Updater}. Read-only.
10266 * <p>If this is used to load visible HTML elements in either way, then
10267 * the Panel may not be used as a Layout for hosting nested Panels.</p>
10268 * <p>If this Panel is intended to be used as the host of a Layout (See {@link #layout}
10269 * then the body Element must not be loaded or changed - it is under the control
10270 * of the Panel's Layout.
10271 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
10272 * @type Ext.Element
10276 * The Panel's bwrap {@link Ext.Element Element} used to contain other Panel elements
10277 * (tbar, body, bbar, footer). See {@link #bodyCfg}. Read-only.
10278 * @type Ext.Element
10282 * True if this panel is collapsed. Read-only.
10284 * @property collapsed
10287 * @cfg {Object} bodyCfg
10288 * <p>A {@link Ext.DomHelper DomHelper} element specification object may be specified for any
10289 * Panel Element.</p>
10290 * <p>By default, the Default element in the table below will be used for the html markup to
10291 * create a child element with the commensurate Default class name (<code>baseCls</code> will be
10292 * replaced by <code>{@link #baseCls}</code>):</p>
10294 * Panel Default Default Custom Additional Additional
10295 * Element element class element class style
10296 * ======== ========================== ========= ============== ===========
10297 * {@link #header} div {@link #baseCls}+'-header' {@link #headerCfg} headerCssClass headerStyle
10298 * {@link #bwrap} div {@link #baseCls}+'-bwrap' {@link #bwrapCfg} bwrapCssClass bwrapStyle
10299 * + tbar div {@link #baseCls}+'-tbar' {@link #tbarCfg} tbarCssClass tbarStyle
10300 * + {@link #body} div {@link #baseCls}+'-body' {@link #bodyCfg} {@link #bodyCssClass} {@link #bodyStyle}
10301 * + bbar div {@link #baseCls}+'-bbar' {@link #bbarCfg} bbarCssClass bbarStyle
10302 * + {@link #footer} div {@link #baseCls}+'-footer' {@link #footerCfg} footerCssClass footerStyle
10304 * <p>Configuring a Custom element may be used, for example, to force the {@link #body} Element
10305 * to use a different form of markup than is created by default. An example of this might be
10306 * to {@link Ext.Element#createChild create a child} Panel containing a custom content, such as
10307 * a header, or forcing centering of all Panel content by having the body be a <center>
10311 title: 'Message Title',
10312 renderTo: Ext.getBody(),
10313 width: 200, height: 130,
10316 cls: 'x-panel-body', // Default class not applied if Custom element specified
10321 cls: 'x-panel-footer', // same as the Default class
10322 html: 'footer html'
10324 footerCssClass: 'custom-footer', // additional css class, see {@link Ext.element#addClass addClass}
10325 footerStyle: 'background-color:red' // see {@link #bodyStyle}
10328 * <p>The example above also explicitly creates a <code>{@link #footer}</code> with custom markup and
10329 * styling applied.</p>
10332 * @cfg {Object} headerCfg
10333 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
10334 * of this Panel's {@link #header} Element. See <code>{@link #bodyCfg}</code> also.</p>
10337 * @cfg {Object} bwrapCfg
10338 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
10339 * of this Panel's {@link #bwrap} Element. See <code>{@link #bodyCfg}</code> also.</p>
10342 * @cfg {Object} tbarCfg
10343 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
10344 * of this Panel's {@link #tbar} Element. See <code>{@link #bodyCfg}</code> also.</p>
10347 * @cfg {Object} bbarCfg
10348 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
10349 * of this Panel's {@link #bbar} Element. See <code>{@link #bodyCfg}</code> also.</p>
10352 * @cfg {Object} footerCfg
10353 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
10354 * of this Panel's {@link #footer} Element. See <code>{@link #bodyCfg}</code> also.</p>
10357 * @cfg {Boolean} closable
10358 * Panels themselves do not directly support being closed, but some Panel subclasses do (like
10359 * {@link Ext.Window}) or a Panel Class within an {@link Ext.TabPanel}. Specify <code>true</code>
10360 * to enable closing in such situations. Defaults to <code>false</code>.
10363 * The Panel's footer {@link Ext.Element Element}. Read-only.
10364 * <p>This Element is used to house the Panel's <code>{@link #buttons}</code> or <code>{@link #fbar}</code>.</p>
10365 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
10366 * @type Ext.Element
10370 * @cfg {Mixed} applyTo
10371 * <p>The id of the node, a DOM node or an existing Element corresponding to a DIV that is already present in
10372 * the document that specifies some panel-specific structural markup. When <code>applyTo</code> is used,
10373 * constituent parts of the panel can be specified by CSS class name within the main element, and the panel
10374 * will automatically create those components from that markup. Any required components not specified in the
10375 * markup will be autogenerated if necessary.</p>
10376 * <p>The following class names are supported (baseCls will be replaced by {@link #baseCls}):</p>
10377 * <ul><li>baseCls + '-header'</li>
10378 * <li>baseCls + '-header-text'</li>
10379 * <li>baseCls + '-bwrap'</li>
10380 * <li>baseCls + '-tbar'</li>
10381 * <li>baseCls + '-body'</li>
10382 * <li>baseCls + '-bbar'</li>
10383 * <li>baseCls + '-footer'</li></ul>
10384 * <p>Using this config, a call to render() is not required. If applyTo is specified, any value passed for
10385 * {@link #renderTo} will be ignored and the target element's parent node will automatically be used as the
10386 * panel's container.</p>
10389 * @cfg {Object/Array} tbar
10390 * <p>The top toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
10391 * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render.
10392 * To access the top toolbar after render, use {@link #getTopToolbar}.</p>
10393 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
10394 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
10395 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
10396 * submission parameters are collected from the DOM tree.</p>
10399 * @cfg {Object/Array} bbar
10400 * <p>The bottom toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
10401 * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render.
10402 * To access the bottom toolbar after render, use {@link #getBottomToolbar}.</p>
10403 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
10404 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
10405 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
10406 * submission parameters are collected from the DOM tree.</p>
10408 /** @cfg {Object/Array} fbar
10409 * <p>A {@link Ext.Toolbar Toolbar} object, a Toolbar config, or an array of
10410 * {@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>
10411 * <p>After render, the <code>fbar</code> property will be an {@link Ext.Toolbar Toolbar} instance.</p>
10412 * <p>If <code>{@link #buttons}</code> are specified, they will supersede the <code>fbar</code> configuration property.</p>
10413 * The Panel's <code>{@link #buttonAlign}</code> configuration affects the layout of these items, for example:
10415 var w = new Ext.Window({
10418 bbar: new Ext.Toolbar({
10425 {@link #buttonAlign}: 'left', // anything but 'center' or 'right' and you can use '-', and '->'
10426 // to control the alignment of fbar items
10434 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
10435 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
10436 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
10437 * submission parameters are collected from the DOM tree.</p>
10440 * @cfg {Boolean} header
10441 * <code>true</code> to create the Panel's header element explicitly, <code>false</code> to skip creating
10442 * it. If a <code>{@link #title}</code> is set the header will be created automatically, otherwise it will not.
10443 * If a <code>{@link #title}</code> is set but <code>header</code> is explicitly set to <code>false</code>, the header
10444 * will not be rendered.
10447 * @cfg {Boolean} footer
10448 * <code>true</code> to create the footer element explicitly, false to skip creating it. The footer
10449 * will be created automatically if <code>{@link #buttons}</code> or a <code>{@link #fbar}</code> have
10450 * been configured. See <code>{@link #bodyCfg}</code> for an example.
10453 * @cfg {String} title
10454 * The title text to be used as innerHTML (html tags are accepted) to display in the panel
10455 * <code>{@link #header}</code> (defaults to ''). When a <code>title</code> is specified the
10456 * <code>{@link #header}</code> element will automatically be created and displayed unless
10457 * {@link #header} is explicitly set to <code>false</code>. If you do not want to specify a
10458 * <code>title</code> at config time, but you may want one later, you must either specify a non-empty
10459 * <code>title</code> (a blank space ' ' will do) or <code>header:true</code> so that the container
10460 * element will get created.
10463 * @cfg {Array} buttons
10464 * <code>buttons</code> will be used as <code>{@link Ext.Container#items items}</code> for the toolbar in
10465 * the footer (<code>{@link #fbar}</code>). Typically the value of this configuration property will be
10466 * an array of {@link Ext.Button}s or {@link Ext.Button} configuration objects.
10467 * If an item is configured with <code>minWidth</code> or the Panel is configured with <code>minButtonWidth</code>,
10468 * that width will be applied to the item.
10471 * @cfg {Object/String/Function} autoLoad
10472 * A valid url spec according to the Updater {@link Ext.Updater#update} method.
10473 * If autoLoad is not null, the panel will attempt to load its contents
10474 * immediately upon render.<p>
10475 * The URL will become the default URL for this panel's {@link #body} element,
10476 * so it may be {@link Ext.Element#refresh refresh}ed at any time.</p>
10479 * @cfg {Boolean} frame
10480 * <code>false</code> by default to render with plain 1px square borders. <code>true</code> to render with
10481 * 9 elements, complete with custom rounded corners (also see {@link Ext.Element#boxWrap}).
10482 * <p>The template generated for each condition is depicted below:</p><pre><code>
10485 <div id="developer-specified-id-goes-here" class="x-panel">
10487 <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:false)</span></div>
10489 <div class="x-panel-bwrap">
10490 <div class="x-panel-body"><p>html value goes here</p></div>
10494 // frame = true (create 9 elements)
10495 <div id="developer-specified-id-goes-here" class="x-panel">
10496 <div class="x-panel-tl"><div class="x-panel-tr"><div class="x-panel-tc">
10497 <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:true)</span></div>
10498 </div></div></div>
10500 <div class="x-panel-bwrap">
10501 <div class="x-panel-ml"><div class="x-panel-mr"><div class="x-panel-mc">
10502 <div class="x-panel-body"><p>html value goes here</p></div>
10503 </div></div></div>
10505 <div class="x-panel-bl"><div class="x-panel-br"><div class="x-panel-bc"/>
10506 </div></div></div>
10511 * @cfg {Boolean} border
10512 * True to display the borders of the panel's body element, false to hide them (defaults to true). By default,
10513 * the border is a 2px wide inset border, but this can be further altered by setting {@link #bodyBorder} to false.
10516 * @cfg {Boolean} bodyBorder
10517 * True to display an interior border on the body element of the panel, false to hide it (defaults to true).
10518 * This only applies when {@link #border} == true. If border == true and bodyBorder == false, the border will display
10519 * as a 1px wide inset border, giving the entire body element an inset appearance.
10522 * @cfg {String/Object/Function} bodyCssClass
10523 * Additional css class selector to be applied to the {@link #body} element in the format expected by
10524 * {@link Ext.Element#addClass} (defaults to null). See {@link #bodyCfg}.
10527 * @cfg {String/Object/Function} bodyStyle
10528 * Custom CSS styles to be applied to the {@link #body} element in the format expected by
10529 * {@link Ext.Element#applyStyles} (defaults to null). See {@link #bodyCfg}.
10532 * @cfg {String} iconCls
10533 * The CSS class selector that specifies a background image to be used as the header icon (defaults to '').
10534 * <p>An example of specifying a custom icon class would be something like:
10536 // specify the property in the config for the class:
10540 // css class that specifies background image to be used as the icon image:
10541 .my-icon { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
10545 * @cfg {Boolean} collapsible
10546 * True to make the panel collapsible and have the expand/collapse toggle button automatically rendered into
10547 * the header tool button area, false to keep the panel statically sized with no button (defaults to false).
10550 * @cfg {Array} tools
10551 * An array of tool button configs to be added to the header tool area. When rendered, each tool is
10552 * stored as an {@link Ext.Element Element} referenced by a public property called <code><b></b>tools.<i><tool-type></i></code>
10553 * <p>Each tool config may contain the following properties:
10554 * <div class="mdetail-params"><ul>
10555 * <li><b>id</b> : String<div class="sub-desc"><b>Required.</b> The type
10556 * of tool to create. By default, this assigns a CSS class of the form <code>x-tool-<i><tool-type></i></code> to the
10557 * resulting tool Element. Ext provides CSS rules, and an icon sprite containing images for the tool types listed below.
10558 * The developer may implement custom tools by supplying alternate CSS rules and background images:
10560 * <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>
10561 * <div class="x-tool x-tool-close" style="float:left; margin-right:5;"> </div><div><code> close</code></div>
10562 * <div class="x-tool x-tool-minimize" style="float:left; margin-right:5;"> </div><div><code> minimize</code></div>
10563 * <div class="x-tool x-tool-maximize" style="float:left; margin-right:5;"> </div><div><code> maximize</code></div>
10564 * <div class="x-tool x-tool-restore" style="float:left; margin-right:5;"> </div><div><code> restore</code></div>
10565 * <div class="x-tool x-tool-gear" style="float:left; margin-right:5;"> </div><div><code> gear</code></div>
10566 * <div class="x-tool x-tool-pin" style="float:left; margin-right:5;"> </div><div><code> pin</code></div>
10567 * <div class="x-tool x-tool-unpin" style="float:left; margin-right:5;"> </div><div><code> unpin</code></div>
10568 * <div class="x-tool x-tool-right" style="float:left; margin-right:5;"> </div><div><code> right</code></div>
10569 * <div class="x-tool x-tool-left" style="float:left; margin-right:5;"> </div><div><code> left</code></div>
10570 * <div class="x-tool x-tool-up" style="float:left; margin-right:5;"> </div><div><code> up</code></div>
10571 * <div class="x-tool x-tool-down" style="float:left; margin-right:5;"> </div><div><code> down</code></div>
10572 * <div class="x-tool x-tool-refresh" style="float:left; margin-right:5;"> </div><div><code> refresh</code></div>
10573 * <div class="x-tool x-tool-minus" style="float:left; margin-right:5;"> </div><div><code> minus</code></div>
10574 * <div class="x-tool x-tool-plus" style="float:left; margin-right:5;"> </div><div><code> plus</code></div>
10575 * <div class="x-tool x-tool-help" style="float:left; margin-right:5;"> </div><div><code> help</code></div>
10576 * <div class="x-tool x-tool-search" style="float:left; margin-right:5;"> </div><div><code> search</code></div>
10577 * <div class="x-tool x-tool-save" style="float:left; margin-right:5;"> </div><div><code> save</code></div>
10578 * <div class="x-tool x-tool-print" style="float:left; margin-right:5;"> </div><div><code> print</code></div>
10580 * <li><b>handler</b> : Function<div class="sub-desc"><b>Required.</b> The function to
10581 * call when clicked. Arguments passed are:<ul>
10582 * <li><b>event</b> : Ext.EventObject<div class="sub-desc">The click event.</div></li>
10583 * <li><b>toolEl</b> : Ext.Element<div class="sub-desc">The tool Element.</div></li>
10584 * <li><b>panel</b> : Ext.Panel<div class="sub-desc">The host Panel</div></li>
10585 * <li><b>tc</b> : Object<div class="sub-desc">The tool configuration object</div></li>
10587 * <li><b>stopEvent</b> : Boolean<div class="sub-desc">Defaults to true. Specify as false to allow click event to propagate.</div></li>
10588 * <li><b>scope</b> : Object<div class="sub-desc">The scope in which to call the handler.</div></li>
10589 * <li><b>qtip</b> : String/Object<div class="sub-desc">A tip string, or
10590 * a config argument to {@link Ext.QuickTip#register}</div></li>
10591 * <li><b>hidden</b> : Boolean<div class="sub-desc">True to initially render hidden.</div></li>
10592 * <li><b>on</b> : Object<div class="sub-desc">A listener config object specifiying
10593 * event listeners in the format of an argument to {@link #addListener}</div></li>
10595 * <p>Note that, apart from the toggle tool which is provided when a panel is collapsible, these
10596 * tools only provide the visual button. Any required functionality must be provided by adding
10597 * handlers that implement the necessary behavior.</p>
10598 * <p>Example usage:</p>
10602 qtip: 'Refresh form Data',
10604 handler: function(event, toolEl, panel){
10611 handler: function(event, toolEl, panel){
10616 * <p>For the custom id of <code>'help'</code> define two relevant css classes with a link to
10617 * a 15x15 image:</p>
10619 .x-tool-help {background-image: url(images/help.png);}
10620 .x-tool-help-over {background-image: url(images/help_over.png);}
10621 // if using an image sprite:
10622 .x-tool-help {background-image: url(images/help.png) no-repeat 0 0;}
10623 .x-tool-help-over {background-position:-15px 0;}
10627 * @cfg {Ext.Template/Ext.XTemplate} toolTemplate
10628 * <p>A Template used to create {@link #tools} in the {@link #header} Element. Defaults to:</p><pre><code>
10629 new Ext.Template('<div class="x-tool x-tool-{id}">&#160;</div>')</code></pre>
10630 * <p>This may may be overridden to provide a custom DOM structure for tools based upon a more
10631 * complex XTemplate. The template's data is a single tool configuration object (Not the entire Array)
10632 * as specified in {@link #tools}. In the following example an <a> tag is used to provide a
10633 * visual indication when hovering over the tool:</p><pre><code>
10634 var win = new Ext.Window({
10637 href: '/MyPdfDoc.pdf'
10639 toolTemplate: new Ext.XTemplate(
10640 '<tpl if="id==\'download\'">',
10641 '<a class="x-tool x-tool-pdf" href="{href}"></a>',
10643 '<tpl if="id!=\'download\'">',
10644 '<div class="x-tool x-tool-{id}">&#160;</div>',
10651 * <p>Note that the CSS class 'x-tool-pdf' should have an associated style rule which provides an
10652 * appropriate background image, something like:</p>
10654 a.x-tool-pdf {background-image: url(../shared/extjs/images/pdf.gif)!important;}
10658 * @cfg {Boolean} hideCollapseTool
10659 * <code>true</code> to hide the expand/collapse toggle button when <code>{@link #collapsible} == true</code>,
10660 * <code>false</code> to display it (defaults to <code>false</code>).
10663 * @cfg {Boolean} titleCollapse
10664 * <code>true</code> to allow expanding and collapsing the panel (when <code>{@link #collapsible} = true</code>)
10665 * by clicking anywhere in the header bar, <code>false</code>) to allow it only by clicking to tool button
10666 * (defaults to <code>false</code>)). If this panel is a child item of a border layout also see the
10667 * {@link Ext.layout.BorderLayout.Region BorderLayout.Region}
10668 * <code>{@link Ext.layout.BorderLayout.Region#floatable floatable}</code> config option.
10672 * @cfg {Mixed} floating
10673 * <p>This property is used to configure the underlying {@link Ext.Layer}. Acceptable values for this
10674 * configuration property are:</p><div class="mdetail-params"><ul>
10675 * <li><b><code>false</code></b> : <b>Default.</b><div class="sub-desc">Display the panel inline where it is
10676 * rendered.</div></li>
10677 * <li><b><code>true</code></b> : <div class="sub-desc">Float the panel (absolute position it with automatic
10678 * shimming and shadow).<ul>
10679 * <div class="sub-desc">Setting floating to true will create an Ext.Layer for this panel and display the
10680 * panel at negative offsets so that it is hidden.</div>
10681 * <div class="sub-desc">Since the panel will be absolute positioned, the position must be set explicitly
10682 * <i>after</i> render (e.g., <code>myPanel.setPosition(100,100);</code>).</div>
10683 * <div class="sub-desc"><b>Note</b>: when floating a panel you should always assign a fixed width,
10684 * otherwise it will be auto width and will expand to fill to the right edge of the viewport.</div>
10686 * <li><b><code>{@link Ext.Layer object}</code></b> : <div class="sub-desc">The specified object will be used
10687 * as the configuration object for the {@link Ext.Layer} that will be created.</div></li>
10691 * @cfg {Boolean/String} shadow
10692 * <code>true</code> (or a valid Ext.Shadow {@link Ext.Shadow#mode} value) to display a shadow behind the
10693 * panel, <code>false</code> to display no shadow (defaults to <code>'sides'</code>). Note that this option
10694 * only applies when <code>{@link #floating} = true</code>.
10697 * @cfg {Number} shadowOffset
10698 * The number of pixels to offset the shadow if displayed (defaults to <code>4</code>). Note that this
10699 * option only applies when <code>{@link #floating} = true</code>.
10702 * @cfg {Boolean} shim
10703 * <code>false</code> to disable the iframe shim in browsers which need one (defaults to <code>true</code>).
10704 * Note that this option only applies when <code>{@link #floating} = true</code>.
10707 * @cfg {Object/Array} keys
10708 * A {@link Ext.KeyMap} config object (in the format expected by {@link Ext.KeyMap#addBinding}
10709 * used to assign custom key handling to this panel (defaults to <code>null</code>).
10712 * @cfg {Boolean/Object} draggable
10713 * <p><code>true</code> to enable dragging of this Panel (defaults to <code>false</code>).</p>
10714 * <p>For custom drag/drop implementations, an <b>Ext.Panel.DD</b> config could also be passed
10715 * in this config instead of <code>true</code>. Ext.Panel.DD is an internal, undocumented class which
10716 * moves a proxy Element around in place of the Panel's element, but provides no other behaviour
10717 * during dragging or on drop. It is a subclass of {@link Ext.dd.DragSource}, so behaviour may be
10718 * added by implementing the interface methods of {@link Ext.dd.DragDrop} e.g.:
10724 renderTo: Ext.getBody(),
10730 // Config option of Ext.Panel.DD class.
10731 // It's a floating Panel, so do not show a placeholder proxy in the original position.
10732 insertProxy: false,
10734 // Called for each mousemove event while dragging the DD object.
10735 onDrag : function(e){
10736 // Record the x,y position of the drag proxy so that we can
10737 // position the Panel at end of drag.
10738 var pel = this.proxy.getEl();
10739 this.x = pel.getLeft(true);
10740 this.y = pel.getTop(true);
10742 // Keep the Shadow aligned if there is one.
10743 var s = this.panel.getEl().shadow;
10745 s.realign(this.x, this.y, pel.getWidth(), pel.getHeight());
10749 // Called on the mouseup event.
10750 endDrag : function(e){
10751 this.panel.setPosition(this.x, this.y);
10758 * @cfg {Boolean} disabled
10759 * Render this panel disabled (default is <code>false</code>). An important note when using the disabled
10760 * config on panels is that IE will often fail to initialize the disabled mask element correectly if
10761 * the panel's layout has not yet completed by the time the Panel is disabled during the render process.
10762 * If you experience this issue, you may need to instead use the {@link #afterlayout} event to initialize
10763 * the disabled state:
10772 single: true // important, as many layouts can occur
10779 * @cfg {Boolean} autoHeight
10780 * <code>true</code> to use height:'auto', <code>false</code> to use fixed height (defaults to <code>false</code>).
10781 * <b>Note</b>: Setting <code>autoHeight: true</code> means that the browser will manage the panel's height
10782 * based on its contents, and that Ext will not manage it at all. If the panel is within a layout that
10783 * manages dimensions (<code>fit</code>, <code>border</code>, etc.) then setting <code>autoHeight: true</code>
10784 * can cause issues with scrolling and will not generally work as expected since the panel will take
10785 * on the height of its contents rather than the height required by the Ext layout.
10790 * @cfg {String} baseCls
10791 * The base CSS class to apply to this panel's element (defaults to <code>'x-panel'</code>).
10792 * <p>Another option available by default is to specify <code>'x-plain'</code> which strips all styling
10793 * except for required attributes for Ext layouts to function (e.g. overflow:hidden).
10794 * See <code>{@link #unstyled}</code> also.</p>
10796 baseCls : 'x-panel',
10798 * @cfg {String} collapsedCls
10799 * A CSS class to add to the panel's element after it has been collapsed (defaults to
10800 * <code>'x-panel-collapsed'</code>).
10802 collapsedCls : 'x-panel-collapsed',
10804 * @cfg {Boolean} maskDisabled
10805 * <code>true</code> to mask the panel when it is {@link #disabled}, <code>false</code> to not mask it (defaults
10806 * to <code>true</code>). Either way, the panel will always tell its contained elements to disable themselves
10807 * when it is disabled, but masking the panel can provide an additional visual cue that the panel is
10810 maskDisabled : true,
10812 * @cfg {Boolean} animCollapse
10813 * <code>true</code> to animate the transition when the panel is collapsed, <code>false</code> to skip the
10814 * animation (defaults to <code>true</code> if the {@link Ext.Fx} class is available, otherwise <code>false</code>).
10816 animCollapse : Ext.enableFx,
10818 * @cfg {Boolean} headerAsText
10819 * <code>true</code> to display the panel <code>{@link #title}</code> in the <code>{@link #header}</code>,
10820 * <code>false</code> to hide it (defaults to <code>true</code>).
10822 headerAsText : true,
10824 * @cfg {String} buttonAlign
10825 * The alignment of any {@link #buttons} added to this panel. Valid values are <code>'right'</code>,
10826 * <code>'left'</code> and <code>'center'</code> (defaults to <code>'right'</code>).
10828 buttonAlign : 'right',
10830 * @cfg {Boolean} collapsed
10831 * <code>true</code> to render the panel collapsed, <code>false</code> to render it expanded (defaults to
10832 * <code>false</code>).
10836 * @cfg {Boolean} collapseFirst
10837 * <code>true</code> to make sure the collapse/expand toggle button always renders first (to the left of)
10838 * any other tools in the panel's title bar, <code>false</code> to render it last (defaults to <code>true</code>).
10840 collapseFirst : true,
10842 * @cfg {Number} minButtonWidth
10843 * Minimum width in pixels of all {@link #buttons} in this panel (defaults to <code>75</code>)
10845 minButtonWidth : 75,
10847 * @cfg {Boolean} unstyled
10848 * Overrides the <code>{@link #baseCls}</code> setting to <code>{@link #baseCls} = 'x-plain'</code> which renders
10849 * the panel unstyled except for required attributes for Ext layouts to function (e.g. overflow:hidden).
10852 * @cfg {String} elements
10853 * A comma-delimited list of panel elements to initialize when the panel is rendered. Normally, this list will be
10854 * generated automatically based on the items added to the panel at config time, but sometimes it might be useful to
10855 * make sure a structural element is rendered even if not specified at config time (for example, you may want
10856 * to add a button or toolbar dynamically after the panel has been rendered). Adding those elements to this
10857 * list will allocate the required placeholders in the panel when it is rendered. Valid values are<div class="mdetail-params"><ul>
10858 * <li><code>header</code></li>
10859 * <li><code>tbar</code> (top bar)</li>
10860 * <li><code>body</code></li>
10861 * <li><code>bbar</code> (bottom bar)</li>
10862 * <li><code>footer</code></li>
10864 * Defaults to '<code>body</code>'.
10868 * @cfg {Boolean} preventBodyReset
10869 * Defaults to <code>false</code>. When set to <code>true</code>, an extra css class <code>'x-panel-normal'</code>
10870 * will be added to the panel's element, effectively applying css styles suggested by the W3C
10871 * (see http://www.w3.org/TR/CSS21/sample.html) to the Panel's <b>body</b> element (not the header,
10874 preventBodyReset : false,
10877 * @cfg {Number/String} padding
10878 * A shortcut for setting a padding style on the body element. The value can either be
10879 * a number to be applied to all sides, or a normal css string describing padding.
10880 * Defaults to <tt>undefined</tt>.
10883 padding: undefined,
10885 /** @cfg {String} resizeEvent
10886 * The event to listen to for resizing in layouts. Defaults to <tt>'bodyresize'</tt>.
10888 resizeEvent: 'bodyresize',
10890 // protected - these could be used to customize the behavior of the window,
10891 // but changing them would not be useful without further mofifications and
10892 // could lead to unexpected or undesirable results.
10893 toolTarget : 'header',
10894 collapseEl : 'bwrap',
10896 disabledClass : '',
10898 // private, notify box this class will handle heights
10899 deferHeight : true,
10905 collapseDefaults : {
10910 initComponent : function(){
10911 Ext.Panel.superclass.initComponent.call(this);
10915 * @event bodyresize
10916 * Fires after the Panel has been resized.
10917 * @param {Ext.Panel} p the Panel which has been resized.
10918 * @param {Number} width The Panel body's new width.
10919 * @param {Number} height The Panel body's new height.
10923 * @event titlechange
10924 * Fires after the Panel title has been {@link #title set} or {@link #setTitle changed}.
10925 * @param {Ext.Panel} p the Panel which has had its title changed.
10926 * @param {String} The new title.
10930 * @event iconchange
10931 * Fires after the Panel icon class has been {@link #iconCls set} or {@link #setIconClass changed}.
10932 * @param {Ext.Panel} p the Panel which has had its {@link #iconCls icon class} changed.
10933 * @param {String} The new icon class.
10934 * @param {String} The old icon class.
10939 * Fires after the Panel has been collapsed.
10940 * @param {Ext.Panel} p the Panel that has been collapsed.
10945 * Fires after the Panel has been expanded.
10946 * @param {Ext.Panel} p The Panel that has been expanded.
10950 * @event beforecollapse
10951 * Fires before the Panel is collapsed. A handler can return false to cancel the collapse.
10952 * @param {Ext.Panel} p the Panel being collapsed.
10953 * @param {Boolean} animate True if the collapse is animated, else false.
10957 * @event beforeexpand
10958 * Fires before the Panel is expanded. A handler can return false to cancel the expand.
10959 * @param {Ext.Panel} p The Panel being expanded.
10960 * @param {Boolean} animate True if the expand is animated, else false.
10964 * @event beforeclose
10965 * Fires before the Panel is closed. Note that Panels do not directly support being closed, but some
10966 * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel. This event only
10967 * applies to such subclasses.
10968 * A handler can return false to cancel the close.
10969 * @param {Ext.Panel} p The Panel being closed.
10974 * Fires after the Panel is closed. Note that Panels do not directly support being closed, but some
10975 * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel.
10976 * @param {Ext.Panel} p The Panel that has been closed.
10981 * Fires after the Panel has been visually activated.
10982 * Note that Panels do not directly support being activated, but some Panel subclasses
10983 * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
10984 * activate and deactivate events under the control of the TabPanel.
10985 * @param {Ext.Panel} p The Panel that has been activated.
10989 * @event deactivate
10990 * Fires after the Panel has been visually deactivated.
10991 * Note that Panels do not directly support being deactivated, but some Panel subclasses
10992 * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
10993 * activate and deactivate events under the control of the TabPanel.
10994 * @param {Ext.Panel} p The Panel that has been deactivated.
11000 this.baseCls = 'x-plain';
11004 this.toolbars = [];
11007 this.elements += ',tbar';
11008 this.topToolbar = this.createToolbar(this.tbar);
11013 this.elements += ',bbar';
11014 this.bottomToolbar = this.createToolbar(this.bbar);
11018 if(this.header === true){
11019 this.elements += ',header';
11020 this.header = null;
11021 }else if(this.headerCfg || (this.title && this.header !== false)){
11022 this.elements += ',header';
11025 if(this.footerCfg || this.footer === true){
11026 this.elements += ',footer';
11027 this.footer = null;
11031 this.fbar = this.buttons;
11032 this.buttons = null;
11035 this.createFbar(this.fbar);
11038 this.on('render', this.doAutoLoad, this, {delay:10});
11043 createFbar : function(fbar){
11044 var min = this.minButtonWidth;
11045 this.elements += ',footer';
11046 this.fbar = this.createToolbar(fbar, {
11047 buttonAlign: this.buttonAlign,
11048 toolbarCls: 'x-panel-fbar',
11049 enableOverflow: false,
11050 defaults: function(c){
11052 minWidth: c.minWidth || min
11056 // @compat addButton and buttons could possibly be removed
11059 * This Panel's Array of buttons as created from the <code>{@link #buttons}</code>
11060 * config property. Read only.
11062 * @property buttons
11064 this.fbar.items.each(function(c){
11065 c.minWidth = c.minWidth || this.minButtonWidth;
11067 this.buttons = this.fbar.items.items;
11071 createToolbar: function(tb, options){
11073 // Convert array to proper toolbar config
11074 if(Ext.isArray(tb)){
11079 result = tb.events ? Ext.apply(tb, options) : this.createComponent(Ext.apply({}, tb, options), 'toolbar');
11080 this.toolbars.push(result);
11085 createElement : function(name, pnode){
11087 pnode.appendChild(this[name].dom);
11091 if(name === 'bwrap' || this.elements.indexOf(name) != -1){
11092 if(this[name+'Cfg']){
11093 this[name] = Ext.fly(pnode).createChild(this[name+'Cfg']);
11095 var el = document.createElement('div');
11096 el.className = this[name+'Cls'];
11097 this[name] = Ext.get(pnode.appendChild(el));
11099 if(this[name+'CssClass']){
11100 this[name].addClass(this[name+'CssClass']);
11102 if(this[name+'Style']){
11103 this[name].applyStyles(this[name+'Style']);
11109 onRender : function(ct, position){
11110 Ext.Panel.superclass.onRender.call(this, ct, position);
11111 this.createClasses();
11119 if(this.collapsible && !this.hideCollapseTool){
11120 this.tools = this.tools ? this.tools.slice(0) : [];
11121 this.tools[this.collapseFirst?'unshift':'push']({
11123 handler : this.toggleCollapse,
11130 this.elements += (this.header !== false) ? ',header' : '';
11134 el.addClass(this.baseCls);
11135 if(d.firstChild){ // existing markup
11136 this.header = el.down('.'+this.headerCls);
11137 this.bwrap = el.down('.'+this.bwrapCls);
11138 var cp = this.bwrap ? this.bwrap : el;
11139 this.tbar = cp.down('.'+this.tbarCls);
11140 this.body = cp.down('.'+this.bodyCls);
11141 this.bbar = cp.down('.'+this.bbarCls);
11142 this.footer = cp.down('.'+this.footerCls);
11143 this.fromMarkup = true;
11145 if (this.preventBodyReset === true) {
11146 el.addClass('x-panel-reset');
11149 el.addClass(this.cls);
11153 this.elements += ',footer';
11156 // This block allows for maximum flexibility and performance when using existing markup
11158 // framing requires special markup
11160 el.insertHtml('afterBegin', String.format(Ext.Element.boxMarkup, this.baseCls));
11162 this.createElement('header', d.firstChild.firstChild.firstChild);
11163 this.createElement('bwrap', d);
11165 // append the mid and bottom frame to the bwrap
11166 bw = this.bwrap.dom;
11167 var ml = d.childNodes[1], bl = d.childNodes[2];
11168 bw.appendChild(ml);
11169 bw.appendChild(bl);
11171 var mc = bw.firstChild.firstChild.firstChild;
11172 this.createElement('tbar', mc);
11173 this.createElement('body', mc);
11174 this.createElement('bbar', mc);
11175 this.createElement('footer', bw.lastChild.firstChild.firstChild);
11178 this.bwrap.dom.lastChild.className += ' x-panel-nofooter';
11181 * Store a reference to this element so:
11182 * a) We aren't looking it up all the time
11183 * b) The last element is reported incorrectly when using a loadmask
11185 this.ft = Ext.get(this.bwrap.dom.lastChild);
11186 this.mc = Ext.get(mc);
11188 this.createElement('header', d);
11189 this.createElement('bwrap', d);
11191 // append the mid and bottom frame to the bwrap
11192 bw = this.bwrap.dom;
11193 this.createElement('tbar', bw);
11194 this.createElement('body', bw);
11195 this.createElement('bbar', bw);
11196 this.createElement('footer', bw);
11199 this.body.addClass(this.bodyCls + '-noheader');
11201 this.tbar.addClass(this.tbarCls + '-noheader');
11206 if(Ext.isDefined(this.padding)){
11207 this.body.setStyle('padding', this.body.addUnits(this.padding));
11210 if(this.border === false){
11211 this.el.addClass(this.baseCls + '-noborder');
11212 this.body.addClass(this.bodyCls + '-noborder');
11214 this.header.addClass(this.headerCls + '-noborder');
11217 this.footer.addClass(this.footerCls + '-noborder');
11220 this.tbar.addClass(this.tbarCls + '-noborder');
11223 this.bbar.addClass(this.bbarCls + '-noborder');
11227 if(this.bodyBorder === false){
11228 this.body.addClass(this.bodyCls + '-noborder');
11231 this.bwrap.enableDisplayMode('block');
11234 this.header.unselectable();
11236 // for tools, we need to wrap any existing header markup
11237 if(this.headerAsText){
11238 this.header.dom.innerHTML =
11239 '<span class="' + this.headerTextCls + '">'+this.header.dom.innerHTML+'</span>';
11242 this.setIconClass(this.iconCls);
11248 this.makeFloating(this.floating);
11251 if(this.collapsible && this.titleCollapse && this.header){
11252 this.mon(this.header, 'click', this.toggleCollapse, this);
11253 this.header.setStyle('cursor', 'pointer');
11256 this.addTool.apply(this, ts);
11259 // Render Toolbars.
11261 this.footer.addClass('x-panel-btns');
11262 this.fbar.ownerCt = this;
11263 this.fbar.render(this.footer);
11264 this.footer.createChild({cls:'x-clear'});
11266 if(this.tbar && this.topToolbar){
11267 this.topToolbar.ownerCt = this;
11268 this.topToolbar.render(this.tbar);
11270 if(this.bbar && this.bottomToolbar){
11271 this.bottomToolbar.ownerCt = this;
11272 this.bottomToolbar.render(this.bbar);
11277 * Sets the CSS class that provides the icon image for this panel. This method will replace any existing
11278 * icon class if one has already been set and fire the {@link #iconchange} event after completion.
11279 * @param {String} cls The new CSS class name
11281 setIconClass : function(cls){
11282 var old = this.iconCls;
11283 this.iconCls = cls;
11284 if(this.rendered && this.header){
11286 this.header.addClass('x-panel-icon');
11287 this.header.replaceClass(old, this.iconCls);
11289 var hd = this.header,
11290 img = hd.child('img.x-panel-inline-icon');
11292 Ext.fly(img).replaceClass(old, this.iconCls);
11294 var hdspan = hd.child('span.' + this.headerTextCls);
11296 Ext.DomHelper.insertBefore(hdspan.dom, {
11297 tag:'img', alt: '', src: Ext.BLANK_IMAGE_URL, cls:'x-panel-inline-icon '+this.iconCls
11303 this.fireEvent('iconchange', this, cls, old);
11307 makeFloating : function(cfg){
11308 this.floating = true;
11309 this.el = new Ext.Layer(Ext.apply({}, cfg, {
11310 shadow: Ext.isDefined(this.shadow) ? this.shadow : 'sides',
11311 shadowOffset: this.shadowOffset,
11313 shim: this.shim === false ? false : undefined
11318 * Returns the {@link Ext.Toolbar toolbar} from the top (<code>{@link #tbar}</code>) section of the panel.
11319 * @return {Ext.Toolbar} The toolbar
11321 getTopToolbar : function(){
11322 return this.topToolbar;
11326 * Returns the {@link Ext.Toolbar toolbar} from the bottom (<code>{@link #bbar}</code>) section of the panel.
11327 * @return {Ext.Toolbar} The toolbar
11329 getBottomToolbar : function(){
11330 return this.bottomToolbar;
11334 * Returns the {@link Ext.Toolbar toolbar} from the footer (<code>{@link #fbar}</code>) section of the panel.
11335 * @return {Ext.Toolbar} The toolbar
11337 getFooterToolbar : function() {
11342 * Adds a button to this panel. Note that this method must be called prior to rendering. The preferred
11343 * approach is to add buttons via the {@link #buttons} config.
11344 * @param {String/Object} config A valid {@link Ext.Button} config. A string will become the text for a default
11345 * button config, an object will be treated as a button config object.
11346 * @param {Function} handler The function to be called on button {@link Ext.Button#click}
11347 * @param {Object} scope The scope (<code>this</code> reference) in which the button handler function is executed. Defaults to the Button.
11348 * @return {Ext.Button} The button that was added
11350 addButton : function(config, handler, scope){
11352 this.createFbar([]);
11355 if(Ext.isString(config)){
11356 config = {text: config};
11358 config = Ext.apply({
11363 return this.fbar.add(config);
11367 addTool : function(){
11368 if(!this.rendered){
11372 Ext.each(arguments, function(arg){
11373 this.tools.push(arg);
11377 // nowhere to render tools!
11378 if(!this[this.toolTarget]){
11381 if(!this.toolTemplate){
11382 // initialize the global tool template on first use
11383 var tt = new Ext.Template(
11384 '<div class="x-tool x-tool-{id}"> </div>'
11386 tt.disableFormats = true;
11388 Ext.Panel.prototype.toolTemplate = tt;
11390 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
11392 if(!this.tools[tc.id]){
11393 var overCls = 'x-tool-'+tc.id+'-over';
11394 var t = this.toolTemplate.insertFirst(this[this.toolTarget], tc, true);
11395 this.tools[tc.id] = t;
11396 t.enableDisplayMode('block');
11397 this.mon(t, 'click', this.createToolHandler(t, tc, overCls, this));
11399 this.mon(t, tc.on);
11405 if(Ext.isObject(tc.qtip)){
11406 Ext.QuickTips.register(Ext.apply({
11410 t.dom.qtip = tc.qtip;
11413 t.addClassOnOver(overCls);
11418 onLayout : function(shallow, force){
11419 Ext.Panel.superclass.onLayout.apply(this, arguments);
11420 if(this.hasLayout && this.toolbars.length > 0){
11421 Ext.each(this.toolbars, function(tb){
11422 tb.doLayout(undefined, force);
11428 syncHeight : function(){
11429 var h = this.toolbarHeight,
11431 lsh = this.lastSize.height,
11434 if(this.autoHeight || !Ext.isDefined(lsh) || lsh == 'auto'){
11439 if(h != this.getToolbarHeight()){
11440 h = Math.max(0, lsh - this.getFrameHeight());
11443 this.toolbarHeight = this.getToolbarHeight();
11444 this.onBodyResize(sz.width, sz.height);
11449 onShow : function(){
11451 return this.el.show();
11453 Ext.Panel.superclass.onShow.call(this);
11457 onHide : function(){
11459 return this.el.hide();
11461 Ext.Panel.superclass.onHide.call(this);
11465 createToolHandler : function(t, tc, overCls, panel){
11466 return function(e){
11467 t.removeClass(overCls);
11468 if(tc.stopEvent !== false){
11472 tc.handler.call(tc.scope || t, e, t, panel, tc);
11478 afterRender : function(){
11479 if(this.floating && !this.hidden){
11483 this.setTitle(this.title);
11485 Ext.Panel.superclass.afterRender.call(this); // do sizing calcs last
11486 if (this.collapsed) {
11487 this.collapsed = false;
11488 this.collapse(false);
11494 getKeyMap : function(){
11496 this.keyMap = new Ext.KeyMap(this.el, this.keys);
11498 return this.keyMap;
11502 initEvents : function(){
11506 if(this.draggable){
11507 this.initDraggable();
11509 if(this.toolbars.length > 0){
11510 Ext.each(this.toolbars, function(tb){
11514 afterlayout: this.syncHeight,
11515 remove: this.syncHeight
11524 initDraggable : function(){
11526 * <p>If this Panel is configured {@link #draggable}, this property will contain
11527 * an instance of {@link Ext.dd.DragSource} which handles dragging the Panel.</p>
11528 * The developer must provide implementations of the abstract methods of {@link Ext.dd.DragSource}
11529 * in order to supply behaviour for each stage of the drag/drop process. See {@link #draggable}.
11530 * @type Ext.dd.DragSource.
11533 this.dd = new Ext.Panel.DD(this, Ext.isBoolean(this.draggable) ? null : this.draggable);
11537 beforeEffect : function(anim){
11539 this.el.beforeAction();
11541 if(anim !== false){
11542 this.el.addClass('x-panel-animated');
11547 afterEffect : function(anim){
11549 this.el.removeClass('x-panel-animated');
11552 // private - wraps up an animation param with internal callbacks
11553 createEffect : function(a, cb, scope){
11561 }else if(!a.callback){
11563 }else { // wrap it up
11564 o.callback = function(){
11566 Ext.callback(a.callback, a.scope);
11569 return Ext.applyIf(o, a);
11573 * Collapses the panel body so that it becomes hidden. Fires the {@link #beforecollapse} event which will
11574 * cancel the collapse action if it returns false.
11575 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
11576 * {@link #animCollapse} panel config)
11577 * @return {Ext.Panel} this
11579 collapse : function(animate){
11580 if(this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforecollapse', this, animate) === false){
11583 var doAnim = animate === true || (animate !== false && this.animCollapse);
11584 this.beforeEffect(doAnim);
11585 this.onCollapse(doAnim, animate);
11590 onCollapse : function(doAnim, animArg){
11592 this[this.collapseEl].slideOut(this.slideAnchor,
11593 Ext.apply(this.createEffect(animArg||true, this.afterCollapse, this),
11594 this.collapseDefaults));
11596 this[this.collapseEl].hide(this.hideMode);
11597 this.afterCollapse(false);
11602 afterCollapse : function(anim){
11603 this.collapsed = true;
11604 this.el.addClass(this.collapsedCls);
11605 if(anim !== false){
11606 this[this.collapseEl].hide(this.hideMode);
11608 this.afterEffect(anim);
11610 // Reset lastSize of all sub-components so they KNOW they are in a collapsed container
11611 this.cascade(function(c) {
11613 c.lastSize = { width: undefined, height: undefined };
11616 this.fireEvent('collapse', this);
11620 * Expands the panel body so that it becomes visible. Fires the {@link #beforeexpand} event which will
11621 * cancel the expand action if it returns false.
11622 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
11623 * {@link #animCollapse} panel config)
11624 * @return {Ext.Panel} this
11626 expand : function(animate){
11627 if(!this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforeexpand', this, animate) === false){
11630 var doAnim = animate === true || (animate !== false && this.animCollapse);
11631 this.el.removeClass(this.collapsedCls);
11632 this.beforeEffect(doAnim);
11633 this.onExpand(doAnim, animate);
11638 onExpand : function(doAnim, animArg){
11640 this[this.collapseEl].slideIn(this.slideAnchor,
11641 Ext.apply(this.createEffect(animArg||true, this.afterExpand, this),
11642 this.expandDefaults));
11644 this[this.collapseEl].show(this.hideMode);
11645 this.afterExpand(false);
11650 afterExpand : function(anim){
11651 this.collapsed = false;
11652 if(anim !== false){
11653 this[this.collapseEl].show(this.hideMode);
11655 this.afterEffect(anim);
11656 if (this.deferLayout) {
11657 delete this.deferLayout;
11658 this.doLayout(true);
11660 this.fireEvent('expand', this);
11664 * Shortcut for performing an {@link #expand} or {@link #collapse} based on the current state of the panel.
11665 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
11666 * {@link #animCollapse} panel config)
11667 * @return {Ext.Panel} this
11669 toggleCollapse : function(animate){
11670 this[this.collapsed ? 'expand' : 'collapse'](animate);
11675 onDisable : function(){
11676 if(this.rendered && this.maskDisabled){
11679 Ext.Panel.superclass.onDisable.call(this);
11683 onEnable : function(){
11684 if(this.rendered && this.maskDisabled){
11687 Ext.Panel.superclass.onEnable.call(this);
11691 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
11695 if(Ext.isDefined(w) || Ext.isDefined(h)){
11696 if(!this.collapsed){
11697 // First, set the the Panel's body width.
11698 // If we have auto-widthed it, get the resulting full offset width so we can size the Toolbars to match
11699 // The Toolbars must not buffer this resize operation because we need to know their heights.
11701 if(Ext.isNumber(w)){
11702 this.body.setWidth(w = this.adjustBodyWidth(w - this.getFrameWidth()));
11703 } else if (w == 'auto') {
11704 w = this.body.setWidth('auto').dom.offsetWidth;
11706 w = this.body.dom.offsetWidth;
11710 this.tbar.setWidth(w);
11711 if(this.topToolbar){
11712 this.topToolbar.setSize(w);
11716 this.bbar.setWidth(w);
11717 if(this.bottomToolbar){
11718 this.bottomToolbar.setSize(w);
11719 // The bbar does not move on resize without this.
11721 this.bbar.setStyle('position', 'static');
11722 this.bbar.setStyle('position', '');
11727 this.footer.setWidth(w);
11729 this.fbar.setSize(Ext.isIE ? (w - this.footer.getFrameWidth('lr')) : 'auto');
11733 // At this point, the Toolbars must be layed out for getFrameHeight to find a result.
11734 if(Ext.isNumber(h)){
11735 h = Math.max(0, h - this.getFrameHeight());
11736 //h = Math.max(0, h - (this.getHeight() - this.body.getHeight()));
11737 this.body.setHeight(h);
11738 }else if(h == 'auto'){
11739 this.body.setHeight(h);
11742 if(this.disabled && this.el._mask){
11743 this.el._mask.setSize(this.el.dom.clientWidth, this.el.getHeight());
11746 // Adds an event to set the correct height afterExpand. This accounts for the deferHeight flag in panel
11747 this.queuedBodySize = {width: w, height: h};
11748 if(!this.queuedExpand && this.allowQueuedExpand !== false){
11749 this.queuedExpand = true;
11750 this.on('expand', function(){
11751 delete this.queuedExpand;
11752 this.onResize(this.queuedBodySize.width, this.queuedBodySize.height);
11753 }, this, {single:true});
11756 this.onBodyResize(w, h);
11759 Ext.Panel.superclass.onResize.call(this, adjWidth, adjHeight, rawWidth, rawHeight);
11764 onBodyResize: function(w, h){
11765 this.fireEvent('bodyresize', this, w, h);
11769 getToolbarHeight: function(){
11772 Ext.each(this.toolbars, function(tb){
11773 h += tb.getHeight();
11780 adjustBodyHeight : function(h){
11785 adjustBodyWidth : function(w){
11790 onPosition : function(){
11795 * Returns the width in pixels of the framing elements of this panel (not including the body width). To
11796 * retrieve the body width see {@link #getInnerWidth}.
11797 * @return {Number} The frame width
11799 getFrameWidth : function(){
11800 var w = this.el.getFrameWidth('lr') + this.bwrap.getFrameWidth('lr');
11803 var l = this.bwrap.dom.firstChild;
11804 w += (Ext.fly(l).getFrameWidth('l') + Ext.fly(l.firstChild).getFrameWidth('r'));
11805 w += this.mc.getFrameWidth('lr');
11811 * Returns the height in pixels of the framing elements of this panel (including any top and bottom bars and
11812 * header and footer elements, but not including the body height). To retrieve the body height see {@link #getInnerHeight}.
11813 * @return {Number} The frame height
11815 getFrameHeight : function() {
11816 var h = this.el.getFrameWidth('tb') + this.bwrap.getFrameWidth('tb');
11817 h += (this.tbar ? this.tbar.getHeight() : 0) +
11818 (this.bbar ? this.bbar.getHeight() : 0);
11821 h += this.el.dom.firstChild.offsetHeight + this.ft.dom.offsetHeight + this.mc.getFrameWidth('tb');
11823 h += (this.header ? this.header.getHeight() : 0) +
11824 (this.footer ? this.footer.getHeight() : 0);
11830 * Returns the width in pixels of the body element (not including the width of any framing elements).
11831 * For the frame width see {@link #getFrameWidth}.
11832 * @return {Number} The body width
11834 getInnerWidth : function(){
11835 return this.getSize().width - this.getFrameWidth();
11839 * Returns the height in pixels of the body element (not including the height of any framing elements).
11840 * For the frame height see {@link #getFrameHeight}.
11841 * @return {Number} The body height
11843 getInnerHeight : function(){
11844 return this.body.getHeight();
11846 return this.getSize().height - this.getFrameHeight();
11851 syncShadow : function(){
11853 this.el.sync(true);
11858 getLayoutTarget : function(){
11863 getContentTarget : function(){
11868 * <p>Sets the title text for the panel and optionally the {@link #iconCls icon class}.</p>
11869 * <p>In order to be able to set the title, a header element must have been created
11870 * for the Panel. This is triggered either by configuring the Panel with a non-blank <code>{@link #title}</code>,
11871 * or configuring it with <code><b>{@link #header}: true</b></code>.</p>
11872 * @param {String} title The title text to set
11873 * @param {String} iconCls (optional) {@link #iconCls iconCls} A user-defined CSS class that provides the icon image for this panel
11875 setTitle : function(title, iconCls){
11876 this.title = title;
11877 if(this.header && this.headerAsText){
11878 this.header.child('span').update(title);
11881 this.setIconClass(iconCls);
11883 this.fireEvent('titlechange', this, title);
11888 * Get the {@link Ext.Updater} for this panel. Enables you to perform Ajax updates of this panel's body.
11889 * @return {Ext.Updater} The Updater
11891 getUpdater : function(){
11892 return this.body.getUpdater();
11896 * Loads this content panel immediately with content returned from an XHR call.
11897 * @param {Object/String/Function} config A config object containing any of the following options:
11900 url: 'your-url.php',
11901 params: {param1: 'foo', param2: 'bar'}, // or a URL encoded string
11902 callback: yourFunction,
11903 scope: yourObject, // optional scope for the callback
11906 text: 'Loading...',
11911 * The only required property is url. The optional properties nocache, text and scripts
11912 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their
11913 * associated property on this panel Updater instance.
11914 * @return {Ext.Panel} this
11917 var um = this.body.getUpdater();
11918 um.update.apply(um, arguments);
11923 beforeDestroy : function(){
11924 Ext.Panel.superclass.beforeDestroy.call(this);
11926 this.header.removeAllListeners();
11929 for(var k in this.tools){
11930 Ext.destroy(this.tools[k]);
11933 if(this.toolbars.length > 0){
11934 Ext.each(this.toolbars, function(tb){
11935 tb.un('afterlayout', this.syncHeight, this);
11936 tb.un('remove', this.syncHeight, this);
11939 if(Ext.isArray(this.buttons)){
11940 while(this.buttons.length) {
11941 Ext.destroy(this.buttons[0]);
11963 Ext.destroy(this.toolbars);
11967 createClasses : function(){
11968 this.headerCls = this.baseCls + '-header';
11969 this.headerTextCls = this.baseCls + '-header-text';
11970 this.bwrapCls = this.baseCls + '-bwrap';
11971 this.tbarCls = this.baseCls + '-tbar';
11972 this.bodyCls = this.baseCls + '-body';
11973 this.bbarCls = this.baseCls + '-bbar';
11974 this.footerCls = this.baseCls + '-footer';
11978 createGhost : function(cls, useShim, appendTo){
11979 var el = document.createElement('div');
11980 el.className = 'x-panel-ghost ' + (cls ? cls : '');
11982 el.appendChild(this.el.dom.firstChild.cloneNode(true));
11984 Ext.fly(el.appendChild(document.createElement('ul'))).setHeight(this.bwrap.getHeight());
11985 el.style.width = this.el.dom.offsetWidth + 'px';;
11987 this.container.dom.appendChild(el);
11989 Ext.getDom(appendTo).appendChild(el);
11991 if(useShim !== false && this.el.useShim !== false){
11992 var layer = new Ext.Layer({shadow:false, useDisplay:true, constrain:false}, el);
11996 return new Ext.Element(el);
12001 doAutoLoad : function(){
12002 var u = this.body.getUpdater();
12004 u.setRenderer(this.renderer);
12006 u.update(Ext.isObject(this.autoLoad) ? this.autoLoad : {url: this.autoLoad});
12010 * Retrieve a tool by id.
12011 * @param {String} id
12012 * @return {Object} tool
12014 getTool : function(id) {
12015 return this.tools[id];
12019 * @cfg {String} autoEl @hide
12022 Ext.reg('panel', Ext.Panel);
12024 * @class Ext.Editor
12025 * @extends Ext.Component
12026 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
12028 * Create a new Editor
12029 * @param {Object} config The config object
12032 Ext.Editor = function(field, config){
12034 this.field = Ext.create(field.field, 'textfield');
12035 config = Ext.apply({}, field); // copy so we don't disturb original config
12036 delete config.field;
12038 this.field = field;
12040 Ext.Editor.superclass.constructor.call(this, config);
12043 Ext.extend(Ext.Editor, Ext.Component, {
12045 * @cfg {Ext.form.Field} field
12046 * The Field object (or descendant) or config object for field
12049 * @cfg {Boolean} allowBlur
12050 * True to {@link #completeEdit complete the editing process} if in edit mode when the
12051 * field is blurred. Defaults to <tt>true</tt>.
12055 * @cfg {Boolean/String} autoSize
12056 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
12057 * or "height" to adopt the height only, "none" to always use the field dimensions. (defaults to false)
12060 * @cfg {Boolean} revertInvalid
12061 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
12062 * validation fails (defaults to true)
12065 * @cfg {Boolean} ignoreNoChange
12066 * True to skip the edit completion process (no save, no events fired) if the user completes an edit and
12067 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
12068 * will never be ignored.
12071 * @cfg {Boolean} hideEl
12072 * False to keep the bound element visible while the editor is displayed (defaults to true)
12075 * @cfg {Mixed} value
12076 * The data value of the underlying field (defaults to "")
12080 * @cfg {String} alignment
12081 * The position to align to (see {@link Ext.Element#alignTo} for more details, defaults to "c-c?").
12085 * @cfg {Array} offsets
12086 * The offsets to use when aligning (see {@link Ext.Element#alignTo} for more details. Defaults to <tt>[0, 0]</tt>.
12090 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
12091 * for bottom-right shadow (defaults to "frame")
12095 * @cfg {Boolean} constrain True to constrain the editor to the viewport
12099 * @cfg {Boolean} swallowKeys Handle the keydown/keypress events so they don't propagate (defaults to true)
12101 swallowKeys : true,
12103 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed. Defaults to <tt>true</tt>.
12105 completeOnEnter : true,
12107 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed. Defaults to <tt>true</tt>.
12109 cancelOnEsc : true,
12111 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
12115 initComponent : function(){
12116 Ext.Editor.superclass.initComponent.call(this);
12119 * @event beforestartedit
12120 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
12121 * false from the handler of this event.
12122 * @param {Editor} this
12123 * @param {Ext.Element} boundEl The underlying element bound to this editor
12124 * @param {Mixed} value The field value being set
12129 * Fires when this editor is displayed
12130 * @param {Ext.Element} boundEl The underlying element bound to this editor
12131 * @param {Mixed} value The starting field value
12135 * @event beforecomplete
12136 * Fires after a change has been made to the field, but before the change is reflected in the underlying
12137 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
12138 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
12139 * event will not fire since no edit actually occurred.
12140 * @param {Editor} this
12141 * @param {Mixed} value The current field value
12142 * @param {Mixed} startValue The original field value
12147 * Fires after editing is complete and any changed value has been written to the underlying field.
12148 * @param {Editor} this
12149 * @param {Mixed} value The current field value
12150 * @param {Mixed} startValue The original field value
12154 * @event canceledit
12155 * Fires after editing has been canceled and the editor's value has been reset.
12156 * @param {Editor} this
12157 * @param {Mixed} value The user-entered field value that was discarded
12158 * @param {Mixed} startValue The original field value that was set back into the editor after cancel
12162 * @event specialkey
12163 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
12164 * {@link Ext.EventObject#getKey} to determine which key was pressed.
12165 * @param {Ext.form.Field} this
12166 * @param {Ext.EventObject} e The event object
12173 onRender : function(ct, position){
12174 this.el = new Ext.Layer({
12175 shadow: this.shadow,
12179 shadowOffset: this.shadowOffset || 4,
12181 constrain: this.constrain
12184 this.el.setZIndex(this.zIndex);
12186 this.el.setStyle("overflow", Ext.isGecko ? "auto" : "hidden");
12187 if(this.field.msgTarget != 'title'){
12188 this.field.msgTarget = 'qtip';
12190 this.field.inEditor = true;
12191 this.mon(this.field, {
12194 specialkey: this.onSpecialKey
12196 if(this.field.grow){
12197 this.mon(this.field, "autosize", this.el.sync, this.el, {delay:1});
12199 this.field.render(this.el).show();
12200 this.field.getEl().dom.name = '';
12201 if(this.swallowKeys){
12202 this.field.el.swallowEvent([
12203 'keypress', // *** Opera
12204 'keydown' // *** all other browsers
12210 onSpecialKey : function(field, e){
12211 var key = e.getKey(),
12212 complete = this.completeOnEnter && key == e.ENTER,
12213 cancel = this.cancelOnEsc && key == e.ESC;
12214 if(complete || cancel){
12217 this.completeEdit();
12221 if(field.triggerBlur){
12222 field.triggerBlur();
12225 this.fireEvent('specialkey', field, e);
12229 * Starts the editing process and shows the editor.
12230 * @param {Mixed} el The element to edit
12231 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
12232 * to the innerHTML of el.
12234 startEdit : function(el, value){
12236 this.completeEdit();
12238 this.boundEl = Ext.get(el);
12239 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
12240 if(!this.rendered){
12241 this.render(this.parentEl || document.body);
12243 if(this.fireEvent("beforestartedit", this, this.boundEl, v) !== false){
12244 this.startValue = v;
12245 this.field.reset();
12246 this.field.setValue(v);
12247 this.realign(true);
12248 this.editing = true;
12254 doAutoSize : function(){
12256 var sz = this.boundEl.getSize(),
12257 fs = this.field.getSize();
12259 switch(this.autoSize){
12261 this.setSize(sz.width, fs.height);
12264 this.setSize(fs.width, sz.height);
12267 this.setSize(fs.width, fs.height);
12270 this.setSize(sz.width, sz.height);
12276 * Sets the height and width of this editor.
12277 * @param {Number} width The new width
12278 * @param {Number} height The new height
12280 setSize : function(w, h){
12281 delete this.field.lastSize;
12282 this.field.setSize(w, h);
12284 // IE7 in strict mode doesn't size properly.
12285 if(Ext.isGecko2 || Ext.isOpera || (Ext.isIE7 && Ext.isStrict)){
12286 // prevent layer scrollbars
12287 this.el.setSize(w, h);
12294 * Realigns the editor to the bound field based on the current alignment config value.
12295 * @param {Boolean} autoSize (optional) True to size the field to the dimensions of the bound element.
12297 realign : function(autoSize){
12298 if(autoSize === true){
12301 this.el.alignTo(this.boundEl, this.alignment, this.offsets);
12305 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
12306 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
12308 completeEdit : function(remainVisible){
12312 // Assert combo values first
12313 if (this.field.assertValue) {
12314 this.field.assertValue();
12316 var v = this.getValue();
12317 if(!this.field.isValid()){
12318 if(this.revertInvalid !== false){
12319 this.cancelEdit(remainVisible);
12323 if(String(v) === String(this.startValue) && this.ignoreNoChange){
12324 this.hideEdit(remainVisible);
12327 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
12328 v = this.getValue();
12329 if(this.updateEl && this.boundEl){
12330 this.boundEl.update(v);
12332 this.hideEdit(remainVisible);
12333 this.fireEvent("complete", this, v, this.startValue);
12338 onShow : function(){
12340 if(this.hideEl !== false){
12341 this.boundEl.hide();
12343 this.field.show().focus(false, true);
12344 this.fireEvent("startedit", this.boundEl, this.startValue);
12348 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
12349 * reverted to the original starting value.
12350 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
12351 * cancel (defaults to false)
12353 cancelEdit : function(remainVisible){
12355 var v = this.getValue();
12356 this.setValue(this.startValue);
12357 this.hideEdit(remainVisible);
12358 this.fireEvent("canceledit", this, v, this.startValue);
12363 hideEdit: function(remainVisible){
12364 if(remainVisible !== true){
12365 this.editing = false;
12371 onBlur : function(){
12372 // selectSameEditor flag allows the same editor to be started without onBlur firing on itself
12373 if(this.allowBlur === true && this.editing && this.selectSameEditor !== true){
12374 this.completeEdit();
12379 onHide : function(){
12381 this.completeEdit();
12385 if(this.field.collapse){
12386 this.field.collapse();
12389 if(this.hideEl !== false){
12390 this.boundEl.show();
12395 * Sets the data value of the editor
12396 * @param {Mixed} value Any valid value supported by the underlying field
12398 setValue : function(v){
12399 this.field.setValue(v);
12403 * Gets the data value of the editor
12404 * @return {Mixed} The data value
12406 getValue : function(){
12407 return this.field.getValue();
12410 beforeDestroy : function(){
12411 Ext.destroyMembers(this, 'field');
12413 delete this.parentEl;
12414 delete this.boundEl;
12417 Ext.reg('editor', Ext.Editor);
12419 * @class Ext.ColorPalette
12420 * @extends Ext.Component
12421 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
12422 * Here's an example of typical usage:
12424 var cp = new Ext.ColorPalette({value:'993300'}); // initial selected color
12425 cp.render('my-div');
12427 cp.on('select', function(palette, selColor){
12428 // do something with selColor
12432 * Create a new ColorPalette
12433 * @param {Object} config The config object
12434 * @xtype colorpalette
12436 Ext.ColorPalette = Ext.extend(Ext.Component, {
12438 * @cfg {String} tpl An existing XTemplate instance to be used in place of the default template for rendering the component.
12441 * @cfg {String} itemCls
12442 * The CSS class to apply to the containing element (defaults to 'x-color-palette')
12444 itemCls : 'x-color-palette',
12446 * @cfg {String} value
12447 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
12448 * the hex codes are case-sensitive.
12452 * @cfg {String} clickEvent
12453 * The DOM event that will cause a color to be selected. This can be any valid event name (dblclick, contextmenu).
12454 * Defaults to <tt>'click'</tt>.
12456 clickEvent :'click',
12458 ctype : 'Ext.ColorPalette',
12461 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the {@link #select} event
12463 allowReselect : false,
12466 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
12467 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
12468 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
12469 * of colors with the width setting until the box is symmetrical.</p>
12470 * <p>You can override individual colors if needed:</p>
12472 var cp = new Ext.ColorPalette();
12473 cp.colors[0] = 'FF0000'; // change the first box to red
12476 Or you can provide a custom array of your own for complete control:
12478 var cp = new Ext.ColorPalette();
12479 cp.colors = ['000000', '993300', '333300'];
12484 '000000', '993300', '333300', '003300', '003366', '000080', '333399', '333333',
12485 '800000', 'FF6600', '808000', '008000', '008080', '0000FF', '666699', '808080',
12486 'FF0000', 'FF9900', '99CC00', '339966', '33CCCC', '3366FF', '800080', '969696',
12487 'FF00FF', 'FFCC00', 'FFFF00', '00FF00', '00FFFF', '00CCFF', '993366', 'C0C0C0',
12488 'FF99CC', 'FFCC99', 'FFFF99', 'CCFFCC', 'CCFFFF', '99CCFF', 'CC99FF', 'FFFFFF'
12492 * @cfg {Function} handler
12493 * Optional. A function that will handle the select event of this palette.
12494 * The handler is passed the following parameters:<div class="mdetail-params"><ul>
12495 * <li><code>palette</code> : ColorPalette<div class="sub-desc">The {@link #palette Ext.ColorPalette}.</div></li>
12496 * <li><code>color</code> : String<div class="sub-desc">The 6-digit color hex code (without the # symbol).</div></li>
12500 * @cfg {Object} scope
12501 * The scope (<tt><b>this</b></tt> reference) in which the <code>{@link #handler}</code>
12502 * function will be called. Defaults to this ColorPalette instance.
12506 initComponent : function(){
12507 Ext.ColorPalette.superclass.initComponent.call(this);
12511 * Fires when a color is selected
12512 * @param {ColorPalette} this
12513 * @param {String} color The 6-digit color hex code (without the # symbol)
12519 this.on('select', this.handler, this.scope, true);
12524 onRender : function(container, position){
12529 Ext.ColorPalette.superclass.onRender.call(this, container, position);
12530 var t = this.tpl || new Ext.XTemplate(
12531 '<tpl for="."><a href="#" class="color-{.}" hidefocus="on"><em><span style="background:#{.}" unselectable="on"> </span></em></a></tpl>'
12533 t.overwrite(this.el, this.colors);
12534 this.mon(this.el, this.clickEvent, this.handleClick, this, {delegate: 'a'});
12535 if(this.clickEvent != 'click'){
12536 this.mon(this.el, 'click', Ext.emptyFn, this, {delegate: 'a', preventDefault: true});
12541 afterRender : function(){
12542 Ext.ColorPalette.superclass.afterRender.call(this);
12544 var s = this.value;
12546 this.select(s, true);
12551 handleClick : function(e, t){
12552 e.preventDefault();
12553 if(!this.disabled){
12554 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
12555 this.select(c.toUpperCase());
12560 * Selects the specified color in the palette (fires the {@link #select} event)
12561 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
12562 * @param {Boolean} suppressEvent (optional) True to stop the select event from firing. Defaults to <tt>false</tt>.
12564 select : function(color, suppressEvent){
12565 color = color.replace('#', '');
12566 if(color != this.value || this.allowReselect){
12569 el.child('a.color-'+this.value).removeClass('x-color-palette-sel');
12571 el.child('a.color-'+color).addClass('x-color-palette-sel');
12572 this.value = color;
12573 if(suppressEvent !== true){
12574 this.fireEvent('select', this, color);
12580 * @cfg {String} autoEl @hide
12583 Ext.reg('colorpalette', Ext.ColorPalette);/**
12584 * @class Ext.DatePicker
12585 * @extends Ext.Component
12586 * <p>A popup date picker. This class is used by the {@link Ext.form.DateField DateField} class
12587 * to allow browsing and selection of valid dates.</p>
12588 * <p>All the string values documented below may be overridden by including an Ext locale file in
12591 * Create a new DatePicker
12592 * @param {Object} config The config object
12593 * @xtype datepicker
12595 Ext.DatePicker = Ext.extend(Ext.BoxComponent, {
12597 * @cfg {String} todayText
12598 * The text to display on the button that selects the current date (defaults to <code>'Today'</code>)
12600 todayText : 'Today',
12602 * @cfg {String} okText
12603 * The text to display on the ok button (defaults to <code>' OK '</code> to give the user extra clicking room)
12605 okText : ' OK ',
12607 * @cfg {String} cancelText
12608 * The text to display on the cancel button (defaults to <code>'Cancel'</code>)
12610 cancelText : 'Cancel',
12612 * @cfg {Function} handler
12613 * Optional. A function that will handle the select event of this picker.
12614 * The handler is passed the following parameters:<div class="mdetail-params"><ul>
12615 * <li><code>picker</code> : DatePicker<div class="sub-desc">This DatePicker.</div></li>
12616 * <li><code>date</code> : Date<div class="sub-desc">The selected date.</div></li>
12620 * @cfg {Object} scope
12621 * The scope (<code><b>this</b></code> reference) in which the <code>{@link #handler}</code>
12622 * function will be called. Defaults to this DatePicker instance.
12625 * @cfg {String} todayTip
12626 * A string used to format the message for displaying in a tooltip over the button that
12627 * selects the current date. Defaults to <code>'{0} (Spacebar)'</code> where
12628 * the <code>{0}</code> token is replaced by today's date.
12630 todayTip : '{0} (Spacebar)',
12632 * @cfg {String} minText
12633 * The error text to display if the minDate validation fails (defaults to <code>'This date is before the minimum date'</code>)
12635 minText : 'This date is before the minimum date',
12637 * @cfg {String} maxText
12638 * The error text to display if the maxDate validation fails (defaults to <code>'This date is after the maximum date'</code>)
12640 maxText : 'This date is after the maximum date',
12642 * @cfg {String} format
12643 * The default date format string which can be overriden for localization support. The format must be
12644 * valid according to {@link Date#parseDate} (defaults to <code>'m/d/y'</code>).
12648 * @cfg {String} disabledDaysText
12649 * The tooltip to display when the date falls on a disabled day (defaults to <code>'Disabled'</code>)
12651 disabledDaysText : 'Disabled',
12653 * @cfg {String} disabledDatesText
12654 * The tooltip text to display when the date falls on a disabled date (defaults to <code>'Disabled'</code>)
12656 disabledDatesText : 'Disabled',
12658 * @cfg {Array} monthNames
12659 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
12661 monthNames : Date.monthNames,
12663 * @cfg {Array} dayNames
12664 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
12666 dayNames : Date.dayNames,
12668 * @cfg {String} nextText
12669 * The next month navigation button tooltip (defaults to <code>'Next Month (Control+Right)'</code>)
12671 nextText : 'Next Month (Control+Right)',
12673 * @cfg {String} prevText
12674 * The previous month navigation button tooltip (defaults to <code>'Previous Month (Control+Left)'</code>)
12676 prevText : 'Previous Month (Control+Left)',
12678 * @cfg {String} monthYearText
12679 * The header month selector tooltip (defaults to <code>'Choose a month (Control+Up/Down to move years)'</code>)
12681 monthYearText : 'Choose a month (Control+Up/Down to move years)',
12683 * @cfg {Number} startDay
12684 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12688 * @cfg {Boolean} showToday
12689 * False to hide the footer area containing the Today button and disable the keyboard handler for spacebar
12690 * that selects the current date (defaults to <code>true</code>).
12694 * @cfg {Date} minDate
12695 * Minimum allowable date (JavaScript date object, defaults to null)
12698 * @cfg {Date} maxDate
12699 * Maximum allowable date (JavaScript date object, defaults to null)
12702 * @cfg {Array} disabledDays
12703 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
12706 * @cfg {RegExp} disabledDatesRE
12707 * JavaScript regular expression used to disable a pattern of dates (defaults to null). The {@link #disabledDates}
12708 * config will generate this regex internally, but if you specify disabledDatesRE it will take precedence over the
12709 * disabledDates value.
12712 * @cfg {Array} disabledDates
12713 * An array of 'dates' to disable, as strings. These strings will be used to build a dynamic regular
12714 * expression so they are very powerful. Some examples:
12716 * <li>['03/08/2003', '09/16/2003'] would disable those exact dates</li>
12717 * <li>['03/08', '09/16'] would disable those days for every year</li>
12718 * <li>['^03/08'] would only match the beginning (useful if you are using short years)</li>
12719 * <li>['03/../2006'] would disable every day in March 2006</li>
12720 * <li>['^03'] would disable every day in every March</li>
12722 * Note that the format of the dates included in the array should exactly match the {@link #format} config.
12723 * In order to support regular expressions, if you are using a date format that has '.' in it, you will have to
12724 * escape the dot when restricting dates. For example: ['03\\.08\\.03'].
12728 // Set by other components to stop the picker focus being updated when the value changes.
12729 focusOnSelect: true,
12731 // default value used to initialise each date in the DatePicker
12732 // (note: 12 noon was chosen because it steers well clear of all DST timezone changes)
12733 initHour: 12, // 24-hour format
12736 initComponent : function(){
12737 Ext.DatePicker.superclass.initComponent.call(this);
12739 this.value = this.value ?
12740 this.value.clearTime(true) : new Date().clearTime();
12745 * Fires when a date is selected
12746 * @param {DatePicker} this DatePicker
12747 * @param {Date} date The selected date
12753 this.on('select', this.handler, this.scope || this);
12756 this.initDisabledDays();
12760 initDisabledDays : function(){
12761 if(!this.disabledDatesRE && this.disabledDates){
12762 var dd = this.disabledDates,
12763 len = dd.length - 1,
12766 Ext.each(dd, function(d, i){
12767 re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i];
12772 this.disabledDatesRE = new RegExp(re + ')');
12777 * Replaces any existing disabled dates with new values and refreshes the DatePicker.
12778 * @param {Array/RegExp} disabledDates An array of date strings (see the {@link #disabledDates} config
12779 * for details on supported values), or a JavaScript regular expression used to disable a pattern of dates.
12781 setDisabledDates : function(dd){
12782 if(Ext.isArray(dd)){
12783 this.disabledDates = dd;
12784 this.disabledDatesRE = null;
12786 this.disabledDatesRE = dd;
12788 this.initDisabledDays();
12789 this.update(this.value, true);
12793 * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.
12794 * @param {Array} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config
12795 * for details on supported values.
12797 setDisabledDays : function(dd){
12798 this.disabledDays = dd;
12799 this.update(this.value, true);
12803 * Replaces any existing {@link #minDate} with the new value and refreshes the DatePicker.
12804 * @param {Date} value The minimum date that can be selected
12806 setMinDate : function(dt){
12808 this.update(this.value, true);
12812 * Replaces any existing {@link #maxDate} with the new value and refreshes the DatePicker.
12813 * @param {Date} value The maximum date that can be selected
12815 setMaxDate : function(dt){
12817 this.update(this.value, true);
12821 * Sets the value of the date field
12822 * @param {Date} value The date to set
12824 setValue : function(value){
12825 this.value = value.clearTime(true);
12826 this.update(this.value);
12830 * Gets the current selected value of the date field
12831 * @return {Date} The selected date
12833 getValue : function(){
12838 focus : function(){
12839 this.update(this.activeDate);
12843 onEnable: function(initial){
12844 Ext.DatePicker.superclass.onEnable.call(this);
12845 this.doDisabled(false);
12846 this.update(initial ? this.value : this.activeDate);
12854 onDisable : function(){
12855 Ext.DatePicker.superclass.onDisable.call(this);
12856 this.doDisabled(true);
12857 if(Ext.isIE && !Ext.isIE8){
12858 /* Really strange problem in IE6/7, when disabled, have to explicitly
12859 * repaint each of the nodes to get them to display correctly, simply
12860 * calling repaint on the main element doesn't appear to be enough.
12862 Ext.each([].concat(this.textNodes, this.el.query('th span')), function(el){
12863 Ext.fly(el).repaint();
12869 doDisabled : function(disabled){
12870 this.keyNav.setDisabled(disabled);
12871 this.prevRepeater.setDisabled(disabled);
12872 this.nextRepeater.setDisabled(disabled);
12873 if(this.showToday){
12874 this.todayKeyListener.setDisabled(disabled);
12875 this.todayBtn.setDisabled(disabled);
12880 onRender : function(container, position){
12882 '<table cellspacing="0">',
12883 '<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>',
12884 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'],
12885 dn = this.dayNames,
12887 for(i = 0; i < 7; i++){
12888 var d = this.startDay+i;
12892 m.push('<th><span>', dn[d].substr(0,1), '</span></th>');
12894 m[m.length] = '</tr></thead><tbody><tr>';
12895 for(i = 0; i < 42; i++) {
12896 if(i % 7 === 0 && i !== 0){
12897 m[m.length] = '</tr><tr>';
12899 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
12901 m.push('</tr></tbody></table></td></tr>',
12902 this.showToday ? '<tr><td colspan="3" class="x-date-bottom" align="center"></td></tr>' : '',
12903 '</table><div class="x-date-mp"></div>');
12905 var el = document.createElement('div');
12906 el.className = 'x-date-picker';
12907 el.innerHTML = m.join('');
12909 container.dom.insertBefore(el, position);
12911 this.el = Ext.get(el);
12912 this.eventEl = Ext.get(el.firstChild);
12914 this.prevRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-left a'), {
12915 handler: this.showPrevMonth,
12917 preventDefault:true,
12921 this.nextRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-right a'), {
12922 handler: this.showNextMonth,
12924 preventDefault:true,
12928 this.monthPicker = this.el.down('div.x-date-mp');
12929 this.monthPicker.enableDisplayMode('block');
12931 this.keyNav = new Ext.KeyNav(this.eventEl, {
12932 'left' : function(e){
12934 this.showPrevMonth();
12936 this.update(this.activeDate.add('d', -1));
12940 'right' : function(e){
12942 this.showNextMonth();
12944 this.update(this.activeDate.add('d', 1));
12948 'up' : function(e){
12950 this.showNextYear();
12952 this.update(this.activeDate.add('d', -7));
12956 'down' : function(e){
12958 this.showPrevYear();
12960 this.update(this.activeDate.add('d', 7));
12964 'pageUp' : function(e){
12965 this.showNextMonth();
12968 'pageDown' : function(e){
12969 this.showPrevMonth();
12972 'enter' : function(e){
12973 e.stopPropagation();
12980 this.el.unselectable();
12982 this.cells = this.el.select('table.x-date-inner tbody td');
12983 this.textNodes = this.el.query('table.x-date-inner tbody span');
12985 this.mbtn = new Ext.Button({
12987 tooltip: this.monthYearText,
12988 renderTo: this.el.child('td.x-date-middle', true)
12990 this.mbtn.el.child('em').addClass('x-btn-arrow');
12992 if(this.showToday){
12993 this.todayKeyListener = this.eventEl.addKeyListener(Ext.EventObject.SPACE, this.selectToday, this);
12994 var today = (new Date()).dateFormat(this.format);
12995 this.todayBtn = new Ext.Button({
12996 renderTo: this.el.child('td.x-date-bottom', true),
12997 text: String.format(this.todayText, today),
12998 tooltip: String.format(this.todayTip, today),
12999 handler: this.selectToday,
13003 this.mon(this.eventEl, 'mousewheel', this.handleMouseWheel, this);
13004 this.mon(this.eventEl, 'click', this.handleDateClick, this, {delegate: 'a.x-date-date'});
13005 this.mon(this.mbtn, 'click', this.showMonthPicker, this);
13006 this.onEnable(true);
13010 createMonthPicker : function(){
13011 if(!this.monthPicker.dom.firstChild){
13012 var buf = ['<table border="0" cellspacing="0">'];
13013 for(var i = 0; i < 6; i++){
13015 '<tr><td class="x-date-mp-month"><a href="#">', Date.getShortMonthName(i), '</a></td>',
13016 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', Date.getShortMonthName(i + 6), '</a></td>',
13018 '<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>' :
13019 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
13023 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
13025 '</button><button type="button" class="x-date-mp-cancel">',
13027 '</button></td></tr>',
13030 this.monthPicker.update(buf.join(''));
13032 this.mon(this.monthPicker, 'click', this.onMonthClick, this);
13033 this.mon(this.monthPicker, 'dblclick', this.onMonthDblClick, this);
13035 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
13036 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
13038 this.mpMonths.each(function(m, a, i){
13041 m.dom.xmonth = 5 + Math.round(i * 0.5);
13043 m.dom.xmonth = Math.round((i-1) * 0.5);
13050 showMonthPicker : function(){
13051 if(!this.disabled){
13052 this.createMonthPicker();
13053 var size = this.el.getSize();
13054 this.monthPicker.setSize(size);
13055 this.monthPicker.child('table').setSize(size);
13057 this.mpSelMonth = (this.activeDate || this.value).getMonth();
13058 this.updateMPMonth(this.mpSelMonth);
13059 this.mpSelYear = (this.activeDate || this.value).getFullYear();
13060 this.updateMPYear(this.mpSelYear);
13062 this.monthPicker.slideIn('t', {duration:0.2});
13067 updateMPYear : function(y){
13069 var ys = this.mpYears.elements;
13070 for(var i = 1; i <= 10; i++){
13071 var td = ys[i-1], y2;
13073 y2 = y + Math.round(i * 0.5);
13074 td.firstChild.innerHTML = y2;
13077 y2 = y - (5-Math.round(i * 0.5));
13078 td.firstChild.innerHTML = y2;
13081 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
13086 updateMPMonth : function(sm){
13087 this.mpMonths.each(function(m, a, i){
13088 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
13093 selectMPMonth : function(m){
13098 onMonthClick : function(e, t){
13100 var el = new Ext.Element(t), pn;
13101 if(el.is('button.x-date-mp-cancel')){
13102 this.hideMonthPicker();
13104 else if(el.is('button.x-date-mp-ok')){
13105 var d = new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate());
13106 if(d.getMonth() != this.mpSelMonth){
13107 // 'fix' the JS rolling date conversion if needed
13108 d = new Date(this.mpSelYear, this.mpSelMonth, 1).getLastDateOfMonth();
13111 this.hideMonthPicker();
13113 else if((pn = el.up('td.x-date-mp-month', 2))){
13114 this.mpMonths.removeClass('x-date-mp-sel');
13115 pn.addClass('x-date-mp-sel');
13116 this.mpSelMonth = pn.dom.xmonth;
13118 else if((pn = el.up('td.x-date-mp-year', 2))){
13119 this.mpYears.removeClass('x-date-mp-sel');
13120 pn.addClass('x-date-mp-sel');
13121 this.mpSelYear = pn.dom.xyear;
13123 else if(el.is('a.x-date-mp-prev')){
13124 this.updateMPYear(this.mpyear-10);
13126 else if(el.is('a.x-date-mp-next')){
13127 this.updateMPYear(this.mpyear+10);
13132 onMonthDblClick : function(e, t){
13134 var el = new Ext.Element(t), pn;
13135 if((pn = el.up('td.x-date-mp-month', 2))){
13136 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
13137 this.hideMonthPicker();
13139 else if((pn = el.up('td.x-date-mp-year', 2))){
13140 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
13141 this.hideMonthPicker();
13146 hideMonthPicker : function(disableAnim){
13147 if(this.monthPicker){
13148 if(disableAnim === true){
13149 this.monthPicker.hide();
13151 this.monthPicker.slideOut('t', {duration:0.2});
13157 showPrevMonth : function(e){
13158 this.update(this.activeDate.add('mo', -1));
13162 showNextMonth : function(e){
13163 this.update(this.activeDate.add('mo', 1));
13167 showPrevYear : function(){
13168 this.update(this.activeDate.add('y', -1));
13172 showNextYear : function(){
13173 this.update(this.activeDate.add('y', 1));
13177 handleMouseWheel : function(e){
13179 if(!this.disabled){
13180 var delta = e.getWheelDelta();
13182 this.showPrevMonth();
13183 } else if(delta < 0){
13184 this.showNextMonth();
13190 handleDateClick : function(e, t){
13192 if(!this.disabled && t.dateValue && !Ext.fly(t.parentNode).hasClass('x-date-disabled')){
13193 this.cancelFocus = this.focusOnSelect === false;
13194 this.setValue(new Date(t.dateValue));
13195 delete this.cancelFocus;
13196 this.fireEvent('select', this, this.value);
13201 selectToday : function(){
13202 if(this.todayBtn && !this.todayBtn.disabled){
13203 this.setValue(new Date().clearTime());
13204 this.fireEvent('select', this, this.value);
13209 update : function(date, forceRefresh){
13211 var vd = this.activeDate, vis = this.isVisible();
13212 this.activeDate = date;
13213 if(!forceRefresh && vd && this.el){
13214 var t = date.getTime();
13215 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13216 this.cells.removeClass('x-date-selected');
13217 this.cells.each(function(c){
13218 if(c.dom.firstChild.dateValue == t){
13219 c.addClass('x-date-selected');
13220 if(vis && !this.cancelFocus){
13221 Ext.fly(c.dom.firstChild).focus(50);
13229 var days = date.getDaysInMonth(),
13230 firstOfMonth = date.getFirstDateOfMonth(),
13231 startingPos = firstOfMonth.getDay()-this.startDay;
13233 if(startingPos < 0){
13236 days += startingPos;
13238 var pm = date.add('mo', -1),
13239 prevStart = pm.getDaysInMonth()-startingPos,
13240 cells = this.cells.elements,
13241 textEls = this.textNodes,
13242 // convert everything to numbers so it's fast
13243 d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart, this.initHour)),
13244 today = new Date().clearTime().getTime(),
13245 sel = date.clearTime(true).getTime(),
13246 min = this.minDate ? this.minDate.clearTime(true) : Number.NEGATIVE_INFINITY,
13247 max = this.maxDate ? this.maxDate.clearTime(true) : Number.POSITIVE_INFINITY,
13248 ddMatch = this.disabledDatesRE,
13249 ddText = this.disabledDatesText,
13250 ddays = this.disabledDays ? this.disabledDays.join('') : false,
13251 ddaysText = this.disabledDaysText,
13252 format = this.format;
13254 if(this.showToday){
13255 var td = new Date().clearTime(),
13256 disable = (td < min || td > max ||
13257 (ddMatch && format && ddMatch.test(td.dateFormat(format))) ||
13258 (ddays && ddays.indexOf(td.getDay()) != -1));
13260 if(!this.disabled){
13261 this.todayBtn.setDisabled(disable);
13262 this.todayKeyListener[disable ? 'disable' : 'enable']();
13266 var setCellClass = function(cal, cell){
13268 var t = d.clearTime(true).getTime();
13269 cell.firstChild.dateValue = t;
13271 cell.className += ' x-date-today';
13272 cell.title = cal.todayText;
13275 cell.className += ' x-date-selected';
13277 Ext.fly(cell.firstChild).focus(50);
13282 cell.className = ' x-date-disabled';
13283 cell.title = cal.minText;
13287 cell.className = ' x-date-disabled';
13288 cell.title = cal.maxText;
13292 if(ddays.indexOf(d.getDay()) != -1){
13293 cell.title = ddaysText;
13294 cell.className = ' x-date-disabled';
13297 if(ddMatch && format){
13298 var fvalue = d.dateFormat(format);
13299 if(ddMatch.test(fvalue)){
13300 cell.title = ddText.replace('%0', fvalue);
13301 cell.className = ' x-date-disabled';
13307 for(; i < startingPos; i++) {
13308 textEls[i].innerHTML = (++prevStart);
13309 d.setDate(d.getDate()+1);
13310 cells[i].className = 'x-date-prevday';
13311 setCellClass(this, cells[i]);
13313 for(; i < days; i++){
13314 var intDay = i - startingPos + 1;
13315 textEls[i].innerHTML = (intDay);
13316 d.setDate(d.getDate()+1);
13317 cells[i].className = 'x-date-active';
13318 setCellClass(this, cells[i]);
13321 for(; i < 42; i++) {
13322 textEls[i].innerHTML = (++extraDays);
13323 d.setDate(d.getDate()+1);
13324 cells[i].className = 'x-date-nextday';
13325 setCellClass(this, cells[i]);
13328 this.mbtn.setText(this.monthNames[date.getMonth()] + ' ' + date.getFullYear());
13330 if(!this.internalRender){
13331 var main = this.el.dom.firstChild,
13332 w = main.offsetWidth;
13333 this.el.setWidth(w + this.el.getBorderWidth('lr'));
13334 Ext.fly(main).setWidth(w);
13335 this.internalRender = true;
13336 // opera does not respect the auto grow header center column
13337 // then, after it gets a width opera refuses to recalculate
13338 // without a second pass
13339 if(Ext.isOpera && !this.secondPass){
13340 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + 'px';
13341 this.secondPass = true;
13342 this.update.defer(10, this, [date]);
13349 beforeDestroy : function() {
13361 delete this.textNodes;
13362 delete this.cells.elements;
13367 * @cfg {String} autoEl @hide
13371 Ext.reg('datepicker', Ext.DatePicker);
13373 * @class Ext.LoadMask
13374 * A simple utility class for generically masking elements while loading data. If the {@link #store}
13375 * config option is specified, the masking will be automatically synchronized with the store's loading
13376 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
13377 * element's Updater load indicator and will be destroyed after the initial load.
13378 * <p>Example usage:</p>
13381 var myMask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait..."});
13385 * Create a new LoadMask
13386 * @param {Mixed} el The element or DOM node, or its id
13387 * @param {Object} config The config object
13389 Ext.LoadMask = function(el, config){
13390 this.el = Ext.get(el);
13391 Ext.apply(this, config);
13395 beforeload: this.onBeforeLoad,
13397 exception: this.onLoad
13399 this.removeMask = Ext.value(this.removeMask, false);
13401 var um = this.el.getUpdater();
13402 um.showLoadIndicator = false; // disable the default indicator
13405 beforeupdate: this.onBeforeLoad,
13406 update: this.onLoad,
13407 failure: this.onLoad
13409 this.removeMask = Ext.value(this.removeMask, true);
13413 Ext.LoadMask.prototype = {
13415 * @cfg {Ext.data.Store} store
13416 * Optional Store to which the mask is bound. The mask is displayed when a load request is issued, and
13417 * hidden on either load sucess, or load fail.
13420 * @cfg {Boolean} removeMask
13421 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
13422 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
13425 * @cfg {String} msg
13426 * The text to display in a centered loading message box (defaults to 'Loading...')
13428 msg : 'Loading...',
13430 * @cfg {String} msgCls
13431 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
13433 msgCls : 'x-mask-loading',
13436 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
13442 * Disables the mask to prevent it from being displayed
13444 disable : function(){
13445 this.disabled = true;
13449 * Enables the mask so that it can be displayed
13451 enable : function(){
13452 this.disabled = false;
13456 onLoad : function(){
13457 this.el.unmask(this.removeMask);
13461 onBeforeLoad : function(){
13462 if(!this.disabled){
13463 this.el.mask(this.msg, this.msgCls);
13468 * Show this LoadMask over the configured Element.
13471 this.onBeforeLoad();
13475 * Hide this LoadMask.
13482 destroy : function(){
13484 this.store.un('beforeload', this.onBeforeLoad, this);
13485 this.store.un('load', this.onLoad, this);
13486 this.store.un('exception', this.onLoad, this);
13488 var um = this.el.getUpdater();
13489 um.un('beforeupdate', this.onBeforeLoad, this);
13490 um.un('update', this.onLoad, this);
13491 um.un('failure', this.onLoad, this);
13494 };Ext.ns('Ext.slider');
13497 * @class Ext.slider.Thumb
13499 * Represents a single thumb element on a Slider. This would not usually be created manually and would instead
13500 * be created internally by an {@link Ext.slider.MultiSlider Ext.Slider}.
13502 Ext.slider.Thumb = Ext.extend(Object, {
13505 * True while the thumb is in a drag operation
13512 * @cfg {Ext.slider.MultiSlider} slider The Slider to render to (required)
13514 constructor: function(config) {
13517 * @type Ext.slider.MultiSlider
13518 * The slider this thumb is contained within
13520 Ext.apply(this, config || {}, {
13521 cls: 'x-slider-thumb',
13524 * @cfg {Boolean} constrain True to constrain the thumb so that it cannot overlap its siblings
13529 Ext.slider.Thumb.superclass.constructor.call(this, config);
13531 if (this.slider.vertical) {
13532 Ext.apply(this, Ext.slider.Thumb.Vertical);
13537 * Renders the thumb into a slider
13539 render: function() {
13540 this.el = this.slider.innerEl.insertFirst({cls: this.cls});
13546 * Enables the thumb if it is currently disabled
13548 enable: function() {
13549 this.disabled = false;
13550 this.el.removeClass(this.slider.disabledClass);
13554 * Disables the thumb if it is currently enabled
13556 disable: function() {
13557 this.disabled = true;
13558 this.el.addClass(this.slider.disabledClass);
13562 * Sets up an Ext.dd.DragTracker for this thumb
13564 initEvents: function() {
13567 el.addClassOnOver('x-slider-thumb-over');
13569 this.tracker = new Ext.dd.DragTracker({
13570 onBeforeStart: this.onBeforeDragStart.createDelegate(this),
13571 onStart : this.onDragStart.createDelegate(this),
13572 onDrag : this.onDrag.createDelegate(this),
13573 onEnd : this.onDragEnd.createDelegate(this),
13578 this.tracker.initEl(el);
13583 * This is tied into the internal Ext.dd.DragTracker. If the slider is currently disabled,
13584 * this returns false to disable the DragTracker too.
13585 * @return {Boolean} False if the slider is currently disabled
13587 onBeforeDragStart : function(e) {
13588 if (this.disabled) {
13591 this.slider.promoteThumb(this);
13598 * This is tied into the internal Ext.dd.DragTracker's onStart template method. Adds the drag CSS class
13599 * to the thumb and fires the 'dragstart' event
13601 onDragStart: function(e){
13602 this.el.addClass('x-slider-thumb-drag');
13603 this.dragging = true;
13604 this.dragStartValue = this.value;
13606 this.slider.fireEvent('dragstart', this.slider, e, this);
13611 * This is tied into the internal Ext.dd.DragTracker's onDrag template method. This is called every time
13612 * the DragTracker detects a drag movement. It updates the Slider's value using the position of the drag
13614 onDrag: function(e) {
13615 var slider = this.slider,
13616 index = this.index,
13617 newValue = this.getNewValue();
13619 if (this.constrain) {
13620 var above = slider.thumbs[index + 1],
13621 below = slider.thumbs[index - 1];
13623 if (below != undefined && newValue <= below.value) newValue = below.value;
13624 if (above != undefined && newValue >= above.value) newValue = above.value;
13627 slider.setValue(index, newValue, false);
13628 slider.fireEvent('drag', slider, e, this);
13631 getNewValue: function() {
13632 var slider = this.slider,
13633 pos = slider.innerEl.translatePoints(this.tracker.getXY());
13635 return Ext.util.Format.round(slider.reverseValue(pos.left), slider.decimalPrecision);
13640 * This is tied to the internal Ext.dd.DragTracker's onEnd template method. Removes the drag CSS class and
13641 * fires the 'changecomplete' event with the new value
13643 onDragEnd: function(e) {
13644 var slider = this.slider,
13645 value = this.value;
13647 this.el.removeClass('x-slider-thumb-drag');
13649 this.dragging = false;
13650 slider.fireEvent('dragend', slider, e);
13652 if (this.dragStartValue != value) {
13653 slider.fireEvent('changecomplete', slider, value, this);
13659 * Destroys the thumb
13661 destroy: function(){
13662 Ext.destroyMembers(this, 'tracker', 'el');
13667 * @class Ext.slider.MultiSlider
13668 * @extends Ext.BoxComponent
13669 * 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:
13672 renderTo: Ext.getBody(),
13680 * Sliders can be created with more than one thumb handle by passing an array of values instead of a single one:
13683 renderTo: Ext.getBody(),
13685 values: [25, 50, 75],
13689 //this defaults to true, setting to false allows the thumbs to pass each other
13690 {@link #constrainThumbs}: false
13694 Ext.slider.MultiSlider = Ext.extend(Ext.BoxComponent, {
13696 * @cfg {Number} value The value to initialize the slider with. Defaults to minValue.
13699 * @cfg {Boolean} vertical Orient the Slider vertically rather than horizontally, defaults to false.
13703 * @cfg {Number} minValue The minimum value for the Slider. Defaults to 0.
13707 * @cfg {Number} maxValue The maximum value for the Slider. Defaults to 100.
13711 * @cfg {Number/Boolean} decimalPrecision.
13712 * <p>The number of decimal places to which to round the Slider's value. Defaults to 0.</p>
13713 * <p>To disable rounding, configure as <tt><b>false</b></tt>.</p>
13715 decimalPrecision: 0,
13717 * @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.
13721 * @cfg {Number} increment How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'.
13727 * @property clickRange
13729 * 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],
13730 * 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'
13731 * 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
13733 clickRange: [5,15],
13736 * @cfg {Boolean} clickToChange Determines whether or not clicking on the Slider axis will change the slider. Defaults to true
13738 clickToChange : true,
13740 * @cfg {Boolean} animate Turn on or off animation. Defaults to true
13744 * @cfg {Boolean} constrainThumbs True to disallow thumbs from overlapping one another. Defaults to true
13746 constrainThumbs: true,
13750 * @property topThumbZIndex
13752 * The number used internally to set the z index of the top thumb (see promoteThumb for details)
13754 topThumbZIndex: 10000,
13756 // private override
13757 initComponent : function(){
13758 if(!Ext.isDefined(this.value)){
13759 this.value = this.minValue;
13765 * Array containing references to each thumb
13769 Ext.slider.MultiSlider.superclass.initComponent.call(this);
13771 this.keyIncrement = Math.max(this.increment, this.keyIncrement);
13774 * @event beforechange
13775 * Fires before the slider value is changed. By returning false from an event handler,
13776 * you can cancel the event and prevent the slider from changing.
13777 * @param {Ext.slider.MultiSlider} slider The slider
13778 * @param {Number} newValue The new value which the slider is being changed to.
13779 * @param {Number} oldValue The old value which the slider was previously.
13785 * Fires when the slider value is changed.
13786 * @param {Ext.slider.MultiSlider} slider The slider
13787 * @param {Number} newValue The new value which the slider has been changed to.
13788 * @param {Ext.slider.Thumb} thumb The thumb that was changed
13793 * @event changecomplete
13794 * Fires when the slider value is changed by the user and any drag operations have completed.
13795 * @param {Ext.slider.MultiSlider} slider The slider
13796 * @param {Number} newValue The new value which the slider has been changed to.
13797 * @param {Ext.slider.Thumb} thumb The thumb that was changed
13803 * Fires after a drag operation has started.
13804 * @param {Ext.slider.MultiSlider} slider The slider
13805 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
13811 * Fires continuously during the drag operation while the mouse is moving.
13812 * @param {Ext.slider.MultiSlider} slider The slider
13813 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
13819 * Fires after the drag operation has completed.
13820 * @param {Ext.slider.MultiSlider} slider The slider
13821 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
13829 * Array of values to initalize the thumbs with
13831 if (this.values == undefined || Ext.isEmpty(this.values)) this.values = [0];
13833 var values = this.values;
13835 for (var i=0; i < values.length; i++) {
13836 this.addThumb(values[i]);
13840 Ext.apply(this, Ext.slider.Vertical);
13845 * Creates a new thumb and adds it to the slider
13846 * @param {Number} value The initial value to set on the thumb. Defaults to 0
13848 addThumb: function(value) {
13849 var thumb = new Ext.slider.Thumb({
13852 index : this.thumbs.length,
13853 constrain: this.constrainThumbs
13855 this.thumbs.push(thumb);
13857 //render the thumb now if needed
13858 if (this.rendered) thumb.render();
13863 * Moves the given thumb above all other by increasing its z-index. This is called when as drag
13864 * any thumb, so that the thumb that was just dragged is always at the highest z-index. This is
13865 * required when the thumbs are stacked on top of each other at one of the ends of the slider's
13866 * range, which can result in the user not being able to move any of them.
13867 * @param {Ext.slider.Thumb} topThumb The thumb to move to the top
13869 promoteThumb: function(topThumb) {
13870 var thumbs = this.thumbs,
13873 for (var i = 0, j = thumbs.length; i < j; i++) {
13876 if (thumb == topThumb) {
13877 zIndex = this.topThumbZIndex;
13882 thumb.el.setStyle('zIndex', zIndex);
13886 // private override
13887 onRender : function() {
13889 cls: 'x-slider ' + (this.vertical ? 'x-slider-vert' : 'x-slider-horz'),
13891 cls: 'x-slider-end',
13893 cls:'x-slider-inner',
13894 cn : [{tag:'a', cls:'x-slider-focus', href:"#", tabIndex: '-1', hidefocus:'on'}]
13899 Ext.slider.MultiSlider.superclass.onRender.apply(this, arguments);
13901 this.endEl = this.el.first();
13902 this.innerEl = this.endEl.first();
13903 this.focusEl = this.innerEl.child('.x-slider-focus');
13905 //render each thumb
13906 for (var i=0; i < this.thumbs.length; i++) {
13907 this.thumbs[i].render();
13910 //calculate the size of half a thumb
13911 var thumb = this.innerEl.child('.x-slider-thumb');
13912 this.halfThumb = (this.vertical ? thumb.getHeight() : thumb.getWidth()) / 2;
13919 * Adds keyboard and mouse listeners on this.el. Ignores click events on the internal focus element.
13920 * Creates a new DragTracker which is used to control what happens when the user drags the thumb around.
13922 initEvents : function(){
13923 this.mon(this.el, {
13925 mousedown: this.onMouseDown,
13926 keydown : this.onKeyDown
13929 this.focusEl.swallowEvent("click", true);
13934 * Mousedown handler for the slider. If the clickToChange is enabled and the click was not on the draggable 'thumb',
13935 * this calculates the new value of the slider and tells the implementation (Horizontal or Vertical) to move the thumb
13936 * @param {Ext.EventObject} e The click event
13938 onMouseDown : function(e){
13943 //see if the click was on any of the thumbs
13944 var thumbClicked = false;
13945 for (var i=0; i < this.thumbs.length; i++) {
13946 thumbClicked = thumbClicked || e.target == this.thumbs[i].el.dom;
13949 if (this.clickToChange && !thumbClicked) {
13950 var local = this.innerEl.translatePoints(e.getXY());
13951 this.onClickChange(local);
13958 * Moves the thumb to the indicated position. Note that a Vertical implementation is provided in Ext.slider.Vertical.
13959 * Only changes the value if the click was within this.clickRange.
13960 * @param {Object} local Object containing top and left values for the click event.
13962 onClickChange : function(local) {
13963 if (local.top > this.clickRange[0] && local.top < this.clickRange[1]) {
13964 //find the nearest thumb to the click event
13965 var thumb = this.getNearest(local, 'left'),
13966 index = thumb.index;
13968 this.setValue(index, Ext.util.Format.round(this.reverseValue(local.left), this.decimalPrecision), undefined, true);
13974 * Returns the nearest thumb to a click event, along with its distance
13975 * @param {Object} local Object containing top and left values from a click event
13976 * @param {String} prop The property of local to compare on. Use 'left' for horizontal sliders, 'top' for vertical ones
13977 * @return {Object} The closest thumb object and its distance from the click event
13979 getNearest: function(local, prop) {
13980 var localValue = prop == 'top' ? this.innerEl.getHeight() - local[prop] : local[prop],
13981 clickValue = this.reverseValue(localValue),
13982 nearestDistance = (this.maxValue - this.minValue) + 5, //add a small fudge for the end of the slider
13986 for (var i=0; i < this.thumbs.length; i++) {
13987 var thumb = this.thumbs[i],
13988 value = thumb.value,
13989 dist = Math.abs(value - clickValue);
13991 if (Math.abs(dist <= nearestDistance)) {
13994 nearestDistance = dist;
14002 * Handler for any keypresses captured by the slider. If the key is UP or RIGHT, the thumb is moved along to the right
14003 * by this.keyIncrement. If DOWN or LEFT it is moved left. Pressing CTRL moves the slider to the end in either direction
14004 * @param {Ext.EventObject} e The Event object
14006 onKeyDown : function(e){
14008 * The behaviour for keyboard handling with multiple thumbs is currently undefined.
14009 * There's no real sane default for it, so leave it like this until we come up
14010 * with a better way of doing it.
14012 if(this.disabled || this.thumbs.length !== 1){
14013 e.preventDefault();
14016 var k = e.getKey(),
14022 val = e.ctrlKey ? this.maxValue : this.getValue(0) + this.keyIncrement;
14023 this.setValue(0, val, undefined, true);
14028 val = e.ctrlKey ? this.minValue : this.getValue(0) - this.keyIncrement;
14029 this.setValue(0, val, undefined, true);
14032 e.preventDefault();
14038 * If using snapping, this takes a desired new value and returns the closest snapped
14040 * @param {Number} value The unsnapped value
14041 * @return {Number} The value of the nearest snap target
14043 doSnap : function(value){
14044 if (!(this.increment && value)) {
14047 var newValue = value,
14048 inc = this.increment,
14052 if (m * 2 >= inc) {
14054 } else if (m * 2 < -inc) {
14058 return newValue.constrain(this.minValue, this.maxValue);
14062 afterRender : function(){
14063 Ext.slider.MultiSlider.superclass.afterRender.apply(this, arguments);
14065 for (var i=0; i < this.thumbs.length; i++) {
14066 var thumb = this.thumbs[i];
14068 if (thumb.value !== undefined) {
14069 var v = this.normalizeValue(thumb.value);
14071 if (v !== thumb.value) {
14072 // delete this.value;
14073 this.setValue(i, v, false);
14075 this.moveThumb(i, this.translateValue(v), false);
14083 * Returns the ratio of pixels to mapped values. e.g. if the slider is 200px wide and maxValue - minValue is 100,
14085 * @return {Number} The ratio of pixels to mapped values
14087 getRatio : function(){
14088 var w = this.innerEl.getWidth(),
14089 v = this.maxValue - this.minValue;
14090 return v == 0 ? w : (w/v);
14095 * Returns a snapped, constrained value when given a desired value
14096 * @param {Number} value Raw number value
14097 * @return {Number} The raw value rounded to the correct d.p. and constrained within the set max and min values
14099 normalizeValue : function(v){
14100 v = this.doSnap(v);
14101 v = Ext.util.Format.round(v, this.decimalPrecision);
14102 v = v.constrain(this.minValue, this.maxValue);
14107 * Sets the minimum value for the slider instance. If the current value is less than the
14108 * minimum value, the current value will be changed.
14109 * @param {Number} val The new minimum value
14111 setMinValue : function(val){
14112 this.minValue = val;
14114 thumbs = this.thumbs,
14115 len = thumbs.length,
14118 for(; i < len; ++i){
14120 t.value = t.value < val ? val : t.value;
14126 * Sets the maximum value for the slider instance. If the current value is more than the
14127 * maximum value, the current value will be changed.
14128 * @param {Number} val The new maximum value
14130 setMaxValue : function(val){
14131 this.maxValue = val;
14133 thumbs = this.thumbs,
14134 len = thumbs.length,
14137 for(; i < len; ++i){
14139 t.value = t.value > val ? val : t.value;
14145 * Programmatically sets the value of the Slider. Ensures that the value is constrained within
14146 * the minValue and maxValue.
14147 * @param {Number} index Index of the thumb to move
14148 * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
14149 * @param {Boolean} animate Turn on or off animation, defaults to true
14151 setValue : function(index, v, animate, changeComplete) {
14152 var thumb = this.thumbs[index],
14155 v = this.normalizeValue(v);
14157 if (v !== thumb.value && this.fireEvent('beforechange', this, v, thumb.value, thumb) !== false) {
14160 this.moveThumb(index, this.translateValue(v), animate !== false);
14161 this.fireEvent('change', this, v, thumb);
14162 if(changeComplete){
14163 this.fireEvent('changecomplete', this, v, thumb);
14172 translateValue : function(v) {
14173 var ratio = this.getRatio();
14174 return (v * ratio) - (this.minValue * ratio) - this.halfThumb;
14179 * Given a pixel location along the slider, returns the mapped slider value for that pixel.
14180 * E.g. if we have a slider 200px wide with minValue = 100 and maxValue = 500, reverseValue(50)
14182 * @param {Number} pos The position along the slider to return a mapped value for
14183 * @return {Number} The mapped value for the given position
14185 reverseValue : function(pos){
14186 var ratio = this.getRatio();
14187 return (pos + (this.minValue * ratio)) / ratio;
14192 * @param {Number} index Index of the thumb to move
14194 moveThumb: function(index, v, animate){
14195 var thumb = this.thumbs[index].el;
14197 if(!animate || this.animate === false){
14200 thumb.shift({left: v, stopFx: true, duration:.35});
14205 focus : function(){
14206 this.focusEl.focus(10);
14210 onResize : function(w, h){
14211 var thumbs = this.thumbs,
14212 len = thumbs.length,
14216 * If we happen to be animating during a resize, the position of the thumb will likely be off
14217 * when the animation stops. As such, just stop any animations before syncing the thumbs.
14219 for(; i < len; ++i){
14220 thumbs[i].el.stopFx();
14222 // check to see if we're using an auto width
14223 if(Ext.isNumber(w)){
14224 this.innerEl.setWidth(w - (this.el.getPadding('l') + this.endEl.getPadding('r')));
14227 Ext.slider.MultiSlider.superclass.onResize.apply(this, arguments);
14231 onDisable: function(){
14232 Ext.slider.MultiSlider.superclass.onDisable.call(this);
14234 for (var i=0; i < this.thumbs.length; i++) {
14235 var thumb = this.thumbs[i],
14241 //IE breaks when using overflow visible and opacity other than 1.
14242 //Create a place holder for the thumb and display it.
14243 var xy = el.getXY();
14246 this.innerEl.addClass(this.disabledClass).dom.disabled = true;
14248 if (!this.thumbHolder) {
14249 this.thumbHolder = this.endEl.createChild({cls: 'x-slider-thumb ' + this.disabledClass});
14252 this.thumbHolder.show().setXY(xy);
14258 onEnable: function(){
14259 Ext.slider.MultiSlider.superclass.onEnable.call(this);
14261 for (var i=0; i < this.thumbs.length; i++) {
14262 var thumb = this.thumbs[i],
14268 this.innerEl.removeClass(this.disabledClass).dom.disabled = false;
14270 if (this.thumbHolder) this.thumbHolder.hide();
14279 * Synchronizes the thumb position to the proper proportion of the total component width based
14280 * on the current slider {@link #value}. This will be called automatically when the Slider
14281 * is resized by a layout, but if it is rendered auto width, this method can be called from
14282 * another resize handler to sync the Slider if necessary.
14284 syncThumb : function() {
14285 if (this.rendered) {
14286 for (var i=0; i < this.thumbs.length; i++) {
14287 this.moveThumb(i, this.translateValue(this.thumbs[i].value));
14293 * Returns the current value of the slider
14294 * @param {Number} index The index of the thumb to return a value for
14295 * @return {Number} The current value of the slider
14297 getValue : function(index) {
14298 return this.thumbs[index].value;
14302 * Returns an array of values - one for the location of each thumb
14303 * @return {Array} The set of thumb values
14305 getValues: function() {
14308 for (var i=0; i < this.thumbs.length; i++) {
14309 values.push(this.thumbs[i].value);
14316 beforeDestroy : function(){
14317 var thumbs = this.thumbs;
14318 for(var i = 0, len = thumbs.length; i < len; ++i){
14319 thumbs[i].destroy();
14322 Ext.destroyMembers(this, 'endEl', 'innerEl', 'focusEl', 'thumbHolder');
14323 Ext.slider.MultiSlider.superclass.beforeDestroy.call(this);
14327 Ext.reg('multislider', Ext.slider.MultiSlider);
14330 * @class Ext.slider.SingleSlider
14331 * @extends Ext.slider.MultiSlider
14332 * Slider which supports vertical or horizontal orientation, keyboard adjustments,
14333 * configurable snapping, axis clicking and animation. Can be added as an item to
14334 * any container. Example usage:
14336 new Ext.slider.SingleSlider({
14337 renderTo: Ext.getBody(),
14345 * The class Ext.slider.SingleSlider is aliased to Ext.Slider for backwards compatibility.
14347 Ext.slider.SingleSlider = Ext.extend(Ext.slider.MultiSlider, {
14348 constructor: function(config) {
14349 config = config || {};
14351 Ext.applyIf(config, {
14352 values: [config.value || 0]
14355 Ext.slider.SingleSlider.superclass.constructor.call(this, config);
14359 * Returns the current value of the slider
14360 * @return {Number} The current value of the slider
14362 getValue: function() {
14363 //just returns the value of the first thumb, which should be the only one in a single slider
14364 return Ext.slider.SingleSlider.superclass.getValue.call(this, 0);
14368 * Programmatically sets the value of the Slider. Ensures that the value is constrained within
14369 * the minValue and maxValue.
14370 * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
14371 * @param {Boolean} animate Turn on or off animation, defaults to true
14373 setValue: function(value, animate) {
14374 var args = Ext.toArray(arguments),
14377 //this is to maintain backwards compatiblity for sliders with only one thunb. Usually you must pass the thumb
14378 //index to setValue, but if we only have one thumb we inject the index here first if given the multi-slider
14379 //signature without the required index. The index will always be 0 for a single slider
14380 if (len == 1 || (len <= 3 && typeof arguments[1] != 'number')) {
14384 return Ext.slider.SingleSlider.superclass.setValue.apply(this, args);
14388 * Synchronizes the thumb position to the proper proportion of the total component width based
14389 * on the current slider {@link #value}. This will be called automatically when the Slider
14390 * is resized by a layout, but if it is rendered auto width, this method can be called from
14391 * another resize handler to sync the Slider if necessary.
14393 syncThumb : function() {
14394 return Ext.slider.SingleSlider.superclass.syncThumb.apply(this, [0].concat(arguments));
14398 getNearest : function(){
14399 // Since there's only 1 thumb, it's always the nearest
14400 return this.thumbs[0];
14404 //backwards compatibility
14405 Ext.Slider = Ext.slider.SingleSlider;
14407 Ext.reg('slider', Ext.slider.SingleSlider);
14409 // private class to support vertical sliders
14410 Ext.slider.Vertical = {
14411 onResize : function(w, h){
14412 this.innerEl.setHeight(h - (this.el.getPadding('t') + this.endEl.getPadding('b')));
14416 getRatio : function(){
14417 var h = this.innerEl.getHeight(),
14418 v = this.maxValue - this.minValue;
14422 moveThumb: function(index, v, animate) {
14423 var thumb = this.thumbs[index],
14426 if (!animate || this.animate === false) {
14429 el.shift({bottom: v, stopFx: true, duration:.35});
14433 onClickChange : function(local) {
14434 if (local.left > this.clickRange[0] && local.left < this.clickRange[1]) {
14435 var thumb = this.getNearest(local, 'top'),
14436 index = thumb.index,
14437 value = this.minValue + this.reverseValue(this.innerEl.getHeight() - local.top);
14439 this.setValue(index, Ext.util.Format.round(value, this.decimalPrecision), undefined, true);
14444 //private class to support vertical dragging of thumbs within a slider
14445 Ext.slider.Thumb.Vertical = {
14446 getNewValue: function() {
14447 var slider = this.slider,
14448 innerEl = slider.innerEl,
14449 pos = innerEl.translatePoints(this.tracker.getXY()),
14450 bottom = innerEl.getHeight() - pos.top;
14452 return slider.minValue + Ext.util.Format.round(bottom / slider.getRatio(), slider.decimalPrecision);
14456 * @class Ext.ProgressBar
14457 * @extends Ext.BoxComponent
14458 * <p>An updateable progress bar component. The progress bar supports two different modes: manual and automatic.</p>
14459 * <p>In manual mode, you are responsible for showing, updating (via {@link #updateProgress}) and clearing the
14460 * progress bar as needed from your own code. This method is most appropriate when you want to show progress
14461 * throughout an operation that has predictable points of interest at which you can update the control.</p>
14462 * <p>In automatic mode, you simply call {@link #wait} and let the progress bar run indefinitely, only clearing it
14463 * once the operation is complete. You can optionally have the progress bar wait for a specific amount of time
14464 * and then clear itself. Automatic mode is most appropriate for timed operations or asynchronous operations in
14465 * which you have no need for indicating intermediate progress.</p>
14466 * @cfg {Float} value A floating point value between 0 and 1 (e.g., .5, defaults to 0)
14467 * @cfg {String} text The progress bar text (defaults to '')
14468 * @cfg {Mixed} textEl The element to render the progress text to (defaults to the progress
14469 * bar's internal text element)
14470 * @cfg {String} id The progress bar element's id (defaults to an auto-generated id)
14473 Ext.ProgressBar = Ext.extend(Ext.BoxComponent, {
14475 * @cfg {String} baseCls
14476 * The base CSS class to apply to the progress bar's wrapper element (defaults to 'x-progress')
14478 baseCls : 'x-progress',
14481 * @cfg {Boolean} animate
14482 * True to animate the progress bar during transitions (defaults to false)
14490 initComponent : function(){
14491 Ext.ProgressBar.superclass.initComponent.call(this);
14495 * Fires after each update interval
14496 * @param {Ext.ProgressBar} this
14497 * @param {Number} The current progress value
14498 * @param {String} The current progress text
14505 onRender : function(ct, position){
14506 var tpl = new Ext.Template(
14507 '<div class="{cls}-wrap">',
14508 '<div class="{cls}-inner">',
14509 '<div class="{cls}-bar">',
14510 '<div class="{cls}-text">',
14511 '<div> </div>',
14514 '<div class="{cls}-text {cls}-text-back">',
14515 '<div> </div>',
14521 this.el = position ? tpl.insertBefore(position, {cls: this.baseCls}, true)
14522 : tpl.append(ct, {cls: this.baseCls}, true);
14525 this.el.dom.id = this.id;
14527 var inner = this.el.dom.firstChild;
14528 this.progressBar = Ext.get(inner.firstChild);
14531 //use an external text el
14532 this.textEl = Ext.get(this.textEl);
14533 delete this.textTopEl;
14535 //setup our internal layered text els
14536 this.textTopEl = Ext.get(this.progressBar.dom.firstChild);
14537 var textBackEl = Ext.get(inner.childNodes[1]);
14538 this.textTopEl.setStyle("z-index", 99).addClass('x-hidden');
14539 this.textEl = new Ext.CompositeElement([this.textTopEl.dom.firstChild, textBackEl.dom.firstChild]);
14540 this.textEl.setWidth(inner.offsetWidth);
14542 this.progressBar.setHeight(inner.offsetHeight);
14546 afterRender : function(){
14547 Ext.ProgressBar.superclass.afterRender.call(this);
14549 this.updateProgress(this.value, this.text);
14551 this.updateText(this.text);
14556 * Updates the progress bar value, and optionally its text. If the text argument is not specified,
14557 * any existing text value will be unchanged. To blank out existing text, pass ''. Note that even
14558 * if the progress bar value exceeds 1, it will never automatically reset -- you are responsible for
14559 * determining when the progress is complete and calling {@link #reset} to clear and/or hide the control.
14560 * @param {Float} value (optional) A floating point value between 0 and 1 (e.g., .5, defaults to 0)
14561 * @param {String} text (optional) The string to display in the progress text element (defaults to '')
14562 * @param {Boolean} animate (optional) Whether to animate the transition of the progress bar. If this value is
14563 * not specified, the default for the class is used (default to false)
14564 * @return {Ext.ProgressBar} this
14566 updateProgress : function(value, text, animate){
14567 this.value = value || 0;
14569 this.updateText(text);
14571 if(this.rendered && !this.isDestroyed){
14572 var w = Math.floor(value*this.el.dom.firstChild.offsetWidth);
14573 this.progressBar.setWidth(w, animate === true || (animate !== false && this.animate));
14574 if(this.textTopEl){
14575 //textTopEl should be the same width as the bar so overflow will clip as the bar moves
14576 this.textTopEl.removeClass('x-hidden').setWidth(w);
14579 this.fireEvent('update', this, value, text);
14584 * Initiates an auto-updating progress bar. A duration can be specified, in which case the progress
14585 * bar will automatically reset after a fixed amount of time and optionally call a callback function
14586 * if specified. If no duration is passed in, then the progress bar will run indefinitely and must
14587 * be manually cleared by calling {@link #reset}. The wait method accepts a config object with
14588 * the following properties:
14590 Property Type Description
14591 ---------- ------------ ----------------------------------------------------------------------
14592 duration Number The length of time in milliseconds that the progress bar should
14593 run before resetting itself (defaults to undefined, in which case it
14594 will run indefinitely until reset is called)
14595 interval Number The length of time in milliseconds between each progress update
14596 (defaults to 1000 ms)
14597 animate Boolean Whether to animate the transition of the progress bar. If this value is
14598 not specified, the default for the class is used.
14599 increment Number The number of progress update segments to display within the progress
14600 bar (defaults to 10). If the bar reaches the end and is still
14601 updating, it will automatically wrap back to the beginning.
14602 text String Optional text to display in the progress bar element (defaults to '').
14603 fn Function A callback function to execute after the progress bar finishes auto-
14604 updating. The function will be called with no arguments. This function
14605 will be ignored if duration is not specified since in that case the
14606 progress bar can only be stopped programmatically, so any required function
14607 should be called by the same code after it resets the progress bar.
14608 scope Object The scope that is passed to the callback function (only applies when
14609 duration and fn are both passed).
14614 var p = new Ext.ProgressBar({
14618 //Wait for 5 seconds, then update the status el (progress bar will auto-reset)
14620 interval: 100, //bar will move fast!
14623 text: 'Updating...',
14626 Ext.fly('status').update('Done!');
14630 //Or update indefinitely until some async action completes, then reset manually
14632 myAction.on('complete', function(){
14634 Ext.fly('status').update('Done!');
14637 * @param {Object} config (optional) Configuration options
14638 * @return {Ext.ProgressBar} this
14640 wait : function(o){
14641 if(!this.waitTimer){
14644 this.updateText(o.text);
14645 this.waitTimer = Ext.TaskMgr.start({
14647 var inc = o.increment || 10;
14649 this.updateProgress(((((i+inc)%inc)+1)*(100/inc))*0.01, null, o.animate);
14651 interval: o.interval || 1000,
14652 duration: o.duration,
14653 onStop: function(){
14655 o.fn.apply(o.scope || this);
14666 * Returns true if the progress bar is currently in a {@link #wait} operation
14667 * @return {Boolean} True if waiting, else false
14669 isWaiting : function(){
14670 return this.waitTimer !== null;
14674 * Updates the progress bar text. If specified, textEl will be updated, otherwise the progress
14675 * bar itself will display the updated text.
14676 * @param {String} text (optional) The string to display in the progress text element (defaults to '')
14677 * @return {Ext.ProgressBar} this
14679 updateText : function(text){
14680 this.text = text || ' ';
14682 this.textEl.update(this.text);
14688 * Synchronizes the inner bar width to the proper proportion of the total componet width based
14689 * on the current progress {@link #value}. This will be called automatically when the ProgressBar
14690 * is resized by a layout, but if it is rendered auto width, this method can be called from
14691 * another resize handler to sync the ProgressBar if necessary.
14693 syncProgressBar : function(){
14695 this.updateProgress(this.value, this.text);
14701 * Sets the size of the progress bar.
14702 * @param {Number} width The new width in pixels
14703 * @param {Number} height The new height in pixels
14704 * @return {Ext.ProgressBar} this
14706 setSize : function(w, h){
14707 Ext.ProgressBar.superclass.setSize.call(this, w, h);
14708 if(this.textTopEl){
14709 var inner = this.el.dom.firstChild;
14710 this.textEl.setSize(inner.offsetWidth, inner.offsetHeight);
14712 this.syncProgressBar();
14717 * Resets the progress bar value to 0 and text to empty string. If hide = true, the progress
14718 * bar will also be hidden (using the {@link #hideMode} property internally).
14719 * @param {Boolean} hide (optional) True to hide the progress bar (defaults to false)
14720 * @return {Ext.ProgressBar} this
14722 reset : function(hide){
14723 this.updateProgress(0);
14724 if(this.textTopEl){
14725 this.textTopEl.addClass('x-hidden');
14735 clearTimer : function(){
14736 if(this.waitTimer){
14737 this.waitTimer.onStop = null; //prevent recursion
14738 Ext.TaskMgr.stop(this.waitTimer);
14739 this.waitTimer = null;
14743 onDestroy: function(){
14746 if(this.textEl.isComposite){
14747 this.textEl.clear();
14749 Ext.destroyMembers(this, 'textEl', 'progressBar', 'textTopEl');
14751 Ext.ProgressBar.superclass.onDestroy.call(this);
14754 Ext.reg('progress', Ext.ProgressBar);