3 * Copyright(c) 2006-2010 Ext JS, Inc.
5 * http://www.extjs.com/license
8 * @class Ext.ComponentMgr
9 * <p>Provides a registry of all Components (instances of {@link Ext.Component} or any subclass
10 * thereof) on a page so that they can be easily accessed by {@link Ext.Component component}
11 * {@link Ext.Component#id id} (see {@link #get}, or the convenience method {@link Ext#getCmp Ext.getCmp}).</p>
12 * <p>This object also provides a registry of available Component <i>classes</i>
13 * indexed by a mnemonic code known as the Component's {@link Ext.Component#xtype xtype}.
14 * The <code>{@link Ext.Component#xtype xtype}</code> provides a way to avoid instantiating child Components
15 * when creating a full, nested config object for a complete Ext page.</p>
16 * <p>A child Component may be specified simply as a <i>config object</i>
17 * as long as the correct <code>{@link Ext.Component#xtype xtype}</code> is specified so that if and when the Component
18 * needs rendering, the correct type can be looked up for lazy instantiation.</p>
19 * <p>For a list of all available <code>{@link Ext.Component#xtype xtypes}</code>, see {@link Ext.Component}.</p>
22 Ext.ComponentMgr = function(){
23 var all = new Ext.util.MixedCollection();
29 * Registers a component.
30 * @param {Ext.Component} c The component
32 register : function(c){
37 * Unregisters a component.
38 * @param {Ext.Component} c The component
40 unregister : function(c){
45 * Returns a component by {@link Ext.Component#id id}.
46 * For additional details see {@link Ext.util.MixedCollection#get}.
47 * @param {String} id The component {@link Ext.Component#id id}
48 * @return Ext.Component The Component, <code>undefined</code> if not found, or <code>null</code> if a
56 * Registers a function that will be called when a Component with the specified id is added to ComponentMgr. This will happen on instantiation.
57 * @param {String} id The component {@link Ext.Component#id id}
58 * @param {Function} fn The callback function
59 * @param {Object} scope The scope (<code>this</code> reference) in which the callback is executed. Defaults to the Component.
61 onAvailable : function(id, fn, scope){
62 all.on("add", function(index, o){
64 fn.call(scope || o, o);
65 all.un("add", fn, scope);
71 * The MixedCollection used internally for the component cache. An example usage may be subscribing to
72 * events on the MixedCollection to monitor addition or removal. Read-only.
73 * @type {MixedCollection}
78 * The xtypes that have been registered with the component manager.
84 * The ptypes that have been registered with the component manager.
90 * Checks if a Component type is registered.
91 * @param {Ext.Component} xtype The mnemonic string by which the Component class may be looked up
92 * @return {Boolean} Whether the type is registered.
94 isRegistered : function(xtype){
95 return types[xtype] !== undefined;
99 * Checks if a Plugin type is registered.
100 * @param {Ext.Component} ptype The mnemonic string by which the Plugin class may be looked up
101 * @return {Boolean} Whether the type is registered.
103 isPluginRegistered : function(ptype){
104 return ptypes[ptype] !== undefined;
108 * <p>Registers a new Component constructor, keyed by a new
109 * {@link Ext.Component#xtype}.</p>
110 * <p>Use this method (or its alias {@link Ext#reg Ext.reg}) to register new
111 * subclasses of {@link Ext.Component} so that lazy instantiation may be used when specifying
113 * see {@link Ext.Container#items}</p>
114 * @param {String} xtype The mnemonic string by which the Component class may be looked up.
115 * @param {Constructor} cls The new Component class.
117 registerType : function(xtype, cls){
123 * Creates a new Component from the specified config object using the
124 * config object's {@link Ext.component#xtype xtype} to determine the class to instantiate.
125 * @param {Object} config A configuration object for the Component you wish to create.
126 * @param {Constructor} defaultType The constructor to provide the default Component type if
127 * the config object does not contain a <code>xtype</code>. (Optional if the config contains a <code>xtype</code>).
128 * @return {Ext.Component} The newly instantiated Component.
130 create : function(config, defaultType){
131 return config.render ? config : new types[config.xtype || defaultType](config);
135 * <p>Registers a new Plugin constructor, keyed by a new
136 * {@link Ext.Component#ptype}.</p>
137 * <p>Use this method (or its alias {@link Ext#preg Ext.preg}) to register new
138 * plugins for {@link Ext.Component}s so that lazy instantiation may be used when specifying
140 * @param {String} ptype The mnemonic string by which the Plugin class may be looked up.
141 * @param {Constructor} cls The new Plugin class.
143 registerPlugin : function(ptype, cls){
149 * Creates a new Plugin from the specified config object using the
150 * config object's {@link Ext.component#ptype ptype} to determine the class to instantiate.
151 * @param {Object} config A configuration object for the Plugin you wish to create.
152 * @param {Constructor} defaultType The constructor to provide the default Plugin type if
153 * the config object does not contain a <code>ptype</code>. (Optional if the config contains a <code>ptype</code>).
154 * @return {Ext.Component} The newly instantiated Plugin.
156 createPlugin : function(config, defaultType){
157 var PluginCls = ptypes[config.ptype || defaultType];
158 if (PluginCls.init) {
161 return new PluginCls(config);
168 * Shorthand for {@link Ext.ComponentMgr#registerType}
169 * @param {String} xtype The {@link Ext.component#xtype mnemonic string} by which the Component class
171 * @param {Constructor} cls The new Component class.
175 Ext.reg = Ext.ComponentMgr.registerType; // this will be called a lot internally, shorthand to keep the bytes down
177 * Shorthand for {@link Ext.ComponentMgr#registerPlugin}
178 * @param {String} ptype The {@link Ext.component#ptype mnemonic string} by which the Plugin class
180 * @param {Constructor} cls The new Plugin class.
184 Ext.preg = Ext.ComponentMgr.registerPlugin;
186 * Shorthand for {@link Ext.ComponentMgr#create}
187 * Creates a new Component from the specified config object using the
188 * config object's {@link Ext.component#xtype xtype} to determine the class to instantiate.
189 * @param {Object} config A configuration object for the Component you wish to create.
190 * @param {Constructor} defaultType The constructor to provide the default Component type if
191 * the config object does not contain a <code>xtype</code>. (Optional if the config contains a <code>xtype</code>).
192 * @return {Ext.Component} The newly instantiated Component.
196 Ext.create = Ext.ComponentMgr.create;/**
197 * @class Ext.Component
198 * @extends Ext.util.Observable
199 * <p>Base class for all Ext components. All subclasses of Component may participate in the automated
200 * Ext component lifecycle of creation, rendering and destruction which is provided by the {@link Ext.Container Container} class.
201 * Components may be added to a Container through the {@link Ext.Container#items items} config option at the time the Container is created,
202 * or they may be added dynamically via the {@link Ext.Container#add add} method.</p>
203 * <p>The Component base class has built-in support for basic hide/show and enable/disable behavior.</p>
204 * <p>All Components are registered with the {@link Ext.ComponentMgr} on construction so that they can be referenced at any time via
205 * {@link Ext#getCmp}, passing the {@link #id}.</p>
206 * <p>All user-developed visual widgets that are required to participate in automated lifecycle and size management should subclass Component (or
207 * {@link Ext.BoxComponent} if managed box model handling is required, ie height and width management).</p>
208 * <p>See the <a href="http://extjs.com/learn/Tutorial:Creating_new_UI_controls">Creating new UI controls</a> tutorial for details on how
209 * and to either extend or augment ExtJs base classes to create custom Components.</p>
210 * <p>Every component has a specific xtype, which is its Ext-specific type name, along with methods for checking the
211 * xtype like {@link #getXType} and {@link #isXType}. This is the list of all valid xtypes:</p>
214 ------------- ------------------
215 box {@link Ext.BoxComponent}
216 button {@link Ext.Button}
217 buttongroup {@link Ext.ButtonGroup}
218 colorpalette {@link Ext.ColorPalette}
219 component {@link Ext.Component}
220 container {@link Ext.Container}
221 cycle {@link Ext.CycleButton}
222 dataview {@link Ext.DataView}
223 datepicker {@link Ext.DatePicker}
224 editor {@link Ext.Editor}
225 editorgrid {@link Ext.grid.EditorGridPanel}
226 flash {@link Ext.FlashComponent}
227 grid {@link Ext.grid.GridPanel}
228 listview {@link Ext.ListView}
229 panel {@link Ext.Panel}
230 progress {@link Ext.ProgressBar}
231 propertygrid {@link Ext.grid.PropertyGrid}
232 slider {@link Ext.Slider}
233 spacer {@link Ext.Spacer}
234 splitbutton {@link Ext.SplitButton}
235 tabpanel {@link Ext.TabPanel}
236 treepanel {@link Ext.tree.TreePanel}
237 viewport {@link Ext.ViewPort}
238 window {@link Ext.Window}
241 ---------------------------------------
242 paging {@link Ext.PagingToolbar}
243 toolbar {@link Ext.Toolbar}
244 tbbutton {@link Ext.Toolbar.Button} (deprecated; use button)
245 tbfill {@link Ext.Toolbar.Fill}
246 tbitem {@link Ext.Toolbar.Item}
247 tbseparator {@link Ext.Toolbar.Separator}
248 tbspacer {@link Ext.Toolbar.Spacer}
249 tbsplit {@link Ext.Toolbar.SplitButton} (deprecated; use splitbutton)
250 tbtext {@link Ext.Toolbar.TextItem}
253 ---------------------------------------
254 menu {@link Ext.menu.Menu}
255 colormenu {@link Ext.menu.ColorMenu}
256 datemenu {@link Ext.menu.DateMenu}
257 menubaseitem {@link Ext.menu.BaseItem}
258 menucheckitem {@link Ext.menu.CheckItem}
259 menuitem {@link Ext.menu.Item}
260 menuseparator {@link Ext.menu.Separator}
261 menutextitem {@link Ext.menu.TextItem}
264 ---------------------------------------
265 form {@link Ext.form.FormPanel}
266 checkbox {@link Ext.form.Checkbox}
267 checkboxgroup {@link Ext.form.CheckboxGroup}
268 combo {@link Ext.form.ComboBox}
269 datefield {@link Ext.form.DateField}
270 displayfield {@link Ext.form.DisplayField}
271 field {@link Ext.form.Field}
272 fieldset {@link Ext.form.FieldSet}
273 hidden {@link Ext.form.Hidden}
274 htmleditor {@link Ext.form.HtmlEditor}
275 label {@link Ext.form.Label}
276 numberfield {@link Ext.form.NumberField}
277 radio {@link Ext.form.Radio}
278 radiogroup {@link Ext.form.RadioGroup}
279 textarea {@link Ext.form.TextArea}
280 textfield {@link Ext.form.TextField}
281 timefield {@link Ext.form.TimeField}
282 trigger {@link Ext.form.TriggerField}
285 ---------------------------------------
286 chart {@link Ext.chart.Chart}
287 barchart {@link Ext.chart.BarChart}
288 cartesianchart {@link Ext.chart.CartesianChart}
289 columnchart {@link Ext.chart.ColumnChart}
290 linechart {@link Ext.chart.LineChart}
291 piechart {@link Ext.chart.PieChart}
294 ---------------------------------------
295 arraystore {@link Ext.data.ArrayStore}
296 directstore {@link Ext.data.DirectStore}
297 groupingstore {@link Ext.data.GroupingStore}
298 jsonstore {@link Ext.data.JsonStore}
299 simplestore {@link Ext.data.SimpleStore} (deprecated; use arraystore)
300 store {@link Ext.data.Store}
301 xmlstore {@link Ext.data.XmlStore}
304 * @param {Ext.Element/String/Object} config The configuration options may be specified as either:
305 * <div class="mdetail-params"><ul>
306 * <li><b>an element</b> :
307 * <p class="sub-desc">it is set as the internal element and its id used as the component id</p></li>
308 * <li><b>a string</b> :
309 * <p class="sub-desc">it is assumed to be the id of an existing element and is used as the component id</p></li>
310 * <li><b>anything else</b> :
311 * <p class="sub-desc">it is assumed to be a standard config object and is applied to the component</p></li>
314 Ext.Component = function(config){
315 config = config || {};
316 if(config.initialConfig){
317 if(config.isAction){ // actions
318 this.baseAction = config;
320 config = config.initialConfig; // component cloning / action set up
321 }else if(config.tagName || config.dom || Ext.isString(config)){ // element object
322 config = {applyTo: config, id: config.id || config};
326 * This Component's initial configuration specification. Read-only.
328 * @property initialConfig
330 this.initialConfig = config;
332 Ext.apply(this, config);
336 * Fires when a component is added to an Ext.Container
337 * @param {Ext.Component} this
338 * @param {Ext.Container} ownerCt Container which holds the component
339 * @param {number} index Position at which the component was added
344 * Fires after the component is disabled.
345 * @param {Ext.Component} this
350 * Fires after the component is enabled.
351 * @param {Ext.Component} this
356 * Fires before the component is shown by calling the {@link #show} method.
357 * Return false from an event handler to stop the show.
358 * @param {Ext.Component} this
363 * Fires after the component is shown when calling the {@link #show} method.
364 * @param {Ext.Component} this
369 * Fires before the component is hidden by calling the {@link #hide} method.
370 * Return false from an event handler to stop the hide.
371 * @param {Ext.Component} this
376 * Fires after the component is hidden.
377 * Fires after the component is hidden when calling the {@link #hide} method.
378 * @param {Ext.Component} this
383 * Fires when a component is removed from an Ext.Container
384 * @param {Ext.Component} this
385 * @param {Ext.Container} ownerCt Container which holds the component
389 * @event beforerender
390 * Fires before the component is {@link #rendered}. Return false from an
391 * event handler to stop the {@link #render}.
392 * @param {Ext.Component} this
397 * Fires after the component markup is {@link #rendered}.
398 * @param {Ext.Component} this
403 * <p>Fires after the component rendering is finished.</p>
404 * <p>The afterrender event is fired after this Component has been {@link #rendered}, been postprocesed
405 * by any afterRender method defined for the Component, and, if {@link #stateful}, after state
406 * has been restored.</p>
407 * @param {Ext.Component} this
411 * @event beforedestroy
412 * Fires before the component is {@link #destroy}ed. Return false from an event handler to stop the {@link #destroy}.
413 * @param {Ext.Component} this
418 * Fires after the component is {@link #destroy}ed.
419 * @param {Ext.Component} this
423 * @event beforestaterestore
424 * Fires before the state of the component is restored. Return false from an event handler to stop the restore.
425 * @param {Ext.Component} this
426 * @param {Object} state The hash of state values returned from the StateProvider. If this
427 * event is not vetoed, then the state object is passed to <b><tt>applyState</tt></b>. By default,
428 * that simply copies property values into this Component. The method maybe overriden to
429 * provide custom state restoration.
431 'beforestaterestore',
433 * @event staterestore
434 * Fires after the state of the component is restored.
435 * @param {Ext.Component} this
436 * @param {Object} state The hash of state values returned from the StateProvider. This is passed
437 * to <b><tt>applyState</tt></b>. By default, that simply copies property values into this
438 * Component. The method maybe overriden to provide custom state restoration.
442 * @event beforestatesave
443 * Fires before the state of the component is saved to the configured state provider. Return false to stop the save.
444 * @param {Ext.Component} this
445 * @param {Object} state The hash of state values. This is determined by calling
446 * <b><tt>getState()</tt></b> on the Component. This method must be provided by the
447 * developer to return whetever representation of state is required, by default, Ext.Component
448 * has a null implementation.
453 * Fires after the state of the component is saved to the configured state provider.
454 * @param {Ext.Component} this
455 * @param {Object} state The hash of state values. This is determined by calling
456 * <b><tt>getState()</tt></b> on the Component. This method must be provided by the
457 * developer to return whetever representation of state is required, by default, Ext.Component
458 * has a null implementation.
463 Ext.ComponentMgr.register(this);
464 Ext.Component.superclass.constructor.call(this);
467 this.baseAction.addComponent(this);
470 this.initComponent();
473 if(Ext.isArray(this.plugins)){
474 for(var i = 0, len = this.plugins.length; i < len; i++){
475 this.plugins[i] = this.initPlugin(this.plugins[i]);
478 this.plugins = this.initPlugin(this.plugins);
482 if(this.stateful !== false){
487 this.applyToMarkup(this.applyTo);
489 }else if(this.renderTo){
490 this.render(this.renderTo);
491 delete this.renderTo;
496 Ext.Component.AUTO_ID = 1000;
498 Ext.extend(Ext.Component, Ext.util.Observable, {
499 // Configs below are used for all Components when rendered by FormLayout.
501 * @cfg {String} fieldLabel <p>The label text to display next to this Component (defaults to '').</p>
502 * <br><p><b>Note</b>: this config is only used when this Component is rendered by a Container which
503 * has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout manager (e.g.
504 * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>).</p><br>
505 * <p>Also see <tt>{@link #hideLabel}</tt> and
506 * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</p>
507 * Example use:<pre><code>
510 renderTo: Ext.getBody(),
519 * @cfg {String} labelStyle <p>A CSS style specification string to apply directly to this field's
520 * label. Defaults to the container's labelStyle value if set (e.g.,
521 * <tt>{@link Ext.layout.FormLayout#labelStyle}</tt> , or '').</p>
522 * <br><p><b>Note</b>: see the note for <code>{@link #clearCls}</code>.</p><br>
523 * <p>Also see <code>{@link #hideLabel}</code> and
524 * <code>{@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</code></p>
525 * Example use:<pre><code>
528 renderTo: Ext.getBody(),
532 labelStyle: 'font-weight:bold;'
538 * @cfg {String} labelSeparator <p>The separator to display after the text of each
539 * <tt>{@link #fieldLabel}</tt>. This property may be configured at various levels.
540 * The order of precedence is:
541 * <div class="mdetail-params"><ul>
542 * <li>field / component level</li>
543 * <li>container level</li>
544 * <li>{@link Ext.layout.FormLayout#labelSeparator layout level} (defaults to colon <tt>':'</tt>)</li>
546 * To display no separator for this field's label specify empty string ''.</p>
547 * <br><p><b>Note</b>: see the note for <tt>{@link #clearCls}</tt>.</p><br>
548 * <p>Also see <tt>{@link #hideLabel}</tt> and
549 * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</p>
550 * Example use:<pre><code>
553 renderTo: Ext.getBody(),
555 labelSeparator: '~' // layout config has lowest priority (defaults to ':')
557 {@link Ext.layout.FormLayout#labelSeparator labelSeparator}: '>>', // config at container level
560 fieldLabel: 'Field 1',
561 labelSeparator: '...' // field/component level config supersedes others
564 fieldLabel: 'Field 2' // labelSeparator will be '='
570 * @cfg {Boolean} hideLabel <p><tt>true</tt> to completely hide the label element
571 * ({@link #fieldLabel label} and {@link #labelSeparator separator}). Defaults to <tt>false</tt>.
572 * By default, even if you do not specify a <tt>{@link #fieldLabel}</tt> the space will still be
573 * reserved so that the field will line up with other fields that do have labels.
574 * Setting this to <tt>true</tt> will cause the field to not reserve that space.</p>
575 * <br><p><b>Note</b>: see the note for <tt>{@link #clearCls}</tt>.</p><br>
576 * Example use:<pre><code>
579 renderTo: Ext.getBody(),
588 * @cfg {String} clearCls <p>The CSS class used to to apply to the special clearing div rendered
589 * directly after each form field wrapper to provide field clearing (defaults to
590 * <tt>'x-form-clear-left'</tt>).</p>
591 * <br><p><b>Note</b>: this config is only used when this Component is rendered by a Container
592 * which has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout
593 * manager (e.g. {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>) and either a
594 * <tt>{@link #fieldLabel}</tt> is specified or <tt>isFormField=true</tt> is specified.</p><br>
595 * <p>See {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl} also.</p>
598 * @cfg {String} itemCls
599 * <p><b>Note</b>: this config is only used when this Component is rendered by a Container which
600 * has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout manager (e.g.
601 * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>).</p><br>
602 * <p>An additional CSS class to apply to the div wrapping the form item
603 * element of this field. If supplied, <tt>itemCls</tt> at the <b>field</b> level will override
604 * the default <tt>itemCls</tt> supplied at the <b>container</b> level. The value specified for
605 * <tt>itemCls</tt> will be added to the default class (<tt>'x-form-item'</tt>).</p>
606 * <p>Since it is applied to the item wrapper (see
607 * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}), it allows
608 * you to write standard CSS rules that can apply to the field, the label (if specified), or
609 * any other element within the markup for the field.</p>
610 * <br><p><b>Note</b>: see the note for <tt>{@link #fieldLabel}</tt>.</p><br>
611 * Example use:<pre><code>
612 // Apply a style to the field's label:
614 .required .x-form-item-label {font-weight:bold;color:red;}
619 renderTo: Ext.getBody(),
623 itemCls: 'required' //this label will be styled
626 fieldLabel: 'Favorite Color'
634 * <p>The <b>unique</b> id of this component (defaults to an {@link #getId auto-assigned id}).
635 * You should assign an id if you need to be able to access the component later and you do
636 * not have an object reference available (e.g., using {@link Ext}.{@link Ext#getCmp getCmp}).</p>
637 * <p>Note that this id will also be used as the element id for the containing HTML element
638 * that is rendered to the page for this component. This allows you to write id-based CSS
639 * rules to style the specific instance of this component uniquely, and also to select
640 * sub-elements using this component's id as the parent.</p>
641 * <p><b>Note</b>: to avoid complications imposed by a unique <tt>id</tt> also see
642 * <code>{@link #itemId}</code> and <code>{@link #ref}</code>.</p>
643 * <p><b>Note</b>: to access the container of an item see <code>{@link #ownerCt}</code>.</p>
646 * @cfg {String} itemId
647 * <p>An <tt>itemId</tt> can be used as an alternative way to get a reference to a component
648 * when no object reference is available. Instead of using an <code>{@link #id}</code> with
649 * {@link Ext}.{@link Ext#getCmp getCmp}, use <code>itemId</code> with
650 * {@link Ext.Container}.{@link Ext.Container#getComponent getComponent} which will retrieve
651 * <code>itemId</code>'s or <tt>{@link #id}</tt>'s. Since <code>itemId</code>'s are an index to the
652 * container's internal MixedCollection, the <code>itemId</code> is scoped locally to the container --
653 * avoiding potential conflicts with {@link Ext.ComponentMgr} which requires a <b>unique</b>
654 * <code>{@link #id}</code>.</p>
656 var c = new Ext.Panel({ //
657 {@link Ext.BoxComponent#height height}: 300,
658 {@link #renderTo}: document.body,
659 {@link Ext.Container#layout layout}: 'auto',
660 {@link Ext.Container#items items}: [
663 {@link Ext.Panel#title title}: 'Panel 1',
664 {@link Ext.BoxComponent#height height}: 150
668 {@link Ext.Panel#title title}: 'Panel 2',
669 {@link Ext.BoxComponent#height height}: 150
673 p1 = c.{@link Ext.Container#getComponent getComponent}('p1'); // not the same as {@link Ext#getCmp Ext.getCmp()}
674 p2 = p1.{@link #ownerCt}.{@link Ext.Container#getComponent getComponent}('p2'); // reference via a sibling
676 * <p>Also see <tt>{@link #id}</tt> and <code>{@link #ref}</code>.</p>
677 * <p><b>Note</b>: to access the container of an item see <tt>{@link #ownerCt}</tt>.</p>
680 * @cfg {String} xtype
681 * The registered <tt>xtype</tt> to create. This config option is not used when passing
682 * a config object into a constructor. This config option is used only when
683 * lazy instantiation is being used, and a child item of a Container is being
684 * specified not as a fully instantiated Component, but as a <i>Component config
685 * object</i>. The <tt>xtype</tt> will be looked up at render time up to determine what
686 * type of child Component to create.<br><br>
687 * The predefined xtypes are listed {@link Ext.Component here}.
689 * If you subclass Components to create your own Components, you may register
690 * them using {@link Ext.ComponentMgr#registerType} in order to be able to
691 * take advantage of lazy instantiation and rendering.
694 * @cfg {String} ptype
695 * The registered <tt>ptype</tt> to create. This config option is not used when passing
696 * a config object into a constructor. This config option is used only when
697 * lazy instantiation is being used, and a Plugin is being
698 * specified not as a fully instantiated Component, but as a <i>Component config
699 * object</i>. The <tt>ptype</tt> will be looked up at render time up to determine what
700 * type of Plugin to create.<br><br>
701 * If you create your own Plugins, you may register them using
702 * {@link Ext.ComponentMgr#registerPlugin} in order to be able to
703 * take advantage of lazy instantiation and rendering.
707 * An optional extra CSS class that will be added to this component's Element (defaults to ''). This can be
708 * useful for adding customized styles to the component or any of its children using standard CSS rules.
711 * @cfg {String} overCls
712 * An optional extra CSS class that will be added to this component's Element when the mouse moves
713 * over the Element, and removed when the mouse moves out. (defaults to ''). This can be
714 * useful for adding customized 'active' or 'hover' styles to the component or any of its children using standard CSS rules.
717 * @cfg {String} style
718 * A custom style specification to be applied to this component's Element. Should be a valid argument to
719 * {@link Ext.Element#applyStyles}.
723 renderTo: Ext.getBody(),
724 width: 400, height: 300,
745 * @cfg {String} ctCls
746 * <p>An optional extra CSS class that will be added to this component's container. This can be useful for
747 * adding customized styles to the container or any of its children using standard CSS rules. See
748 * {@link Ext.layout.ContainerLayout}.{@link Ext.layout.ContainerLayout#extraCls extraCls} also.</p>
749 * <p><b>Note</b>: <tt>ctCls</tt> defaults to <tt>''</tt> except for the following class
750 * which assigns a value by default:
751 * <div class="mdetail-params"><ul>
752 * <li>{@link Ext.layout.Box Box Layout} : <tt>'x-box-layout-ct'</tt></li>
754 * To configure the above Class with an extra CSS class append to the default. For example,
755 * for BoxLayout (Hbox and Vbox):<pre><code>
756 * ctCls: 'x-box-layout-ct custom-class'
761 * @cfg {Boolean} disabled
762 * Render this component disabled (default is false).
766 * @cfg {Boolean} hidden
767 * Render this component hidden (default is false). If <tt>true</tt>, the
768 * {@link #hide} method will be called internally.
772 * @cfg {Object/Array} plugins
773 * An object or array of objects that will provide custom functionality for this component. The only
774 * requirement for a valid plugin is that it contain an init method that accepts a reference of type Ext.Component.
775 * When a component is created, if any plugins are available, the component will call the init method on each
776 * plugin, passing a reference to itself. Each plugin can then call methods or respond to events on the
777 * component as needed to provide its functionality.
780 * @cfg {Mixed} applyTo
781 * <p>Specify the id of the element, a DOM element or an existing Element corresponding to a DIV
782 * that is already present in the document that specifies some structural markup for this
783 * component.</p><div><ul>
784 * <li><b>Description</b> : <ul>
785 * <div class="sub-desc">When <tt>applyTo</tt> is used, constituent parts of the component can also be specified
786 * by id or CSS class name within the main element, and the component being created may attempt
787 * to create its subcomponents from that markup if applicable.</div>
789 * <li><b>Notes</b> : <ul>
790 * <div class="sub-desc">When using this config, a call to render() is not required.</div>
791 * <div class="sub-desc">If applyTo is specified, any value passed for {@link #renderTo} will be ignored and the target
792 * element's parent node will automatically be used as the component's container.</div>
797 * @cfg {Mixed} renderTo
798 * <p>Specify the id of the element, a DOM element or an existing Element that this component
799 * will be rendered into.</p><div><ul>
800 * <li><b>Notes</b> : <ul>
801 * <div class="sub-desc">Do <u>not</u> use this option if the Component is to be a child item of
802 * a {@link Ext.Container Container}. It is the responsibility of the
803 * {@link Ext.Container Container}'s {@link Ext.Container#layout layout manager}
804 * to render and manage its child items.</div>
805 * <div class="sub-desc">When using this config, a call to render() is not required.</div>
808 * <p>See <tt>{@link #render}</tt> also.</p>
811 * @cfg {Boolean} stateful
812 * <p>A flag which causes the Component to attempt to restore the state of
813 * internal properties from a saved state on startup. The component must have
814 * either a <code>{@link #stateId}</code> or <code>{@link #id}</code> assigned
815 * for state to be managed. Auto-generated ids are not guaranteed to be stable
816 * across page loads and cannot be relied upon to save and restore the same
817 * state for a component.<p>
818 * <p>For state saving to work, the state manager's provider must have been
819 * set to an implementation of {@link Ext.state.Provider} which overrides the
820 * {@link Ext.state.Provider#set set} and {@link Ext.state.Provider#get get}
821 * methods to save and recall name/value pairs. A built-in implementation,
822 * {@link Ext.state.CookieProvider} is available.</p>
823 * <p>To set the state provider for the current page:</p>
825 Ext.state.Manager.setProvider(new Ext.state.CookieProvider({
826 expires: new Date(new Date().getTime()+(1000*60*60*24*7)), //7 days from now
829 * <p>A stateful Component attempts to save state when one of the events
830 * listed in the <code>{@link #stateEvents}</code> configuration fires.</p>
831 * <p>To save state, a stateful Component first serializes its state by
832 * calling <b><code>getState</code></b>. By default, this function does
833 * nothing. The developer must provide an implementation which returns an
834 * object hash which represents the Component's restorable state.</p>
835 * <p>The value yielded by getState is passed to {@link Ext.state.Manager#set}
836 * which uses the configured {@link Ext.state.Provider} to save the object
837 * keyed by the Component's <code>{@link stateId}</code>, or, if that is not
838 * specified, its <code>{@link #id}</code>.</p>
839 * <p>During construction, a stateful Component attempts to <i>restore</i>
840 * its state by calling {@link Ext.state.Manager#get} passing the
841 * <code>{@link #stateId}</code>, or, if that is not specified, the
842 * <code>{@link #id}</code>.</p>
843 * <p>The resulting object is passed to <b><code>applyState</code></b>.
844 * The default implementation of <code>applyState</code> simply copies
845 * properties into the object, but a developer may override this to support
846 * more behaviour.</p>
847 * <p>You can perform extra processing on state save and restore by attaching
848 * handlers to the {@link #beforestaterestore}, {@link #staterestore},
849 * {@link #beforestatesave} and {@link #statesave} events.</p>
852 * @cfg {String} stateId
853 * The unique id for this component to use for state management purposes
854 * (defaults to the component id if one was set, otherwise null if the
855 * component is using a generated id).
856 * <p>See <code>{@link #stateful}</code> for an explanation of saving and
857 * restoring Component state.</p>
860 * @cfg {Array} stateEvents
861 * <p>An array of events that, when fired, should trigger this component to
862 * save its state (defaults to none). <code>stateEvents</code> may be any type
863 * of event supported by this component, including browser or custom events
864 * (e.g., <tt>['click', 'customerchange']</tt>).</p>
865 * <p>See <code>{@link #stateful}</code> for an explanation of saving and
866 * restoring Component state.</p>
869 * @cfg {Mixed} autoEl
870 * <p>A tag name or {@link Ext.DomHelper DomHelper} spec used to create the {@link #getEl Element} which will
871 * encapsulate this Component.</p>
872 * <p>You do not normally need to specify this. For the base classes {@link Ext.Component}, {@link Ext.BoxComponent},
873 * and {@link Ext.Container}, this defaults to <b><tt>'div'</tt></b>. The more complex Ext classes use a more complex
874 * DOM structure created by their own onRender methods.</p>
875 * <p>This is intended to allow the developer to create application-specific utility Components encapsulated by
876 * different DOM elements. Example usage:</p><pre><code>
881 src: 'http://www.example.com/example.jpg'
887 html: 'autoEl is cool!'
892 cls: 'ux-unordered-list',
896 html: 'First list item'
904 * @cfg {String} disabledClass
905 * CSS class added to the component when it is disabled (defaults to 'x-item-disabled').
907 disabledClass : 'x-item-disabled',
909 * @cfg {Boolean} allowDomMove
910 * Whether the component can move the Dom node when rendering (defaults to true).
914 * @cfg {Boolean} autoShow
915 * True if the component should check for hidden classes (e.g. 'x-hidden' or 'x-hide-display') and remove
916 * them on render (defaults to false).
920 * @cfg {String} hideMode
921 * <p>How this component should be hidden. Supported values are <tt>'visibility'</tt>
922 * (css visibility), <tt>'offsets'</tt> (negative offset position) and <tt>'display'</tt>
924 * <br><p><b>Note</b>: the default of <tt>'display'</tt> is generally preferred
925 * since items are automatically laid out when they are first shown (no sizing
926 * is done while hidden).</p>
928 hideMode : 'display',
930 * @cfg {Boolean} hideParent
931 * True to hide and show the component's container when hide/show is called on the component, false to hide
932 * and show the component itself (defaults to false). For example, this can be used as a shortcut for a hide
933 * button on a window by setting hide:true on the button when adding it to its parent container.
937 * <p>The {@link Ext.Element} which encapsulates this Component. Read-only.</p>
938 * <p>This will <i>usually</i> be a <DIV> element created by the class's onRender method, but
939 * that may be overridden using the <code>{@link #autoEl}</code> config.</p>
940 * <br><p><b>Note</b>: this element will not be available until this Component has been rendered.</p><br>
941 * <p>To add listeners for <b>DOM events</b> to this Component (as opposed to listeners
942 * for this Component's own Observable events), see the {@link Ext.util.Observable#listeners listeners}
943 * config for a suggestion, or use a render listener directly:</p><pre><code>
945 title: 'The Clickable Panel',
947 render: function(p) {
948 // Append the Panel to the click handler's argument list.
949 p.getEl().on('click', handlePanelClick.createDelegate(null, [p], true));
951 single: true // Remove the listener after first invocation
955 * <p>See also <tt>{@link #getEl getEl}</p>
960 * This Component's owner {@link Ext.Container Container} (defaults to undefined, and is set automatically when
961 * this Component is added to a Container). Read-only.
962 * <p><b>Note</b>: to access items within the Container see <tt>{@link #itemId}</tt>.</p>
963 * @type Ext.Container
967 * True if this component is hidden. Read-only.
972 * True if this component is disabled. Read-only.
977 * True if this component has been rendered. Read-only.
984 * @cfg {String} contentEl
985 * <p>Optional. Specify an existing HTML element, or the <code>id</code> of an existing HTML element to use as the content
986 * for this component.</p>
988 * <li><b>Description</b> :
989 * <div class="sub-desc">This config option is used to take an existing HTML element and place it in the layout element
990 * 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>
992 * <div class="sub-desc">The specified HTML element is appended to the layout element of the component <i>after any configured
993 * {@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>
994 * <div class="sub-desc">The specified HTML element used will not participate in any <code><b>{@link Ext.Container#layout layout}</b></code>
995 * scheme that the Component may use. It is just HTML. Layouts operate on child <code><b>{@link Ext.Container#items items}</b></code>.</div>
996 * <div class="sub-desc">Add either the <code>x-hidden</code> or the <code>x-hide-display</code> CSS class to
997 * prevent a brief flicker of the content before it is rendered to the panel.</div></li>
1001 * @cfg {String/Object} html
1002 * An HTML fragment, or a {@link Ext.DomHelper DomHelper} specification to use as the layout element
1003 * content (defaults to ''). The HTML content is added after the component is rendered,
1004 * so the document will not contain this HTML at the time the {@link #render} event is fired.
1005 * This content is inserted into the body <i>before</i> any configured {@link #contentEl} is appended.
1010 * An <bold>{@link Ext.Template}</bold>, <bold>{@link Ext.XTemplate}</bold>
1011 * or an array of strings to form an Ext.XTemplate.
1012 * Used in conjunction with the <code>{@link #data}</code> and
1013 * <code>{@link #tplWriteMode}</code> configurations.
1017 * @cfg {String} tplWriteMode The Ext.(X)Template method to use when
1018 * updating the content area of the Component. Defaults to <tt>'overwrite'</tt>
1019 * (see <code>{@link Ext.XTemplate#overwrite}</code>).
1021 tplWriteMode : 'overwrite',
1025 * The initial set of data to apply to the <code>{@link #tpl}</code> to
1026 * update the content area of the Component.
1030 * @cfg {Array} bubbleEvents
1031 * <p>An array of events that, when fired, should be bubbled to any parent container.
1032 * See {@link Ext.util.Observable#enableBubble}.
1033 * Defaults to <tt>[]</tt>.
1039 ctype : 'Ext.Component',
1045 getActionEl : function(){
1046 return this[this.actionMode];
1049 initPlugin : function(p){
1050 if(p.ptype && !Ext.isFunction(p.init)){
1051 p = Ext.ComponentMgr.createPlugin(p);
1052 }else if(Ext.isString(p)){
1053 p = Ext.ComponentMgr.createPlugin({
1062 * Function to be implemented by Component subclasses to be part of standard component initialization flow (it is empty by default).
1064 // Traditional constructor:
1065 Ext.Foo = function(config){
1066 // call superclass constructor:
1067 Ext.Foo.superclass.constructor.call(this, config);
1073 Ext.extend(Ext.Foo, Ext.Bar, {
1077 // initComponent replaces the constructor:
1078 Ext.Foo = Ext.extend(Ext.Bar, {
1079 initComponent : function(){
1080 // call superclass initComponent
1081 Ext.Container.superclass.initComponent.call(this);
1090 initComponent : function(){
1092 * this is double processing, however it allows people to be able to do
1098 * MyClass.superclass.initComponent.call(this);
1101 this.on(this.listeners);
1102 delete this.listeners;
1104 this.enableBubble(this.bubbleEvents);
1108 * <p>Render this Component into the passed HTML element.</p>
1109 * <p><b>If you are using a {@link Ext.Container Container} object to house this Component, then
1110 * do not use the render method.</b></p>
1111 * <p>A Container's child Components are rendered by that Container's
1112 * {@link Ext.Container#layout layout} manager when the Container is first rendered.</p>
1113 * <p>Certain layout managers allow dynamic addition of child components. Those that do
1114 * include {@link Ext.layout.CardLayout}, {@link Ext.layout.AnchorLayout},
1115 * {@link Ext.layout.FormLayout}, {@link Ext.layout.TableLayout}.</p>
1116 * <p>If the Container is already rendered when a new child Component is added, you may need to call
1117 * the Container's {@link Ext.Container#doLayout doLayout} to refresh the view which causes any
1118 * unrendered child Components to be rendered. This is required so that you can add multiple
1119 * child components if needed while only refreshing the layout once.</p>
1120 * <p>When creating complex UIs, it is important to remember that sizing and positioning
1121 * of child items is the responsibility of the Container's {@link Ext.Container#layout layout} manager.
1122 * If you expect child items to be sized in response to user interactions, you must
1123 * configure the Container with a layout manager which creates and manages the type of layout you
1125 * <p><b>Omitting the Container's {@link Ext.Container#layout layout} config means that a basic
1126 * layout manager is used which does nothing but render child components sequentially into the
1127 * Container. No sizing or positioning will be performed in this situation.</b></p>
1128 * @param {Element/HTMLElement/String} container (optional) The element this Component should be
1129 * rendered into. If it is being created from existing markup, this should be omitted.
1130 * @param {String/Number} position (optional) The element ID or DOM node index within the container <b>before</b>
1131 * which this component will be inserted (defaults to appending to the end of the container)
1133 render : function(container, position){
1134 if(!this.rendered && this.fireEvent('beforerender', this) !== false){
1135 if(!container && this.el){
1136 this.el = Ext.get(this.el);
1137 container = this.el.dom.parentNode;
1138 this.allowDomMove = false;
1140 this.container = Ext.get(container);
1142 this.container.addClass(this.ctCls);
1144 this.rendered = true;
1145 if(position !== undefined){
1146 if(Ext.isNumber(position)){
1147 position = this.container.dom.childNodes[position];
1149 position = Ext.getDom(position);
1152 this.onRender(this.container, position || null);
1154 this.el.removeClass(['x-hidden','x-hide-' + this.hideMode]);
1157 this.el.addClass(this.cls);
1161 this.el.applyStyles(this.style);
1165 this.el.addClassOnOver(this.overCls);
1167 this.fireEvent('render', this);
1170 // Populate content of the component with html, contentEl or
1172 var contentTarget = this.getContentTarget();
1174 contentTarget.update(Ext.DomHelper.markup(this.html));
1177 if (this.contentEl){
1178 var ce = Ext.getDom(this.contentEl);
1179 Ext.fly(ce).removeClass(['x-hidden', 'x-hide-display']);
1180 contentTarget.appendChild(ce);
1183 if (!this.tpl.compile) {
1184 this.tpl = new Ext.XTemplate(this.tpl);
1187 this.tpl[this.tplWriteMode](contentTarget, this.data);
1191 this.afterRender(this.container);
1195 // call this so we don't fire initial hide events.
1199 // pass silent so the event doesn't fire the first time.
1203 if(this.stateful !== false){
1204 this.initStateEvents();
1206 this.fireEvent('afterrender', this);
1213 * Update the content area of a component.
1214 * @param {Mixed} htmlOrData
1215 * If this component has been configured with a template via the tpl config
1216 * then it will use this argument as data to populate the template.
1217 * If this component was not configured with a template, the components
1218 * content area will be updated via Ext.Element update
1219 * @param {Boolean} loadScripts
1220 * (optional) Only legitimate when using the html configuration. Defaults to false
1221 * @param {Function} callback
1222 * (optional) Only legitimate when using the html configuration. Callback to execute when scripts have finished loading
1224 update: function(htmlOrData, loadScripts, cb) {
1225 var contentTarget = this.getContentTarget();
1226 if (this.tpl && typeof htmlOrData !== "string") {
1227 this.tpl[this.tplWriteMode](contentTarget, htmlOrData || {});
1229 var html = Ext.isObject(htmlOrData) ? Ext.DomHelper.markup(htmlOrData) : htmlOrData;
1230 contentTarget.update(html, loadScripts, cb);
1237 * Method to manage awareness of when components are added to their
1238 * respective Container, firing an added event.
1239 * References are established at add time rather than at render time.
1240 * @param {Ext.Container} container Container which holds the component
1241 * @param {number} pos Position at which the component was added
1243 onAdded : function(container, pos) {
1244 this.ownerCt = container;
1246 this.fireEvent('added', this, container, pos);
1251 * Method to manage awareness of when components are removed from their
1252 * respective Container, firing an removed event. References are properly
1253 * cleaned up after removing a component from its owning container.
1255 onRemoved : function() {
1257 this.fireEvent('removed', this, this.ownerCt);
1258 delete this.ownerCt;
1263 * Method to establish a reference to a component.
1265 initRef : function() {
1268 * <p>A path specification, relative to the Component's <code>{@link #ownerCt}</code>
1269 * specifying into which ancestor Container to place a named reference to this Component.</p>
1270 * <p>The ancestor axis can be traversed by using '/' characters in the path.
1271 * For example, to put a reference to a Toolbar Button into <i>the Panel which owns the Toolbar</i>:</p><pre><code>
1272 var myGrid = new Ext.grid.EditorGridPanel({
1273 title: 'My EditorGridPanel',
1275 colModel: myColModel,
1278 handler: saveChanges,
1280 ref: '../saveButton'
1283 afteredit: function() {
1284 // The button reference is in the GridPanel
1285 myGrid.saveButton.enable();
1290 * <p>In the code above, if the <code>ref</code> had been <code>'saveButton'</code>
1291 * the reference would have been placed into the Toolbar. Each '/' in the <code>ref</code>
1292 * moves up one level from the Component's <code>{@link #ownerCt}</code>.</p>
1293 * <p>Also see the <code>{@link #added}</code> and <code>{@link #removed}</code> events.</p>
1295 if(this.ref && !this.refOwner){
1296 var levels = this.ref.split('/'),
1297 last = levels.length,
1301 while(t && i < last){
1306 t[this.refName = levels[--i]] = this;
1308 * @type Ext.Container
1309 * @property refOwner
1310 * The ancestor Container into which the {@link #ref} reference was inserted if this Component
1311 * is a child of a Container, and has been configured with a <code>ref</code>.
1318 removeRef : function() {
1319 if (this.refOwner && this.refName) {
1320 delete this.refOwner[this.refName];
1321 delete this.refOwner;
1326 initState : function(){
1327 if(Ext.state.Manager){
1328 var id = this.getStateId();
1330 var state = Ext.state.Manager.get(id);
1332 if(this.fireEvent('beforestaterestore', this, state) !== false){
1333 this.applyState(Ext.apply({}, state));
1334 this.fireEvent('staterestore', this, state);
1342 getStateId : function(){
1343 return this.stateId || ((/^(ext-comp-|ext-gen)/).test(String(this.id)) ? null : this.id);
1347 initStateEvents : function(){
1348 if(this.stateEvents){
1349 for(var i = 0, e; e = this.stateEvents[i]; i++){
1350 this.on(e, this.saveState, this, {delay:100});
1356 applyState : function(state){
1358 Ext.apply(this, state);
1363 getState : function(){
1368 saveState : function(){
1369 if(Ext.state.Manager && this.stateful !== false){
1370 var id = this.getStateId();
1372 var state = this.getState();
1373 if(this.fireEvent('beforestatesave', this, state) !== false){
1374 Ext.state.Manager.set(id, state);
1375 this.fireEvent('statesave', this, state);
1382 * Apply this component to existing markup that is valid. With this function, no call to render() is required.
1383 * @param {String/HTMLElement} el
1385 applyToMarkup : function(el){
1386 this.allowDomMove = false;
1387 this.el = Ext.get(el);
1388 this.render(this.el.dom.parentNode);
1392 * Adds a CSS class to the component's underlying element.
1393 * @param {string} cls The CSS class name to add
1394 * @return {Ext.Component} this
1396 addClass : function(cls){
1398 this.el.addClass(cls);
1400 this.cls = this.cls ? this.cls + ' ' + cls : cls;
1406 * Removes a CSS class from the component's underlying element.
1407 * @param {string} cls The CSS class name to remove
1408 * @return {Ext.Component} this
1410 removeClass : function(cls){
1412 this.el.removeClass(cls);
1414 this.cls = this.cls.split(' ').remove(cls).join(' ');
1420 // default function is not really useful
1421 onRender : function(ct, position){
1422 if(!this.el && this.autoEl){
1423 if(Ext.isString(this.autoEl)){
1424 this.el = document.createElement(this.autoEl);
1426 var div = document.createElement('div');
1427 Ext.DomHelper.overwrite(div, this.autoEl);
1428 this.el = div.firstChild;
1431 this.el.id = this.getId();
1435 this.el = Ext.get(this.el);
1436 if(this.allowDomMove !== false){
1437 ct.dom.insertBefore(this.el.dom, position);
1439 Ext.removeNode(div);
1447 getAutoCreate : function(){
1448 var cfg = Ext.isObject(this.autoCreate) ?
1449 this.autoCreate : Ext.apply({}, this.defaultAutoCreate);
1450 if(this.id && !cfg.id){
1457 afterRender : Ext.emptyFn,
1460 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
1461 * removing the component from its {@link Ext.Container} (if applicable) and unregistering it from
1462 * {@link Ext.ComponentMgr}. Destruction is generally handled automatically by the framework and this method
1463 * should usually not need to be called directly.
1466 destroy : function(){
1467 if(!this.isDestroyed){
1468 if(this.fireEvent('beforedestroy', this) !== false){
1469 this.destroying = true;
1470 this.beforeDestroy();
1471 if(this.ownerCt && this.ownerCt.remove){
1472 this.ownerCt.remove(this, false);
1476 if(this.actionMode == 'container' || this.removeMode == 'container'){
1477 this.container.remove();
1480 // Stop any buffered tasks
1481 if(this.focusTask && this.focusTask.cancel){
1482 this.focusTask.cancel();
1485 Ext.ComponentMgr.unregister(this);
1486 this.fireEvent('destroy', this);
1487 this.purgeListeners();
1488 this.destroying = false;
1489 this.isDestroyed = true;
1494 deleteMembers : function(){
1495 var args = arguments;
1496 for(var i = 0, len = args.length; i < len; ++i){
1497 delete this[args[i]];
1502 beforeDestroy : Ext.emptyFn,
1505 onDestroy : Ext.emptyFn,
1508 * <p>Returns the {@link Ext.Element} which encapsulates this Component.</p>
1509 * <p>This will <i>usually</i> be a <DIV> element created by the class's onRender method, but
1510 * that may be overridden using the {@link #autoEl} config.</p>
1511 * <br><p><b>Note</b>: this element will not be available until this Component has been rendered.</p><br>
1512 * <p>To add listeners for <b>DOM events</b> to this Component (as opposed to listeners
1513 * for this Component's own Observable events), see the {@link #listeners} config for a suggestion,
1514 * or use a render listener directly:</p><pre><code>
1516 title: 'The Clickable Panel',
1518 render: function(p) {
1519 // Append the Panel to the click handler's argument list.
1520 p.getEl().on('click', handlePanelClick.createDelegate(null, [p], true));
1522 single: true // Remove the listener after first invocation
1526 * @return {Ext.Element} The Element which encapsulates this Component.
1533 getContentTarget : function(){
1538 * Returns the <code>id</code> of this component or automatically generates and
1539 * returns an <code>id</code> if an <code>id</code> is not defined yet:<pre><code>
1540 * 'ext-comp-' + (++Ext.Component.AUTO_ID)
1542 * @return {String} id
1545 return this.id || (this.id = 'ext-comp-' + (++Ext.Component.AUTO_ID));
1549 * Returns the <code>{@link #itemId}</code> of this component. If an
1550 * <code>{@link #itemId}</code> was not assigned through configuration the
1551 * <code>id</code> is returned using <code>{@link #getId}</code>.
1554 getItemId : function(){
1555 return this.itemId || this.getId();
1559 * Try to focus this component.
1560 * @param {Boolean} selectText (optional) If applicable, true to also select the text in this component
1561 * @param {Boolean/Number} delay (optional) Delay the focus this number of milliseconds (true for 10 milliseconds)
1562 * @return {Ext.Component} this
1564 focus : function(selectText, delay){
1566 this.focusTask = new Ext.util.DelayedTask(this.focus, this, [selectText, false]);
1567 this.focusTask.delay(Ext.isNumber(delay) ? delay : 10);
1570 if(this.rendered && !this.isDestroyed){
1572 if(selectText === true){
1573 this.el.dom.select();
1588 * Disable this component and fire the 'disable' event.
1589 * @return {Ext.Component} this
1591 disable : function(/* private */ silent){
1595 this.disabled = true;
1596 if(silent !== true){
1597 this.fireEvent('disable', this);
1603 onDisable : function(){
1604 this.getActionEl().addClass(this.disabledClass);
1605 this.el.dom.disabled = true;
1609 * Enable this component and fire the 'enable' event.
1610 * @return {Ext.Component} this
1612 enable : function(){
1616 this.disabled = false;
1617 this.fireEvent('enable', this);
1622 onEnable : function(){
1623 this.getActionEl().removeClass(this.disabledClass);
1624 this.el.dom.disabled = false;
1628 * Convenience function for setting disabled/enabled by boolean.
1629 * @param {Boolean} disabled
1630 * @return {Ext.Component} this
1632 setDisabled : function(disabled){
1633 return this[disabled ? 'disable' : 'enable']();
1637 * Show this component. Listen to the '{@link #beforeshow}' event and return
1638 * <tt>false</tt> to cancel showing the component. Fires the '{@link #show}'
1639 * event after showing the component.
1640 * @return {Ext.Component} this
1643 if(this.fireEvent('beforeshow', this) !== false){
1644 this.hidden = false;
1645 if(this.autoRender){
1646 this.render(Ext.isBoolean(this.autoRender) ? Ext.getBody() : this.autoRender);
1651 this.fireEvent('show', this);
1657 onShow : function(){
1658 this.getVisibilityEl().removeClass('x-hide-' + this.hideMode);
1662 * Hide this component. Listen to the '{@link #beforehide}' event and return
1663 * <tt>false</tt> to cancel hiding the component. Fires the '{@link #hide}'
1664 * event after hiding the component. Note this method is called internally if
1665 * the component is configured to be <code>{@link #hidden}</code>.
1666 * @return {Ext.Component} this
1669 if(this.fireEvent('beforehide', this) !== false){
1671 this.fireEvent('hide', this);
1685 onHide : function(){
1686 this.getVisibilityEl().addClass('x-hide-' + this.hideMode);
1690 getVisibilityEl : function(){
1691 return this.hideParent ? this.container : this.getActionEl();
1695 * Convenience function to hide or show this component by boolean.
1696 * @param {Boolean} visible True to show, false to hide
1697 * @return {Ext.Component} this
1699 setVisible : function(visible){
1700 return this[visible ? 'show' : 'hide']();
1704 * Returns true if this component is visible.
1705 * @return {Boolean} True if this component is visible, false otherwise.
1707 isVisible : function(){
1708 return this.rendered && this.getVisibilityEl().isVisible();
1712 * Clone the current component using the original config values passed into this instance by default.
1713 * @param {Object} overrides A new config containing any properties to override in the cloned version.
1714 * An id property can be passed on this object, otherwise one will be generated to avoid duplicates.
1715 * @return {Ext.Component} clone The cloned copy of this component
1717 cloneConfig : function(overrides){
1718 overrides = overrides || {};
1719 var id = overrides.id || Ext.id();
1720 var cfg = Ext.applyIf(overrides, this.initialConfig);
1721 cfg.id = id; // prevent dup id
1722 return new this.constructor(cfg);
1726 * Gets the xtype for this component as registered with {@link Ext.ComponentMgr}. For a list of all
1727 * available xtypes, see the {@link Ext.Component} header. Example usage:
1729 var t = new Ext.form.TextField();
1730 alert(t.getXType()); // alerts 'textfield'
1732 * @return {String} The xtype
1734 getXType : function(){
1735 return this.constructor.xtype;
1739 * <p>Tests whether or not this Component is of a specific xtype. This can test whether this Component is descended
1740 * from the xtype (default) or whether it is directly of the xtype specified (shallow = true).</p>
1741 * <p><b>If using your own subclasses, be aware that a Component must register its own xtype
1742 * to participate in determination of inherited xtypes.</b></p>
1743 * <p>For a list of all available xtypes, see the {@link Ext.Component} header.</p>
1744 * <p>Example usage:</p>
1746 var t = new Ext.form.TextField();
1747 var isText = t.isXType('textfield'); // true
1748 var isBoxSubclass = t.isXType('box'); // true, descended from BoxComponent
1749 var isBoxInstance = t.isXType('box', true); // false, not a direct BoxComponent instance
1751 * @param {String} xtype The xtype to check for this Component
1752 * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
1753 * the default), or true to check whether this Component is directly of the specified xtype.
1754 * @return {Boolean} True if this component descends from the specified xtype, false otherwise.
1756 isXType : function(xtype, shallow){
1757 //assume a string by default
1758 if (Ext.isFunction(xtype)){
1759 xtype = xtype.xtype; //handle being passed the class, e.g. Ext.Component
1760 }else if (Ext.isObject(xtype)){
1761 xtype = xtype.constructor.xtype; //handle being passed an instance
1764 return !shallow ? ('/' + this.getXTypes() + '/').indexOf('/' + xtype + '/') != -1 : this.constructor.xtype == xtype;
1768 * <p>Returns this Component's xtype hierarchy as a slash-delimited string. For a list of all
1769 * available xtypes, see the {@link Ext.Component} header.</p>
1770 * <p><b>If using your own subclasses, be aware that a Component must register its own xtype
1771 * to participate in determination of inherited xtypes.</b></p>
1772 * <p>Example usage:</p>
1774 var t = new Ext.form.TextField();
1775 alert(t.getXTypes()); // alerts 'component/box/field/textfield'
1777 * @return {String} The xtype hierarchy string
1779 getXTypes : function(){
1780 var tc = this.constructor;
1782 var c = [], sc = this;
1783 while(sc && sc.constructor.xtype){
1784 c.unshift(sc.constructor.xtype);
1785 sc = sc.constructor.superclass;
1788 tc.xtypes = c.join('/');
1794 * Find a container above this component at any level by a custom function. If the passed function returns
1795 * true, the container will be returned.
1796 * @param {Function} fn The custom function to call with the arguments (container, this component).
1797 * @return {Ext.Container} The first Container for which the custom function returns true
1799 findParentBy : function(fn) {
1800 for (var p = this.ownerCt; (p != null) && !fn(p, this); p = p.ownerCt);
1805 * Find a container above this component at any level by xtype or class
1806 * @param {String/Class} xtype The xtype string for a component, or the class of the component directly
1807 * @return {Ext.Container} The first Container which matches the given xtype or class
1809 findParentByType : function(xtype) {
1810 return Ext.isFunction(xtype) ?
1811 this.findParentBy(function(p){
1812 return p.constructor === xtype;
1814 this.findParentBy(function(p){
1815 return p.constructor.xtype === xtype;
1820 getPositionEl : function(){
1821 return this.positionEl || this.el;
1825 purgeListeners : function(){
1826 Ext.Component.superclass.purgeListeners.call(this);
1828 this.on('beforedestroy', this.clearMons, this, {single: true});
1833 clearMons : function(){
1834 Ext.each(this.mons, function(m){
1835 m.item.un(m.ename, m.fn, m.scope);
1841 createMons: function(){
1844 this.on('beforedestroy', this.clearMons, this, {single: true});
1849 * <p>Adds listeners to any Observable object (or Elements) which are automatically removed when this Component
1850 * is destroyed. Usage:</p><code><pre>
1851 myGridPanel.mon(myGridPanel.getSelectionModel(), 'selectionchange', handleSelectionChange, null, {buffer: 50});
1853 * <p>or:</p><code><pre>
1854 myGridPanel.mon(myGridPanel.getSelectionModel(), {
1855 selectionchange: handleSelectionChange,
1859 * @param {Observable|Element} item The item to which to add a listener/listeners.
1860 * @param {Object|String} ename The event name, or an object containing event name properties.
1861 * @param {Function} fn Optional. If the <code>ename</code> parameter was an event name, this
1862 * is the handler function.
1863 * @param {Object} scope Optional. If the <code>ename</code> parameter was an event name, this
1864 * is the scope (<code>this</code> reference) in which the handler function is executed.
1865 * @param {Object} opt Optional. If the <code>ename</code> parameter was an event name, this
1866 * is the {@link Ext.util.Observable#addListener addListener} options.
1868 mon : function(item, ename, fn, scope, opt){
1870 if(Ext.isObject(ename)){
1871 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
1878 if(Ext.isFunction(o[e])){
1881 item: item, ename: e, fn: o[e], scope: o.scope
1883 item.on(e, o[e], o.scope, o);
1885 // individual options
1887 item: item, ename: e, fn: o[e], scope: o.scope
1896 item: item, ename: ename, fn: fn, scope: scope
1898 item.on(ename, fn, scope, opt);
1902 * Removes listeners that were added by the {@link #mon} method.
1903 * @param {Observable|Element} item The item from which to remove a listener/listeners.
1904 * @param {Object|String} ename The event name, or an object containing event name properties.
1905 * @param {Function} fn Optional. If the <code>ename</code> parameter was an event name, this
1906 * is the handler function.
1907 * @param {Object} scope Optional. If the <code>ename</code> parameter was an event name, this
1908 * is the scope (<code>this</code> reference) in which the handler function is executed.
1910 mun : function(item, ename, fn, scope){
1913 for(var i = 0, len = this.mons.length; i < len; ++i){
1915 if(item === mon.item && ename == mon.ename && fn === mon.fn && scope === mon.scope){
1916 this.mons.splice(i, 1);
1917 item.un(ename, fn, scope);
1926 * Returns the next component in the owning container
1927 * @return Ext.Component
1929 nextSibling : function(){
1931 var index = this.ownerCt.items.indexOf(this);
1932 if(index != -1 && index+1 < this.ownerCt.items.getCount()){
1933 return this.ownerCt.items.itemAt(index+1);
1940 * Returns the previous component in the owning container
1941 * @return Ext.Component
1943 previousSibling : function(){
1945 var index = this.ownerCt.items.indexOf(this);
1947 return this.ownerCt.items.itemAt(index-1);
1954 * Provides the link for Observable's fireEvent method to bubble up the ownership hierarchy.
1955 * @return {Ext.Container} the Container which owns this Component.
1957 getBubbleTarget : function(){
1958 return this.ownerCt;
1962 Ext.reg('component', Ext.Component);/**
1964 * <p>An Action is a piece of reusable functionality that can be abstracted out of any particular component so that it
1965 * can be usefully shared among multiple components. Actions let you share handlers, configuration options and UI
1966 * updates across any components that support the Action interface (primarily {@link Ext.Toolbar}, {@link Ext.Button}
1967 * and {@link Ext.menu.Menu} components).</p>
1968 * <p>Aside from supporting the config object interface, any component that needs to use Actions must also support
1969 * the following method list, as these will be called as needed by the Action class: setText(string), setIconCls(string),
1970 * setDisabled(boolean), setVisible(boolean) and setHandler(function).</p>
1971 * Example usage:<br>
1973 // Define the shared action. Each component below will have the same
1974 // display text and icon, and will display the same message on click.
1975 var action = new Ext.Action({
1976 {@link #text}: 'Do something',
1977 {@link #handler}: function(){
1978 Ext.Msg.alert('Click', 'You did something.');
1980 {@link #iconCls}: 'do-something',
1981 {@link #itemId}: 'myAction'
1984 var panel = new Ext.Panel({
1989 // Add the action directly to a toolbar as a menu button
1992 text: 'Action Menu',
1993 // Add the action to a menu as a text item
1998 // Add the action to the panel body as a standard button
1999 new Ext.Button(action)
2001 renderTo: Ext.getBody()
2004 // Change the text for all components using the action
2005 action.setText('Something else');
2007 // Reference an action through a container using the itemId
2008 var btn = panel.getComponent('myAction');
2009 var aRef = btn.baseAction;
2010 aRef.setText('New text');
2013 * @param {Object} config The configuration options
2015 Ext.Action = Ext.extend(Object, {
2017 * @cfg {String} text The text to set for all components using this action (defaults to '').
2020 * @cfg {String} iconCls
2021 * The CSS class selector that specifies a background image to be used as the header icon for
2022 * all components using this action (defaults to '').
2023 * <p>An example of specifying a custom icon class would be something like:
2025 // specify the property in the config for the class:
2027 iconCls: 'do-something'
2029 // css class that specifies background image to be used as the icon image:
2030 .do-something { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
2034 * @cfg {Boolean} disabled True to disable all components using this action, false to enable them (defaults to false).
2037 * @cfg {Boolean} hidden True to hide all components using this action, false to show them (defaults to false).
2040 * @cfg {Function} handler The function that will be invoked by each component tied to this action
2041 * when the component's primary event is triggered (defaults to undefined).
2044 * @cfg {String} itemId
2045 * See {@link Ext.Component}.{@link Ext.Component#itemId itemId}.
2048 * @cfg {Object} scope The scope (<tt><b>this</b></tt> reference) in which the
2049 * <code>{@link #handler}</code> is executed. Defaults to this Button.
2052 constructor : function(config){
2053 this.initialConfig = config;
2054 this.itemId = config.itemId = (config.itemId || config.id || Ext.id());
2062 * Sets the text to be displayed by all components using this action.
2063 * @param {String} text The text to display
2065 setText : function(text){
2066 this.initialConfig.text = text;
2067 this.callEach('setText', [text]);
2071 * Gets the text currently displayed by all components using this action.
2073 getText : function(){
2074 return this.initialConfig.text;
2078 * Sets the icon CSS class for all components using this action. The class should supply
2079 * a background image that will be used as the icon image.
2080 * @param {String} cls The CSS class supplying the icon image
2082 setIconClass : function(cls){
2083 this.initialConfig.iconCls = cls;
2084 this.callEach('setIconClass', [cls]);
2088 * Gets the icon CSS class currently used by all components using this action.
2090 getIconClass : function(){
2091 return this.initialConfig.iconCls;
2095 * Sets the disabled state of all components using this action. Shortcut method
2096 * for {@link #enable} and {@link #disable}.
2097 * @param {Boolean} disabled True to disable the component, false to enable it
2099 setDisabled : function(v){
2100 this.initialConfig.disabled = v;
2101 this.callEach('setDisabled', [v]);
2105 * Enables all components using this action.
2107 enable : function(){
2108 this.setDisabled(false);
2112 * Disables all components using this action.
2114 disable : function(){
2115 this.setDisabled(true);
2119 * Returns true if the components using this action are currently disabled, else returns false.
2121 isDisabled : function(){
2122 return this.initialConfig.disabled;
2126 * Sets the hidden state of all components using this action. Shortcut method
2127 * for <code>{@link #hide}</code> and <code>{@link #show}</code>.
2128 * @param {Boolean} hidden True to hide the component, false to show it
2130 setHidden : function(v){
2131 this.initialConfig.hidden = v;
2132 this.callEach('setVisible', [!v]);
2136 * Shows all components using this action.
2139 this.setHidden(false);
2143 * Hides all components using this action.
2146 this.setHidden(true);
2150 * Returns true if the components using this action are currently hidden, else returns false.
2152 isHidden : function(){
2153 return this.initialConfig.hidden;
2157 * Sets the function that will be called by each Component using this action when its primary event is triggered.
2158 * @param {Function} fn The function that will be invoked by the action's components. The function
2159 * will be called with no arguments.
2160 * @param {Object} scope The scope (<code>this</code> reference) in which the function is executed. Defaults to the Component firing the event.
2162 setHandler : function(fn, scope){
2163 this.initialConfig.handler = fn;
2164 this.initialConfig.scope = scope;
2165 this.callEach('setHandler', [fn, scope]);
2169 * Executes the specified function once for each Component currently tied to this action. The function passed
2170 * in should accept a single argument that will be an object that supports the basic Action config/method interface.
2171 * @param {Function} fn The function to execute for each component
2172 * @param {Object} scope The scope (<code>this</code> reference) in which the function is executed. Defaults to the Component.
2174 each : function(fn, scope){
2175 Ext.each(this.items, fn, scope);
2179 callEach : function(fnName, args){
2180 var cs = this.items;
2181 for(var i = 0, len = cs.length; i < len; i++){
2182 cs[i][fnName].apply(cs[i], args);
2187 addComponent : function(comp){
2188 this.items.push(comp);
2189 comp.on('destroy', this.removeComponent, this);
2193 removeComponent : function(comp){
2194 this.items.remove(comp);
2198 * Executes this action manually using the handler function specified in the original config object
2199 * or the handler function set with <code>{@link #setHandler}</code>. Any arguments passed to this
2200 * function will be passed on to the handler function.
2201 * @param {Mixed} arg1 (optional) Variable number of arguments passed to the handler function
2202 * @param {Mixed} arg2 (optional)
2203 * @param {Mixed} etc... (optional)
2205 execute : function(){
2206 this.initialConfig.handler.apply(this.initialConfig.scope || window, arguments);
2211 * @extends Ext.Element
2212 * An extended {@link Ext.Element} object that supports a shadow and shim, constrain to viewport and
2213 * automatic maintaining of shadow/shim positions.
2214 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
2215 * @cfg {String/Boolean} shadow True to automatically create an {@link Ext.Shadow}, or a string indicating the
2216 * shadow's display {@link Ext.Shadow#mode}. False to disable the shadow. (defaults to false)
2217 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: 'div', cls: 'x-layer'}).
2218 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
2219 * @cfg {String} cls CSS class to add to the element
2220 * @cfg {Number} zindex Starting z-index (defaults to 11000)
2221 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 4)
2222 * @cfg {Boolean} useDisplay
2223 * Defaults to use css offsets to hide the Layer. Specify <tt>true</tt>
2224 * to use css style <tt>'display:none;'</tt> to hide the Layer.
2226 * @param {Object} config An object with config options.
2227 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
2230 Ext.Layer = function(config, existingEl){
2231 config = config || {};
2232 var dh = Ext.DomHelper;
2233 var cp = config.parentEl, pel = cp ? Ext.getDom(cp) : document.body;
2235 this.dom = Ext.getDom(existingEl);
2238 var o = config.dh || {tag: 'div', cls: 'x-layer'};
2239 this.dom = dh.append(pel, o);
2242 this.addClass(config.cls);
2244 this.constrain = config.constrain !== false;
2245 this.setVisibilityMode(Ext.Element.VISIBILITY);
2247 this.id = this.dom.id = config.id;
2249 this.id = Ext.id(this.dom);
2251 this.zindex = config.zindex || this.getZIndex();
2252 this.position('absolute', this.zindex);
2254 this.shadowOffset = config.shadowOffset || 4;
2255 this.shadow = new Ext.Shadow({
2256 offset : this.shadowOffset,
2257 mode : config.shadow
2260 this.shadowOffset = 0;
2262 this.useShim = config.shim !== false && Ext.useShims;
2263 this.useDisplay = config.useDisplay;
2267 var supr = Ext.Element.prototype;
2269 // shims are shared among layer to keep from having 100 iframes
2272 Ext.extend(Ext.Layer, Ext.Element, {
2274 getZIndex : function(){
2275 return this.zindex || parseInt((this.getShim() || this).getStyle('z-index'), 10) || 11000;
2278 getShim : function(){
2285 var shim = shims.shift();
2287 shim = this.createShim();
2288 shim.enableDisplayMode('block');
2289 shim.dom.style.display = 'none';
2290 shim.dom.style.visibility = 'visible';
2292 var pn = this.dom.parentNode;
2293 if(shim.dom.parentNode != pn){
2294 pn.insertBefore(shim.dom, this.dom);
2296 shim.setStyle('z-index', this.getZIndex()-2);
2301 hideShim : function(){
2303 this.shim.setDisplayed(false);
2304 shims.push(this.shim);
2309 disableShadow : function(){
2311 this.shadowDisabled = true;
2313 this.lastShadowOffset = this.shadowOffset;
2314 this.shadowOffset = 0;
2318 enableShadow : function(show){
2320 this.shadowDisabled = false;
2321 this.shadowOffset = this.lastShadowOffset;
2322 delete this.lastShadowOffset;
2330 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
2331 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
2332 sync : function(doShow){
2333 var shadow = this.shadow;
2334 if(!this.updating && this.isVisible() && (shadow || this.useShim)){
2335 var shim = this.getShim(),
2336 w = this.getWidth(),
2337 h = this.getHeight(),
2338 l = this.getLeft(true),
2339 t = this.getTop(true);
2341 if(shadow && !this.shadowDisabled){
2342 if(doShow && !shadow.isVisible()){
2345 shadow.realign(l, t, w, h);
2351 // fit the shim behind the shadow, so it is shimmed too
2352 var shadowAdj = shadow.el.getXY(), shimStyle = shim.dom.style,
2353 shadowSize = shadow.el.getSize();
2354 shimStyle.left = (shadowAdj[0])+'px';
2355 shimStyle.top = (shadowAdj[1])+'px';
2356 shimStyle.width = (shadowSize.width)+'px';
2357 shimStyle.height = (shadowSize.height)+'px';
2364 shim.setLeftTop(l, t);
2370 destroy : function(){
2375 this.removeAllListeners();
2376 Ext.removeNode(this.dom);
2380 remove : function(){
2385 beginUpdate : function(){
2386 this.updating = true;
2390 endUpdate : function(){
2391 this.updating = false;
2396 hideUnders : function(negOffset){
2404 constrainXY : function(){
2406 var vw = Ext.lib.Dom.getViewWidth(),
2407 vh = Ext.lib.Dom.getViewHeight();
2408 var s = Ext.getDoc().getScroll();
2410 var xy = this.getXY();
2411 var x = xy[0], y = xy[1];
2412 var so = this.shadowOffset;
2413 var w = this.dom.offsetWidth+so, h = this.dom.offsetHeight+so;
2414 // only move it if it needs it
2416 // first validate right/bottom
2417 if((x + w) > vw+s.left){
2421 if((y + h) > vh+s.top){
2425 // then make sure top/left isn't negative
2436 var ay = this.avoidY;
2437 if(y <= ay && (y+h) >= ay){
2443 supr.setXY.call(this, xy);
2450 isVisible : function(){
2451 return this.visible;
2455 showAction : function(){
2456 this.visible = true; // track visibility to prevent getStyle calls
2457 if(this.useDisplay === true){
2458 this.setDisplayed('');
2459 }else if(this.lastXY){
2460 supr.setXY.call(this, this.lastXY);
2461 }else if(this.lastLT){
2462 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
2467 hideAction : function(){
2468 this.visible = false;
2469 if(this.useDisplay === true){
2470 this.setDisplayed(false);
2472 this.setLeftTop(-10000,-10000);
2476 // overridden Element method
2477 setVisible : function(v, a, d, c, e){
2482 var cb = function(){
2487 }.createDelegate(this);
2488 supr.setVisible.call(this, true, true, d, cb, e);
2491 this.hideUnders(true);
2500 }.createDelegate(this);
2502 supr.setVisible.call(this, v, a, d, cb, e);
2512 storeXY : function(xy){
2517 storeLeftTop : function(left, top){
2519 this.lastLT = [left, top];
2523 beforeFx : function(){
2524 this.beforeAction();
2525 return Ext.Layer.superclass.beforeFx.apply(this, arguments);
2529 afterFx : function(){
2530 Ext.Layer.superclass.afterFx.apply(this, arguments);
2531 this.sync(this.isVisible());
2535 beforeAction : function(){
2536 if(!this.updating && this.shadow){
2541 // overridden Element method
2542 setLeft : function(left){
2543 this.storeLeftTop(left, this.getTop(true));
2544 supr.setLeft.apply(this, arguments);
2549 setTop : function(top){
2550 this.storeLeftTop(this.getLeft(true), top);
2551 supr.setTop.apply(this, arguments);
2556 setLeftTop : function(left, top){
2557 this.storeLeftTop(left, top);
2558 supr.setLeftTop.apply(this, arguments);
2563 setXY : function(xy, a, d, c, e){
2565 this.beforeAction();
2567 var cb = this.createCB(c);
2568 supr.setXY.call(this, xy, a, d, cb, e);
2576 createCB : function(c){
2587 // overridden Element method
2588 setX : function(x, a, d, c, e){
2589 this.setXY([x, this.getY()], a, d, c, e);
2593 // overridden Element method
2594 setY : function(y, a, d, c, e){
2595 this.setXY([this.getX(), y], a, d, c, e);
2599 // overridden Element method
2600 setSize : function(w, h, a, d, c, e){
2601 this.beforeAction();
2602 var cb = this.createCB(c);
2603 supr.setSize.call(this, w, h, a, d, cb, e);
2610 // overridden Element method
2611 setWidth : function(w, a, d, c, e){
2612 this.beforeAction();
2613 var cb = this.createCB(c);
2614 supr.setWidth.call(this, w, a, d, cb, e);
2621 // overridden Element method
2622 setHeight : function(h, a, d, c, e){
2623 this.beforeAction();
2624 var cb = this.createCB(c);
2625 supr.setHeight.call(this, h, a, d, cb, e);
2632 // overridden Element method
2633 setBounds : function(x, y, w, h, a, d, c, e){
2634 this.beforeAction();
2635 var cb = this.createCB(c);
2637 this.storeXY([x, y]);
2638 supr.setXY.call(this, [x, y]);
2639 supr.setSize.call(this, w, h, a, d, cb, e);
2642 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
2648 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
2649 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
2650 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
2651 * @param {Number} zindex The new z-index to set
2652 * @return {this} The Layer
2654 setZIndex : function(zindex){
2655 this.zindex = zindex;
2656 this.setStyle('z-index', zindex + 2);
2658 this.shadow.setZIndex(zindex + 1);
2661 this.shim.setStyle('z-index', zindex);
2669 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
2670 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
2671 * functionality that can also provide the same shadow effect, see the {@link Ext.Layer} class.
2673 * Create a new Shadow
2674 * @param {Object} config The config object
2676 Ext.Shadow = function(config){
2677 Ext.apply(this, config);
2678 if(typeof this.mode != "string"){
2679 this.mode = this.defaultMode;
2681 var o = this.offset, a = {h: 0};
2682 var rad = Math.floor(this.offset/2);
2683 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
2689 a.l -= this.offset + rad;
2690 a.t -= this.offset + rad;
2701 a.l -= (this.offset - rad);
2702 a.t -= this.offset + rad;
2704 a.w -= (this.offset - rad)*2;
2715 a.l -= (this.offset - rad);
2716 a.t -= (this.offset - rad);
2718 a.w -= (this.offset + rad + 1);
2719 a.h -= (this.offset + rad);
2728 Ext.Shadow.prototype = {
2730 * @cfg {String} mode
2731 * The shadow display mode. Supports the following options:<div class="mdetail-params"><ul>
2732 * <li><b><tt>sides</tt></b> : Shadow displays on both sides and bottom only</li>
2733 * <li><b><tt>frame</tt></b> : Shadow displays equally on all four sides</li>
2734 * <li><b><tt>drop</tt></b> : Traditional bottom-right drop shadow</li>
2738 * @cfg {String} offset
2739 * The number of pixels to offset the shadow from the element (defaults to <tt>4</tt>)
2744 defaultMode: "drop",
2747 * Displays the shadow under the target element
2748 * @param {Mixed} targetEl The id or element under which the shadow should display
2750 show : function(target){
2751 target = Ext.get(target);
2753 this.el = Ext.Shadow.Pool.pull();
2754 if(this.el.dom.nextSibling != target.dom){
2755 this.el.insertBefore(target);
2758 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
2760 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
2763 target.getLeft(true),
2764 target.getTop(true),
2768 this.el.dom.style.display = "block";
2772 * Returns true if the shadow is visible, else false
2774 isVisible : function(){
2775 return this.el ? true : false;
2779 * Direct alignment when values are already available. Show must be called at least once before
2780 * calling this method to ensure it is initialized.
2781 * @param {Number} left The target element left position
2782 * @param {Number} top The target element top position
2783 * @param {Number} width The target element width
2784 * @param {Number} height The target element height
2786 realign : function(l, t, w, h){
2790 var a = this.adjusts, d = this.el.dom, s = d.style;
2792 s.left = (l+a.l)+"px";
2793 s.top = (t+a.t)+"px";
2794 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
2795 if(s.width != sws || s.height != shs){
2799 var cn = d.childNodes;
2800 var sww = Math.max(0, (sw-12))+"px";
2801 cn[0].childNodes[1].style.width = sww;
2802 cn[1].childNodes[1].style.width = sww;
2803 cn[2].childNodes[1].style.width = sww;
2804 cn[1].style.height = Math.max(0, (sh-12))+"px";
2814 this.el.dom.style.display = "none";
2815 Ext.Shadow.Pool.push(this.el);
2821 * Adjust the z-index of this shadow
2822 * @param {Number} zindex The new z-index
2824 setZIndex : function(z){
2827 this.el.setStyle("z-index", z);
2832 // Private utility class that manages the internal Shadow cache
2833 Ext.Shadow.Pool = function(){
2835 var markup = Ext.isIE ?
2836 '<div class="x-ie-shadow"></div>' :
2837 '<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>';
2842 sh = Ext.get(Ext.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
2843 sh.autoBoxAdjust = false;
2848 push : function(sh){
2853 * @class Ext.BoxComponent
2854 * @extends Ext.Component
2855 * <p>Base class for any {@link Ext.Component Component} that is to be sized as a box, using width and height.</p>
2856 * <p>BoxComponent provides automatic box model adjustments for sizing and positioning and will work correctly
2857 * within the Component rendering model.</p>
2858 * <p>A BoxComponent may be created as a custom Component which encapsulates any HTML element, either a pre-existing
2859 * element, or one that is created to your specifications at render time. Usually, to participate in layouts,
2860 * a Component will need to be a <b>Box</b>Component in order to have its width and height managed.</p>
2861 * <p>To use a pre-existing element as a BoxComponent, configure it so that you preset the <b>el</b> property to the
2862 * element to reference:<pre><code>
2863 var pageHeader = new Ext.BoxComponent({
2866 * This may then be {@link Ext.Container#add added} to a {@link Ext.Container Container} as a child item.</p>
2867 * <p>To create a BoxComponent based around a HTML element to be created at render time, use the
2868 * {@link Ext.Component#autoEl autoEl} config option which takes the form of a
2869 * {@link Ext.DomHelper DomHelper} specification:<pre><code>
2870 var myImage = new Ext.BoxComponent({
2873 src: '/images/my-image.jpg'
2875 });</code></pre></p>
2877 * @param {Ext.Element/String/Object} config The configuration options.
2880 Ext.BoxComponent = Ext.extend(Ext.Component, {
2882 // Configs below are used for all Components when rendered by BoxLayout.
2884 * @cfg {Number} flex
2885 * <p><b>Note</b>: this config is only used when this Component is rendered
2886 * by a Container which has been configured to use a <b>{@link Ext.layout.BoxLayout BoxLayout}.</b>
2887 * Each child Component with a <code>flex</code> property will be flexed either vertically (by a VBoxLayout)
2888 * or horizontally (by an HBoxLayout) according to the item's <b>relative</b> <code>flex</code> value
2889 * compared to the sum of all Components with <code>flex</flex> value specified. Any child items that have
2890 * either a <code>flex = 0</code> or <code>flex = undefined</code> will not be 'flexed' (the initial size will not be changed).
2892 // Configs below are used for all Components when rendered by AnchorLayout.
2894 * @cfg {String} anchor <p><b>Note</b>: this config is only used when this Component is rendered
2895 * by a Container which has been configured to use an <b>{@link Ext.layout.AnchorLayout AnchorLayout} (or subclass thereof).</b>
2896 * based layout manager, for example:<div class="mdetail-params"><ul>
2897 * <li>{@link Ext.form.FormPanel}</li>
2898 * <li>specifying <code>layout: 'anchor' // or 'form', or 'absolute'</code></li>
2900 * <p>See {@link Ext.layout.AnchorLayout}.{@link Ext.layout.AnchorLayout#anchor anchor} also.</p>
2902 // tabTip config is used when a BoxComponent is a child of a TabPanel
2904 * @cfg {String} tabTip
2905 * <p><b>Note</b>: this config is only used when this BoxComponent is a child item of a TabPanel.</p>
2906 * A string to be used as innerHTML (html tags are accepted) to show in a tooltip when mousing over
2907 * the associated tab selector element. {@link Ext.QuickTips}.init()
2908 * must be called in order for the tips to render.
2910 // Configs below are used for all Components when rendered by BorderLayout.
2912 * @cfg {String} region <p><b>Note</b>: this config is only used when this BoxComponent is rendered
2913 * by a Container which has been configured to use the <b>{@link Ext.layout.BorderLayout BorderLayout}</b>
2914 * layout manager (e.g. specifying <tt>layout:'border'</tt>).</p><br>
2915 * <p>See {@link Ext.layout.BorderLayout} also.</p>
2917 // margins config is used when a BoxComponent is rendered by BorderLayout or BoxLayout.
2919 * @cfg {Object} margins <p><b>Note</b>: this config is only used when this BoxComponent is rendered
2920 * by a Container which has been configured to use the <b>{@link Ext.layout.BorderLayout BorderLayout}</b>
2921 * or one of the two <b>{@link Ext.layout.BoxLayout BoxLayout} subclasses.</b></p>
2922 * <p>An object containing margins to apply to this BoxComponent in the
2923 * format:</p><pre><code>
2926 right: (right margin),
2927 bottom: (bottom margin),
2930 * <p>May also be a string containing space-separated, numeric margin values. The order of the
2931 * sides associated with each value matches the way CSS processes margin values:</p>
2932 * <p><div class="mdetail-params"><ul>
2933 * <li>If there is only one value, it applies to all sides.</li>
2934 * <li>If there are two values, the top and bottom borders are set to the first value and the
2935 * right and left are set to the second.</li>
2936 * <li>If there are three values, the top is set to the first value, the left and right are set
2937 * to the second, and the bottom is set to the third.</li>
2938 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
2940 * <p>Defaults to:</p><pre><code>
2941 * {top:0, right:0, bottom:0, left:0}
2946 * The local x (left) coordinate for this component if contained within a positioning container.
2950 * The local y (top) coordinate for this component if contained within a positioning container.
2953 * @cfg {Number} pageX
2954 * The page level x coordinate for this component if contained within a positioning container.
2957 * @cfg {Number} pageY
2958 * The page level y coordinate for this component if contained within a positioning container.
2961 * @cfg {Number} height
2962 * The height of this component in pixels (defaults to auto).
2963 * <b>Note</b> to express this dimension as a percentage or offset see {@link Ext.Component#anchor}.
2966 * @cfg {Number} width
2967 * The width of this component in pixels (defaults to auto).
2968 * <b>Note</b> to express this dimension as a percentage or offset see {@link Ext.Component#anchor}.
2971 * @cfg {Number} boxMinHeight
2972 * <p>The minimum value in pixels which this BoxComponent will set its height to.</p>
2973 * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
2976 * @cfg {Number} boxMinWidth
2977 * <p>The minimum value in pixels which this BoxComponent will set its width to.</p>
2978 * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
2981 * @cfg {Number} boxMaxHeight
2982 * <p>The maximum value in pixels which this BoxComponent will set its height to.</p>
2983 * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
2986 * @cfg {Number} boxMaxWidth
2987 * <p>The maximum value in pixels which this BoxComponent will set its width to.</p>
2988 * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
2991 * @cfg {Boolean} autoHeight
2992 * <p>True to use height:'auto', false to use fixed height (or allow it to be managed by its parent
2993 * Container's {@link Ext.Container#layout layout manager}. Defaults to false.</p>
2994 * <p><b>Note</b>: Although many components inherit this config option, not all will
2995 * function as expected with a height of 'auto'. Setting autoHeight:true means that the
2996 * browser will manage height based on the element's contents, and that Ext will not manage it at all.</p>
2997 * <p>If the <i>browser</i> is managing the height, be aware that resizes performed by the browser in response
2998 * to changes within the structure of the Component cannot be detected. Therefore changes to the height might
2999 * result in elements needing to be synchronized with the new height. Example:</p><pre><code>
3000 var w = new Ext.Window({
3005 title: 'Collapse Me',
3010 beforecollapse: function() {
3013 beforeexpand: function() {
3016 collapse: function() {
3019 expand: function() {
3028 * @cfg {Boolean} autoWidth
3029 * <p>True to use width:'auto', false to use fixed width (or allow it to be managed by its parent
3030 * Container's {@link Ext.Container#layout layout manager}. Defaults to false.</p>
3031 * <p><b>Note</b>: Although many components inherit this config option, not all will
3032 * function as expected with a width of 'auto'. Setting autoWidth:true means that the
3033 * browser will manage width based on the element's contents, and that Ext will not manage it at all.</p>
3034 * <p>If the <i>browser</i> is managing the width, be aware that resizes performed by the browser in response
3035 * to changes within the structure of the Component cannot be detected. Therefore changes to the width might
3036 * result in elements needing to be synchronized with the new width. For example, where the target element is:</p><pre><code>
3037 <div id='grid-container' style='margin-left:25%;width:50%'></div>
3039 * A Panel rendered into that target element must listen for browser window resize in order to relay its
3040 * child items when the browser changes its width:<pre><code>
3041 var myPanel = new Ext.Panel({
3042 renderTo: 'grid-container',
3043 monitorResize: true, // relay on browser resize
3065 * @cfg {Boolean} autoScroll
3066 * <code>true</code> to use overflow:'auto' on the components layout element and show scroll bars automatically when
3067 * necessary, <code>false</code> to clip any overflowing content (defaults to <code>false</code>).
3070 /* // private internal config
3071 * {Boolean} deferHeight
3072 * True to defer height calculations to an external component, false to allow this component to set its own
3073 * height (defaults to false).
3077 initComponent : function(){
3078 Ext.BoxComponent.superclass.initComponent.call(this);
3082 * Fires after the component is resized.
3083 * @param {Ext.Component} this
3084 * @param {Number} adjWidth The box-adjusted width that was set
3085 * @param {Number} adjHeight The box-adjusted height that was set
3086 * @param {Number} rawWidth The width that was originally specified
3087 * @param {Number} rawHeight The height that was originally specified
3092 * Fires after the component is moved.
3093 * @param {Ext.Component} this
3094 * @param {Number} x The new x position
3095 * @param {Number} y The new y position
3101 // private, set in afterRender to signify that the component has been rendered
3103 // private, used to defer height settings to subclasses
3107 * Sets the width and height of this BoxComponent. This method fires the {@link #resize} event. This method can accept
3108 * either width and height as separate arguments, or you can pass a size object like <code>{width:10, height:20}</code>.
3109 * @param {Mixed} width The new width to set. This may be one of:<div class="mdetail-params"><ul>
3110 * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li>
3111 * <li>A String used to set the CSS width style.</li>
3112 * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>
3113 * <li><code>undefined</code> to leave the width unchanged.</li>
3115 * @param {Mixed} height The new height to set (not required if a size object is passed as the first arg).
3116 * This may be one of:<div class="mdetail-params"><ul>
3117 * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li>
3118 * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
3119 * <li><code>undefined</code> to leave the height unchanged.</li>
3121 * @return {Ext.BoxComponent} this
3123 setSize : function(w, h){
3125 // support for standard size objects
3126 if(typeof w == 'object'){
3130 if (Ext.isDefined(w) && Ext.isDefined(this.boxMinWidth) && (w < this.boxMinWidth)) {
3131 w = this.boxMinWidth;
3133 if (Ext.isDefined(h) && Ext.isDefined(this.boxMinHeight) && (h < this.boxMinHeight)) {
3134 h = this.boxMinHeight;
3136 if (Ext.isDefined(w) && Ext.isDefined(this.boxMaxWidth) && (w > this.boxMaxWidth)) {
3137 w = this.boxMaxWidth;
3139 if (Ext.isDefined(h) && Ext.isDefined(this.boxMaxHeight) && (h > this.boxMaxHeight)) {
3140 h = this.boxMaxHeight;
3149 // prevent recalcs when not needed
3150 if(this.cacheSizes !== false && this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
3153 this.lastSize = {width: w, height: h};
3154 var adj = this.adjustSize(w, h),
3158 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
3159 rz = this.getResizeEl();
3160 if(!this.deferHeight && aw !== undefined && ah !== undefined){
3162 }else if(!this.deferHeight && ah !== undefined){
3164 }else if(aw !== undefined){
3167 this.onResize(aw, ah, w, h);
3168 this.fireEvent('resize', this, aw, ah, w, h);
3174 * Sets the width of the component. This method fires the {@link #resize} event.
3175 * @param {Mixed} width The new width to set. This may be one of:<div class="mdetail-params"><ul>
3176 * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit defaultUnit}s (by default, pixels).</li>
3177 * <li>A String used to set the CSS width style.</li>
3179 * @return {Ext.BoxComponent} this
3181 setWidth : function(width){
3182 return this.setSize(width);
3186 * Sets the height of the component. This method fires the {@link #resize} event.
3187 * @param {Mixed} height The new height to set. This may be one of:<div class="mdetail-params"><ul>
3188 * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit defaultUnit}s (by default, pixels).</li>
3189 * <li>A String used to set the CSS height style.</li>
3190 * <li><i>undefined</i> to leave the height unchanged.</li>
3192 * @return {Ext.BoxComponent} this
3194 setHeight : function(height){
3195 return this.setSize(undefined, height);
3199 * Gets the current size of the component's underlying element.
3200 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
3202 getSize : function(){
3203 return this.getResizeEl().getSize();
3207 * Gets the current width of the component's underlying element.
3210 getWidth : function(){
3211 return this.getResizeEl().getWidth();
3215 * Gets the current height of the component's underlying element.
3218 getHeight : function(){
3219 return this.getResizeEl().getHeight();
3223 * Gets the current size of the component's underlying element, including space taken by its margins.
3224 * @return {Object} An object containing the element's size {width: (element width + left/right margins), height: (element height + top/bottom margins)}
3226 getOuterSize : function(){
3227 var el = this.getResizeEl();
3228 return {width: el.getWidth() + el.getMargins('lr'),
3229 height: el.getHeight() + el.getMargins('tb')};
3233 * Gets the current XY position of the component's underlying element.
3234 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
3235 * @return {Array} The XY position of the element (e.g., [100, 200])
3237 getPosition : function(local){
3238 var el = this.getPositionEl();
3240 return [el.getLeft(true), el.getTop(true)];
3242 return this.xy || el.getXY();
3246 * Gets the current box measurements of the component's underlying element.
3247 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
3248 * @return {Object} box An object in the format {x, y, width, height}
3250 getBox : function(local){
3251 var pos = this.getPosition(local);
3252 var s = this.getSize();
3259 * Sets the current box measurements of the component's underlying element.
3260 * @param {Object} box An object in the format {x, y, width, height}
3261 * @return {Ext.BoxComponent} this
3263 updateBox : function(box){
3264 this.setSize(box.width, box.height);
3265 this.setPagePosition(box.x, box.y);
3270 * <p>Returns the outermost Element of this Component which defines the Components overall size.</p>
3271 * <p><i>Usually</i> this will return the same Element as <code>{@link #getEl}</code>,
3272 * but in some cases, a Component may have some more wrapping Elements around its main
3273 * active Element.</p>
3274 * <p>An example is a ComboBox. It is encased in a <i>wrapping</i> Element which
3275 * contains both the <code><input></code> Element (which is what would be returned
3276 * by its <code>{@link #getEl}</code> method, <i>and</i> the trigger button Element.
3277 * This Element is returned as the <code>resizeEl</code>.
3278 * @return {Ext.Element} The Element which is to be resized by size managing layouts.
3280 getResizeEl : function(){
3281 return this.resizeEl || this.el;
3285 * Sets the overflow on the content element of the component.
3286 * @param {Boolean} scroll True to allow the Component to auto scroll.
3287 * @return {Ext.BoxComponent} this
3289 setAutoScroll : function(scroll){
3291 this.getContentTarget().setOverflow(scroll ? 'auto' : '');
3293 this.autoScroll = scroll;
3298 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
3299 * This method fires the {@link #move} event.
3300 * @param {Number} left The new left
3301 * @param {Number} top The new top
3302 * @return {Ext.BoxComponent} this
3304 setPosition : function(x, y){
3305 if(x && typeof x[1] == 'number'){
3314 var adj = this.adjustPosition(x, y);
3315 var ax = adj.x, ay = adj.y;
3317 var el = this.getPositionEl();
3318 if(ax !== undefined || ay !== undefined){
3319 if(ax !== undefined && ay !== undefined){
3320 el.setLeftTop(ax, ay);
3321 }else if(ax !== undefined){
3323 }else if(ay !== undefined){
3326 this.onPosition(ax, ay);
3327 this.fireEvent('move', this, ax, ay);
3333 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
3334 * This method fires the {@link #move} event.
3335 * @param {Number} x The new x position
3336 * @param {Number} y The new y position
3337 * @return {Ext.BoxComponent} this
3339 setPagePosition : function(x, y){
3340 if(x && typeof x[1] == 'number'){
3349 if(x === undefined || y === undefined){ // cannot translate undefined points
3352 var p = this.getPositionEl().translatePoints(x, y);
3353 this.setPosition(p.left, p.top);
3358 afterRender : function(){
3359 Ext.BoxComponent.superclass.afterRender.call(this);
3361 this.resizeEl = Ext.get(this.resizeEl);
3363 if(this.positionEl){
3364 this.positionEl = Ext.get(this.positionEl);
3366 this.boxReady = true;
3367 Ext.isDefined(this.autoScroll) && this.setAutoScroll(this.autoScroll);
3368 this.setSize(this.width, this.height);
3369 if(this.x || this.y){
3370 this.setPosition(this.x, this.y);
3371 }else if(this.pageX || this.pageY){
3372 this.setPagePosition(this.pageX, this.pageY);
3377 * Force the component's size to recalculate based on the underlying element's current height and width.
3378 * @return {Ext.BoxComponent} this
3380 syncSize : function(){
3381 delete this.lastSize;
3382 this.setSize(this.autoWidth ? undefined : this.getResizeEl().getWidth(), this.autoHeight ? undefined : this.getResizeEl().getHeight());
3387 * Called after the component is resized, this method is empty by default but can be implemented by any
3388 * subclass that needs to perform custom logic after a resize occurs.
3389 * @param {Number} adjWidth The box-adjusted width that was set
3390 * @param {Number} adjHeight The box-adjusted height that was set
3391 * @param {Number} rawWidth The width that was originally specified
3392 * @param {Number} rawHeight The height that was originally specified
3394 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
3398 * Called after the component is moved, this method is empty by default but can be implemented by any
3399 * subclass that needs to perform custom logic after a move occurs.
3400 * @param {Number} x The new x position
3401 * @param {Number} y The new y position
3403 onPosition : function(x, y){
3408 adjustSize : function(w, h){
3412 if(this.autoHeight){
3415 return {width : w, height: h};
3419 adjustPosition : function(x, y){
3420 return {x : x, y: y};
3423 Ext.reg('box', Ext.BoxComponent);
3428 * @extends Ext.BoxComponent
3429 * <p>Used to provide a sizable space in a layout.</p>
3431 * @param {Object} config
3433 Ext.Spacer = Ext.extend(Ext.BoxComponent, {
3436 Ext.reg('spacer', Ext.Spacer);/**
3437 * @class Ext.SplitBar
3438 * @extends Ext.util.Observable
3439 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
3443 var split = new Ext.SplitBar("elementToDrag", "elementToSize",
3444 Ext.SplitBar.HORIZONTAL, Ext.SplitBar.LEFT);
3445 split.setAdapter(new Ext.SplitBar.AbsoluteLayoutAdapter("container"));
3446 split.minSize = 100;
3447 split.maxSize = 600;
3448 split.animate = true;
3449 split.on('moved', splitterMoved);
3452 * Create a new SplitBar
3453 * @param {Mixed} dragElement The element to be dragged and act as the SplitBar.
3454 * @param {Mixed} resizingElement The element to be resized based on where the SplitBar element is dragged
3455 * @param {Number} orientation (optional) Either Ext.SplitBar.HORIZONTAL or Ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
3456 * @param {Number} placement (optional) Either Ext.SplitBar.LEFT or Ext.SplitBar.RIGHT for horizontal or
3457 Ext.SplitBar.TOP or Ext.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
3458 position of the SplitBar).
3460 Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
3463 this.el = Ext.get(dragElement, true);
3464 this.el.dom.unselectable = "on";
3466 this.resizingEl = Ext.get(resizingElement, true);
3470 * The orientation of the split. Either Ext.SplitBar.HORIZONTAL or Ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
3471 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
3474 this.orientation = orientation || Ext.SplitBar.HORIZONTAL;
3477 * The increment, in pixels by which to move this SplitBar. When <i>undefined</i>, the SplitBar moves smoothly.
3479 * @property tickSize
3482 * The minimum size of the resizing element. (Defaults to 0)
3488 * The maximum size of the resizing element. (Defaults to 2000)
3491 this.maxSize = 2000;
3494 * Whether to animate the transition to the new size
3497 this.animate = false;
3500 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
3503 this.useShim = false;
3510 this.proxy = Ext.SplitBar.createProxy(this.orientation);
3512 this.proxy = Ext.get(existingProxy).dom;
3515 this.dd = new Ext.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
3518 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
3521 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
3524 this.dragSpecs = {};
3527 * @private The adapter to use to positon and resize elements
3529 this.adapter = new Ext.SplitBar.BasicLayoutAdapter();
3530 this.adapter.init(this);
3532 if(this.orientation == Ext.SplitBar.HORIZONTAL){
3534 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Ext.SplitBar.LEFT : Ext.SplitBar.RIGHT);
3535 this.el.addClass("x-splitbar-h");
3538 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Ext.SplitBar.TOP : Ext.SplitBar.BOTTOM);
3539 this.el.addClass("x-splitbar-v");
3545 * Fires when the splitter is moved (alias for {@link #moved})
3546 * @param {Ext.SplitBar} this
3547 * @param {Number} newSize the new width or height
3552 * Fires when the splitter is moved
3553 * @param {Ext.SplitBar} this
3554 * @param {Number} newSize the new width or height
3558 * @event beforeresize
3559 * Fires before the splitter is dragged
3560 * @param {Ext.SplitBar} this
3567 Ext.SplitBar.superclass.constructor.call(this);
3570 Ext.extend(Ext.SplitBar, Ext.util.Observable, {
3571 onStartProxyDrag : function(x, y){
3572 this.fireEvent("beforeresize", this);
3573 this.overlay = Ext.DomHelper.append(document.body, {cls: "x-drag-overlay", html: " "}, true);
3574 this.overlay.unselectable();
3575 this.overlay.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
3576 this.overlay.show();
3577 Ext.get(this.proxy).setDisplayed("block");
3578 var size = this.adapter.getElementSize(this);
3579 this.activeMinSize = this.getMinimumSize();
3580 this.activeMaxSize = this.getMaximumSize();
3581 var c1 = size - this.activeMinSize;
3582 var c2 = Math.max(this.activeMaxSize - size, 0);
3583 if(this.orientation == Ext.SplitBar.HORIZONTAL){
3584 this.dd.resetConstraints();
3585 this.dd.setXConstraint(
3586 this.placement == Ext.SplitBar.LEFT ? c1 : c2,
3587 this.placement == Ext.SplitBar.LEFT ? c2 : c1,
3590 this.dd.setYConstraint(0, 0);
3592 this.dd.resetConstraints();
3593 this.dd.setXConstraint(0, 0);
3594 this.dd.setYConstraint(
3595 this.placement == Ext.SplitBar.TOP ? c1 : c2,
3596 this.placement == Ext.SplitBar.TOP ? c2 : c1,
3600 this.dragSpecs.startSize = size;
3601 this.dragSpecs.startPoint = [x, y];
3602 Ext.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
3606 * @private Called after the drag operation by the DDProxy
3608 onEndProxyDrag : function(e){
3609 Ext.get(this.proxy).setDisplayed(false);
3610 var endPoint = Ext.lib.Event.getXY(e);
3612 Ext.destroy(this.overlay);
3613 delete this.overlay;
3616 if(this.orientation == Ext.SplitBar.HORIZONTAL){
3617 newSize = this.dragSpecs.startSize +
3618 (this.placement == Ext.SplitBar.LEFT ?
3619 endPoint[0] - this.dragSpecs.startPoint[0] :
3620 this.dragSpecs.startPoint[0] - endPoint[0]
3623 newSize = this.dragSpecs.startSize +
3624 (this.placement == Ext.SplitBar.TOP ?
3625 endPoint[1] - this.dragSpecs.startPoint[1] :
3626 this.dragSpecs.startPoint[1] - endPoint[1]
3629 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
3630 if(newSize != this.dragSpecs.startSize){
3631 if(this.fireEvent('beforeapply', this, newSize) !== false){
3632 this.adapter.setElementSize(this, newSize);
3633 this.fireEvent("moved", this, newSize);
3634 this.fireEvent("resize", this, newSize);
3640 * Get the adapter this SplitBar uses
3641 * @return The adapter object
3643 getAdapter : function(){
3644 return this.adapter;
3648 * Set the adapter this SplitBar uses
3649 * @param {Object} adapter A SplitBar adapter object
3651 setAdapter : function(adapter){
3652 this.adapter = adapter;
3653 this.adapter.init(this);
3657 * Gets the minimum size for the resizing element
3658 * @return {Number} The minimum size
3660 getMinimumSize : function(){
3661 return this.minSize;
3665 * Sets the minimum size for the resizing element
3666 * @param {Number} minSize The minimum size
3668 setMinimumSize : function(minSize){
3669 this.minSize = minSize;
3673 * Gets the maximum size for the resizing element
3674 * @return {Number} The maximum size
3676 getMaximumSize : function(){
3677 return this.maxSize;
3681 * Sets the maximum size for the resizing element
3682 * @param {Number} maxSize The maximum size
3684 setMaximumSize : function(maxSize){
3685 this.maxSize = maxSize;
3689 * Sets the initialize size for the resizing element
3690 * @param {Number} size The initial size
3692 setCurrentSize : function(size){
3693 var oldAnimate = this.animate;
3694 this.animate = false;
3695 this.adapter.setElementSize(this, size);
3696 this.animate = oldAnimate;
3700 * Destroy this splitbar.
3701 * @param {Boolean} removeEl True to remove the element
3703 destroy : function(removeEl){
3704 Ext.destroy(this.shim, Ext.get(this.proxy));
3709 this.purgeListeners();
3714 * @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.
3716 Ext.SplitBar.createProxy = function(dir){
3717 var proxy = new Ext.Element(document.createElement("div"));
3718 document.body.appendChild(proxy.dom);
3719 proxy.unselectable();
3720 var cls = 'x-splitbar-proxy';
3721 proxy.addClass(cls + ' ' + (dir == Ext.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
3726 * @class Ext.SplitBar.BasicLayoutAdapter
3727 * Default Adapter. It assumes the splitter and resizing element are not positioned
3728 * elements and only gets/sets the width of the element. Generally used for table based layouts.
3730 Ext.SplitBar.BasicLayoutAdapter = function(){
3733 Ext.SplitBar.BasicLayoutAdapter.prototype = {
3734 // do nothing for now
3739 * Called before drag operations to get the current size of the resizing element.
3740 * @param {Ext.SplitBar} s The SplitBar using this adapter
3742 getElementSize : function(s){
3743 if(s.orientation == Ext.SplitBar.HORIZONTAL){
3744 return s.resizingEl.getWidth();
3746 return s.resizingEl.getHeight();
3751 * Called after drag operations to set the size of the resizing element.
3752 * @param {Ext.SplitBar} s The SplitBar using this adapter
3753 * @param {Number} newSize The new size to set
3754 * @param {Function} onComplete A function to be invoked when resizing is complete
3756 setElementSize : function(s, newSize, onComplete){
3757 if(s.orientation == Ext.SplitBar.HORIZONTAL){
3759 s.resizingEl.setWidth(newSize);
3761 onComplete(s, newSize);
3764 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
3769 s.resizingEl.setHeight(newSize);
3771 onComplete(s, newSize);
3774 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
3781 *@class Ext.SplitBar.AbsoluteLayoutAdapter
3782 * @extends Ext.SplitBar.BasicLayoutAdapter
3783 * Adapter that moves the splitter element to align with the resized sizing element.
3784 * Used with an absolute positioned SplitBar.
3785 * @param {Mixed} container The container that wraps around the absolute positioned content. If it's
3786 * document.body, make sure you assign an id to the body element.
3788 Ext.SplitBar.AbsoluteLayoutAdapter = function(container){
3789 this.basic = new Ext.SplitBar.BasicLayoutAdapter();
3790 this.container = Ext.get(container);
3793 Ext.SplitBar.AbsoluteLayoutAdapter.prototype = {
3798 getElementSize : function(s){
3799 return this.basic.getElementSize(s);
3802 setElementSize : function(s, newSize, onComplete){
3803 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
3806 moveSplitter : function(s){
3807 var yes = Ext.SplitBar;
3808 switch(s.placement){
3810 s.el.setX(s.resizingEl.getRight());
3813 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
3816 s.el.setY(s.resizingEl.getBottom());
3819 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
3826 * Orientation constant - Create a vertical SplitBar
3830 Ext.SplitBar.VERTICAL = 1;
3833 * Orientation constant - Create a horizontal SplitBar
3837 Ext.SplitBar.HORIZONTAL = 2;
3840 * Placement constant - The resizing element is to the left of the splitter element
3844 Ext.SplitBar.LEFT = 1;
3847 * Placement constant - The resizing element is to the right of the splitter element
3851 Ext.SplitBar.RIGHT = 2;
3854 * Placement constant - The resizing element is positioned above the splitter element
3858 Ext.SplitBar.TOP = 3;
3861 * Placement constant - The resizing element is positioned under splitter element
3865 Ext.SplitBar.BOTTOM = 4;
3867 * @class Ext.Container
3868 * @extends Ext.BoxComponent
3869 * <p>Base class for any {@link Ext.BoxComponent} that may contain other Components. Containers handle the
3870 * basic behavior of containing items, namely adding, inserting and removing items.</p>
3872 * <p>The most commonly used Container classes are {@link Ext.Panel}, {@link Ext.Window} and {@link Ext.TabPanel}.
3873 * If you do not need the capabilities offered by the aforementioned classes you can create a lightweight
3874 * Container to be encapsulated by an HTML element to your specifications by using the
3875 * <code><b>{@link Ext.Component#autoEl autoEl}</b></code> config option. This is a useful technique when creating
3876 * embedded {@link Ext.layout.ColumnLayout column} layouts inside {@link Ext.form.FormPanel FormPanels}
3879 * <p>The code below illustrates both how to explicitly create a Container, and how to implicitly
3880 * create one using the <b><code>'container'</code></b> xtype:<pre><code>
3881 // explicitly create a Container
3882 var embeddedColumns = new Ext.Container({
3883 autoEl: 'div', // This is the default
3886 // implicitly create Container by specifying xtype
3888 autoEl: 'div', // This is the default.
3895 // The two items below will be Ext.Containers, each encapsulated by a <DIV> element.
3900 fieldLabel: 'Start date'
3906 fieldLabel: 'End date'
3909 });</code></pre></p>
3911 * <p><u><b>Layout</b></u></p>
3912 * <p>Container classes delegate the rendering of child Components to a layout
3913 * manager class which must be configured into the Container using the
3914 * <code><b>{@link #layout}</b></code> configuration property.</p>
3915 * <p>When either specifying child <code>{@link #items}</code> of a Container,
3916 * or dynamically {@link #add adding} Components to a Container, remember to
3917 * consider how you wish the Container to arrange those child elements, and
3918 * whether those child elements need to be sized using one of Ext's built-in
3919 * <b><code>{@link #layout}</code></b> schemes. By default, Containers use the
3920 * {@link Ext.layout.ContainerLayout ContainerLayout} scheme which only
3921 * renders child components, appending them one after the other inside the
3922 * Container, and <b>does not apply any sizing</b> at all.</p>
3923 * <p>A common mistake is when a developer neglects to specify a
3924 * <b><code>{@link #layout}</code></b> (e.g. widgets like GridPanels or
3925 * TreePanels are added to Containers for which no <code><b>{@link #layout}</b></code>
3926 * has been specified). If a Container is left to use the default
3927 * {@link Ext.layout.ContainerLayout ContainerLayout} scheme, none of its
3928 * child components will be resized, or changed in any way when the Container
3930 * <p>Certain layout managers allow dynamic addition of child components.
3931 * Those that do include {@link Ext.layout.CardLayout},
3932 * {@link Ext.layout.AnchorLayout}, {@link Ext.layout.FormLayout}, and
3933 * {@link Ext.layout.TableLayout}. For example:<pre><code>
3934 // Create the GridPanel.
3935 var myNewGrid = new Ext.grid.GridPanel({
3937 columns: myColumnModel,
3938 title: 'Results', // the title becomes the title of the tab
3941 myTabPanel.add(myNewGrid); // {@link Ext.TabPanel} implicitly uses {@link Ext.layout.CardLayout CardLayout}
3942 myTabPanel.{@link Ext.TabPanel#setActiveTab setActiveTab}(myNewGrid);
3944 * <p>The example above adds a newly created GridPanel to a TabPanel. Note that
3945 * a TabPanel uses {@link Ext.layout.CardLayout} as its layout manager which
3946 * means all its child items are sized to {@link Ext.layout.FitLayout fit}
3947 * exactly into its client area.
3948 * <p><b><u>Overnesting is a common problem</u></b>.
3949 * An example of overnesting occurs when a GridPanel is added to a TabPanel
3950 * by wrapping the GridPanel <i>inside</i> a wrapping Panel (that has no
3951 * <code><b>{@link #layout}</b></code> specified) and then add that wrapping Panel
3952 * to the TabPanel. The point to realize is that a GridPanel <b>is</b> a
3953 * Component which can be added directly to a Container. If the wrapping Panel
3954 * has no <code><b>{@link #layout}</b></code> configuration, then the overnested
3955 * GridPanel will not be sized as expected.<p>
3957 * <p><u><b>Adding via remote configuration</b></u></p>
3959 * <p>A server side script can be used to add Components which are generated dynamically on the server.
3960 * An example of adding a GridPanel to a TabPanel where the GridPanel is generated by the server
3961 * based on certain parameters:
3963 // execute an Ajax request to invoke server side script:
3965 url: 'gen-invoice-grid.php',
3966 // send additional parameters to instruct server script
3968 startDate: Ext.getCmp('start-date').getValue(),
3969 endDate: Ext.getCmp('end-date').getValue()
3971 // process the response object to add it to the TabPanel:
3972 success: function(xhr) {
3973 var newComponent = eval(xhr.responseText); // see discussion below
3974 myTabPanel.add(newComponent); // add the component to the TabPanel
3975 myTabPanel.setActiveTab(newComponent);
3977 failure: function() {
3978 Ext.Msg.alert("Grid create failed", "Server communication failure");
3982 * <p>The server script needs to return an executable Javascript statement which, when processed
3983 * using <code>eval()</code>, will return either a config object with an {@link Ext.Component#xtype xtype},
3984 * or an instantiated Component. The server might return this for example:</p><pre><code>
3986 function formatDate(value){
3987 return value ? value.dateFormat('M d, Y') : '';
3990 var store = new Ext.data.Store({
3991 url: 'get-invoice-data.php',
3993 startDate: '01/01/2008',
3994 endDate: '01/31/2008'
3996 reader: new Ext.data.JsonReader({
3997 record: 'transaction',
3999 totalRecords: 'total'
4003 {name: 'date', type: 'date', dateFormat: 'm/d/Y'},
4004 {name: 'value', type: 'float'}
4008 var grid = new Ext.grid.GridPanel({
4009 title: 'Invoice Report',
4010 bbar: new Ext.PagingToolbar(store),
4013 {header: "Customer", width: 250, dataIndex: 'customer', sortable: true},
4014 {header: "Invoice Number", width: 120, dataIndex: 'invNo', sortable: true},
4015 {header: "Invoice Date", width: 100, dataIndex: 'date', renderer: formatDate, sortable: true},
4016 {header: "Value", width: 120, dataIndex: 'value', renderer: 'usMoney', sortable: true}
4020 return grid; // return instantiated component
4023 * <p>When the above code fragment is passed through the <code>eval</code> function in the success handler
4024 * of the Ajax request, the code is executed by the Javascript processor, and the anonymous function
4025 * runs, and returns the instantiated grid component.</p>
4026 * <p>Note: since the code above is <i>generated</i> by a server script, the <code>baseParams</code> for
4027 * the Store, the metadata to allow generation of the Record layout, and the ColumnModel
4028 * can all be generated into the code since these are all known on the server.</p>
4032 Ext.Container = Ext.extend(Ext.BoxComponent, {
4034 * @cfg {Boolean} monitorResize
4035 * True to automatically monitor window resize events to handle anything that is sensitive to the current size
4036 * of the viewport. This value is typically managed by the chosen <code>{@link #layout}</code> and should not need
4037 * to be set manually.
4040 * @cfg {String/Object} layout
4041 * <p><b>*Important</b>: In order for child items to be correctly sized and
4042 * positioned, typically a layout manager <b>must</b> be specified through
4043 * the <code>layout</code> configuration option.</p>
4044 * <br><p>The sizing and positioning of child {@link items} is the responsibility of
4045 * the Container's layout manager which creates and manages the type of layout
4046 * you have in mind. For example:</p><pre><code>
4048 width:300, height: 300,
4049 layout: 'fit', // explicitly set layout manager: override the default (layout:'auto')
4051 title: 'Panel inside a Window'
4055 * <p>If the {@link #layout} configuration is not explicitly specified for
4056 * a general purpose container (e.g. Container or Panel) the
4057 * {@link Ext.layout.ContainerLayout default layout manager} will be used
4058 * which does nothing but render child components sequentially into the
4059 * Container (no sizing or positioning will be performed in this situation).
4060 * Some container classes implicitly specify a default layout
4061 * (e.g. FormPanel specifies <code>layout:'form'</code>). Other specific
4062 * purpose classes internally specify/manage their internal layout (e.g.
4063 * GridPanel, TabPanel, TreePanel, Toolbar, Menu, etc.).</p>
4064 * <br><p><b><code>layout</code></b> may be specified as either as an Object or
4065 * as a String:</p><div><ul class="mdetail-params">
4067 * <li><u>Specify as an Object</u></li>
4068 * <div><ul class="mdetail-params">
4069 * <li>Example usage:</li>
4078 * <li><code><b>type</b></code></li>
4079 * <br/><p>The layout type to be used for this container. If not specified,
4080 * a default {@link Ext.layout.ContainerLayout} will be created and used.</p>
4081 * <br/><p>Valid layout <code>type</code> values are:</p>
4082 * <div class="sub-desc"><ul class="mdetail-params">
4083 * <li><code><b>{@link Ext.layout.AbsoluteLayout absolute}</b></code></li>
4084 * <li><code><b>{@link Ext.layout.AccordionLayout accordion}</b></code></li>
4085 * <li><code><b>{@link Ext.layout.AnchorLayout anchor}</b></code></li>
4086 * <li><code><b>{@link Ext.layout.ContainerLayout auto}</b></code> <b>Default</b></li>
4087 * <li><code><b>{@link Ext.layout.BorderLayout border}</b></code></li>
4088 * <li><code><b>{@link Ext.layout.CardLayout card}</b></code></li>
4089 * <li><code><b>{@link Ext.layout.ColumnLayout column}</b></code></li>
4090 * <li><code><b>{@link Ext.layout.FitLayout fit}</b></code></li>
4091 * <li><code><b>{@link Ext.layout.FormLayout form}</b></code></li>
4092 * <li><code><b>{@link Ext.layout.HBoxLayout hbox}</b></code></li>
4093 * <li><code><b>{@link Ext.layout.MenuLayout menu}</b></code></li>
4094 * <li><code><b>{@link Ext.layout.TableLayout table}</b></code></li>
4095 * <li><code><b>{@link Ext.layout.ToolbarLayout toolbar}</b></code></li>
4096 * <li><code><b>{@link Ext.layout.VBoxLayout vbox}</b></code></li>
4099 * <li>Layout specific configuration properties</li>
4100 * <br/><p>Additional layout specific configuration properties may also be
4101 * specified. For complete details regarding the valid config options for
4102 * each layout type, see the layout class corresponding to the <code>type</code>
4107 * <li><u>Specify as a String</u></li>
4108 * <div><ul class="mdetail-params">
4109 * <li>Example usage:</li>
4117 * <li><code><b>layout</b></code></li>
4118 * <br/><p>The layout <code>type</code> to be used for this container (see list
4119 * of valid layout type values above).</p><br/>
4120 * <li><code><b>{@link #layoutConfig}</b></code></li>
4121 * <br/><p>Additional layout specific configuration properties. For complete
4122 * details regarding the valid config options for each layout type, see the
4123 * layout class corresponding to the <code>layout</code> specified.</p>
4124 * </ul></div></ul></div>
4127 * @cfg {Object} layoutConfig
4128 * This is a config object containing properties specific to the chosen
4129 * <b><code>{@link #layout}</code></b> if <b><code>{@link #layout}</code></b>
4130 * has been specified as a <i>string</i>.</p>
4133 * @cfg {Boolean/Number} bufferResize
4134 * When set to true (50 milliseconds) or a number of milliseconds, the layout assigned for this container will buffer
4135 * the frequency it calculates and does a re-layout of components. This is useful for heavy containers or containers
4136 * with a large quantity of sub-components for which frequent layout calls would be expensive. Defaults to <code>50</code>.
4141 * @cfg {String/Number} activeItem
4142 * A string component id or the numeric index of the component that should be initially activated within the
4143 * container's layout on render. For example, activeItem: 'item-1' or activeItem: 0 (index 0 = the first
4144 * item in the container's collection). activeItem only applies to layout styles that can display
4145 * items one at a time (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout} and
4146 * {@link Ext.layout.FitLayout}). Related to {@link Ext.layout.ContainerLayout#activeItem}.
4149 * @cfg {Object/Array} items
4150 * <pre><b>** IMPORTANT</b>: be sure to <b>{@link #layout specify a <code>layout</code>} if needed ! **</b></pre>
4151 * <p>A single item, or an array of child Components to be added to this container,
4154 // specifying a single item
4156 layout: 'fit', // specify a layout!
4158 // specifying multiple items
4159 items: [{...}, {...}],
4160 layout: 'anchor', // specify a layout!
4162 * <p>Each item may be:</p>
4163 * <div><ul class="mdetail-params">
4164 * <li>any type of object based on {@link Ext.Component}</li>
4165 * <li>a fully instanciated object or</li>
4166 * <li>an object literal that:</li>
4167 * <div><ul class="mdetail-params">
4168 * <li>has a specified <code>{@link Ext.Component#xtype xtype}</code></li>
4169 * <li>the {@link Ext.Component#xtype} specified is associated with the Component
4170 * desired and should be chosen from one of the available xtypes as listed
4171 * in {@link Ext.Component}.</li>
4172 * <li>If an <code>{@link Ext.Component#xtype xtype}</code> is not explicitly
4173 * specified, the {@link #defaultType} for that Container is used.</li>
4174 * <li>will be "lazily instanciated", avoiding the overhead of constructing a fully
4175 * instanciated Component object</li>
4176 * </ul></div></ul></div>
4177 * <p><b>Notes</b>:</p>
4178 * <div><ul class="mdetail-params">
4179 * <li>Ext uses lazy rendering. Child Components will only be rendered
4180 * should it become necessary. Items are automatically laid out when they are first
4181 * shown (no sizing is done while hidden), or in response to a {@link #doLayout} call.</li>
4182 * <li>Do not specify <code>{@link Ext.Panel#contentEl contentEl}</code>/
4183 * <code>{@link Ext.Panel#html html}</code> with <code>items</code>.</li>
4187 * @cfg {Object|Function} defaults
4188 * <p>This option is a means of applying default settings to all added items whether added through the {@link #items}
4189 * config or via the {@link #add} or {@link #insert} methods.</p>
4190 * <p>If an added item is a config object, and <b>not</b> an instantiated Component, then the default properties are
4191 * unconditionally applied. If the added item <b>is</b> an instantiated Component, then the default properties are
4192 * applied conditionally so as not to override existing properties in the item.</p>
4193 * <p>If the defaults option is specified as a function, then the function will be called using this Container as the
4194 * scope (<code>this</code> reference) and passing the added item as the first parameter. Any resulting object
4195 * from that call is then applied to the item as default properties.</p>
4196 * <p>For example, to automatically apply padding to the body of each of a set of
4197 * contained {@link Ext.Panel} items, you could pass: <code>defaults: {bodyStyle:'padding:15px'}</code>.</p>
4198 * <p>Usage:</p><pre><code>
4199 defaults: { // defaults are applied to items, not the container
4204 xtype: 'panel', // defaults <b>do not</b> have precedence over
4205 id: 'panel1', // options in config objects, so the defaults
4206 autoScroll: false // will not be applied here, panel1 will be autoScroll:false
4208 new Ext.Panel({ // defaults <b>do</b> have precedence over options
4209 id: 'panel2', // options in components, so the defaults
4210 autoScroll: false // will be applied here, panel2 will be autoScroll:true.
4217 /** @cfg {Boolean} autoDestroy
4218 * If true the container will automatically destroy any contained component that is removed from it, else
4219 * destruction must be handled manually (defaults to true).
4223 /** @cfg {Boolean} forceLayout
4224 * If true the container will force a layout initially even if hidden or collapsed. This option
4225 * is useful for forcing forms to render in collapsed or hidden containers. (defaults to false).
4229 /** @cfg {Boolean} hideBorders
4230 * True to hide the borders of each contained component, false to defer to the component's existing
4231 * border settings (defaults to false).
4233 /** @cfg {String} defaultType
4234 * <p>The default {@link Ext.Component xtype} of child Components to create in this Container when
4235 * a child item is specified as a raw configuration object, rather than as an instantiated Component.</p>
4236 * <p>Defaults to <code>'panel'</code>, except {@link Ext.menu.Menu} which defaults to <code>'menuitem'</code>,
4237 * and {@link Ext.Toolbar} and {@link Ext.ButtonGroup} which default to <code>'button'</code>.</p>
4239 defaultType : 'panel',
4241 /** @cfg {String} resizeEvent
4242 * The event to listen to for resizing in layouts. Defaults to <code>'resize'</code>.
4244 resizeEvent: 'resize',
4247 * @cfg {Array} bubbleEvents
4248 * <p>An array of events that, when fired, should be bubbled to any parent container.
4249 * See {@link Ext.util.Observable#enableBubble}.
4250 * Defaults to <code>['add', 'remove']</code>.
4252 bubbleEvents: ['add', 'remove'],
4255 initComponent : function(){
4256 Ext.Container.superclass.initComponent.call(this);
4260 * @event afterlayout
4261 * Fires when the components in this container are arranged by the associated layout manager.
4262 * @param {Ext.Container} this
4263 * @param {ContainerLayout} layout The ContainerLayout implementation for this container
4268 * Fires before any {@link Ext.Component} is added or inserted into the container.
4269 * A handler can return false to cancel the add.
4270 * @param {Ext.Container} this
4271 * @param {Ext.Component} component The component being added
4272 * @param {Number} index The index at which the component will be added to the container's items collection
4276 * @event beforeremove
4277 * Fires before any {@link Ext.Component} is removed from the container. A handler can return
4278 * false to cancel the remove.
4279 * @param {Ext.Container} this
4280 * @param {Ext.Component} component The component being removed
4286 * Fires after any {@link Ext.Component} is added or inserted into the container.
4287 * @param {Ext.Container} this
4288 * @param {Ext.Component} component The component that was added
4289 * @param {Number} index The index at which the component was added to the container's items collection
4295 * Fires after any {@link Ext.Component} is removed from the container.
4296 * @param {Ext.Container} this
4297 * @param {Ext.Component} component The component that was removed
4303 * The collection of components in this container as a {@link Ext.util.MixedCollection}
4304 * @type MixedCollection
4307 var items = this.items;
4315 initItems : function(){
4317 this.items = new Ext.util.MixedCollection(false, this.getComponentId);
4318 this.getLayout(); // initialize the layout
4323 setLayout : function(layout){
4324 if(this.layout && this.layout != layout){
4325 this.layout.setContainer(null);
4327 this.layout = layout;
4329 layout.setContainer(this);
4332 afterRender: function(){
4333 // Render this Container, this should be done before setLayout is called which
4334 // will hook onResize
4335 Ext.Container.superclass.afterRender.call(this);
4337 this.layout = 'auto';
4339 if(Ext.isObject(this.layout) && !this.layout.layout){
4340 this.layoutConfig = this.layout;
4341 this.layout = this.layoutConfig.type;
4343 if(Ext.isString(this.layout)){
4344 this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig);
4346 this.setLayout(this.layout);
4348 // If a CardLayout, the active item set
4349 if(this.activeItem !== undefined){
4350 var item = this.activeItem;
4351 delete this.activeItem;
4352 this.layout.setActiveItem(item);
4355 // If we have no ownerCt, render and size all children
4357 this.doLayout(false, true);
4360 // This is a manually configured flag set by users in conjunction with renderTo.
4361 // Not to be confused with the flag by the same name used in Layouts.
4362 if(this.monitorResize === true){
4363 Ext.EventManager.onWindowResize(this.doLayout, this, [false]);
4368 * <p>Returns the Element to be used to contain the child Components of this Container.</p>
4369 * <p>An implementation is provided which returns the Container's {@link #getEl Element}, but
4370 * if there is a more complex structure to a Container, this may be overridden to return
4371 * the element into which the {@link #layout layout} renders child Components.</p>
4372 * @return {Ext.Element} The Element to render child Components into.
4374 getLayoutTarget : function(){
4378 // private - used as the key lookup function for the items collection
4379 getComponentId : function(comp){
4380 return comp.getItemId();
4384 * <p>Adds {@link Ext.Component Component}(s) to this Container.</p>
4385 * <br><p><b>Description</b></u> :
4386 * <div><ul class="mdetail-params">
4387 * <li>Fires the {@link #beforeadd} event before adding</li>
4388 * <li>The Container's {@link #defaults default config values} will be applied
4389 * accordingly (see <code>{@link #defaults}</code> for details).</li>
4390 * <li>Fires the {@link #add} event after the component has been added.</li>
4392 * <br><p><b>Notes</b></u> :
4393 * <div><ul class="mdetail-params">
4394 * <li>If the Container is <i>already rendered</i> when <code>add</code>
4395 * is called, you may need to call {@link #doLayout} to refresh the view which causes
4396 * any unrendered child Components to be rendered. This is required so that you can
4397 * <code>add</code> multiple child components if needed while only refreshing the layout
4398 * once. For example:<pre><code>
4399 var tb = new {@link Ext.Toolbar}();
4400 tb.render(document.body); // toolbar is rendered
4401 tb.add({text:'Button 1'}); // add multiple items ({@link #defaultType} for {@link Ext.Toolbar Toolbar} is 'button')
4402 tb.add({text:'Button 2'});
4403 tb.{@link #doLayout}(); // refresh the layout
4404 * </code></pre></li>
4405 * <li><i>Warning:</i> Containers directly managed by the BorderLayout layout manager
4406 * may not be removed or added. See the Notes for {@link Ext.layout.BorderLayout BorderLayout}
4407 * for more details.</li>
4409 * @param {...Object/Array} component
4410 * <p>Either one or more Components to add or an Array of Components to add. See
4411 * <code>{@link #items}</code> for additional information.</p>
4412 * @return {Ext.Component/Array} The Components that were added.
4414 add : function(comp){
4416 var args = arguments.length > 1;
4417 if(args || Ext.isArray(comp)){
4419 Ext.each(args ? arguments : comp, function(c){
4420 result.push(this.add(c));
4424 var c = this.lookupComponent(this.applyDefaults(comp));
4425 var index = this.items.length;
4426 if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){
4429 c.onAdded(this, index);
4431 this.fireEvent('add', this, c, index);
4436 onAdd : function(c){
4437 // Empty template method
4441 onAdded : function(container, pos) {
4442 //overridden here so we can cascade down, not worth creating a template method.
4443 this.ownerCt = container;
4445 //initialize references for child items
4446 this.cascade(function(c){
4449 this.fireEvent('added', this, container, pos);
4453 * Inserts a Component into this Container at a specified index. Fires the
4454 * {@link #beforeadd} event before inserting, then fires the {@link #add} event after the
4455 * Component has been inserted.
4456 * @param {Number} index The index at which the Component will be inserted
4457 * into the Container's items collection
4458 * @param {Ext.Component} component The child Component to insert.<br><br>
4459 * Ext uses lazy rendering, and will only render the inserted Component should
4460 * it become necessary.<br><br>
4461 * A Component config object may be passed in order to avoid the overhead of
4462 * constructing a real Component object if lazy rendering might mean that the
4463 * inserted Component will not be rendered immediately. To take advantage of
4464 * this 'lazy instantiation', set the {@link Ext.Component#xtype} config
4465 * property to the registered type of the Component wanted.<br><br>
4466 * For a list of all available xtypes, see {@link Ext.Component}.
4467 * @return {Ext.Component} component The Component (or config object) that was
4468 * inserted with the Container's default config values applied.
4470 insert : function(index, comp){
4472 var a = arguments, len = a.length;
4475 for(var i = len-1; i >= 1; --i) {
4476 result.push(this.insert(index, a[i]));
4480 var c = this.lookupComponent(this.applyDefaults(comp));
4481 index = Math.min(index, this.items.length);
4482 if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){
4483 if(c.ownerCt == this){
4484 this.items.remove(c);
4486 this.items.insert(index, c);
4487 c.onAdded(this, index);
4489 this.fireEvent('add', this, c, index);
4495 applyDefaults : function(c){
4496 var d = this.defaults;
4498 if(Ext.isFunction(d)){
4499 d = d.call(this, c);
4501 if(Ext.isString(c)){
4502 c = Ext.ComponentMgr.get(c);
4504 }else if(!c.events){
4514 onBeforeAdd : function(item){
4516 item.ownerCt.remove(item, false);
4518 if(this.hideBorders === true){
4519 item.border = (item.border === true);
4524 * Removes a component from this container. Fires the {@link #beforeremove} event before removing, then fires
4525 * the {@link #remove} event after the component has been removed.
4526 * @param {Component/String} component The component reference or id to remove.
4527 * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
4528 * Defaults to the value of this Container's {@link #autoDestroy} config.
4529 * @return {Ext.Component} component The Component that was removed.
4531 remove : function(comp, autoDestroy){
4533 var c = this.getComponent(comp);
4534 if(c && this.fireEvent('beforeremove', this, c) !== false){
4535 this.doRemove(c, autoDestroy);
4536 this.fireEvent('remove', this, c);
4541 onRemove: function(c){
4542 // Empty template method
4546 doRemove: function(c, autoDestroy){
4547 var l = this.layout,
4548 hasLayout = l && this.rendered;
4553 this.items.remove(c);
4556 if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){
4565 * Removes all components from this container.
4566 * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
4567 * Defaults to the value of this Container's {@link #autoDestroy} config.
4568 * @return {Array} Array of the destroyed components
4570 removeAll: function(autoDestroy){
4572 var item, rem = [], items = [];
4573 this.items.each(function(i){
4576 for (var i = 0, len = rem.length; i < len; ++i){
4578 this.remove(item, autoDestroy);
4579 if(item.ownerCt !== this){
4587 * Examines this container's <code>{@link #items}</code> <b>property</b>
4588 * and gets a direct child component of this container.
4589 * @param {String/Number} comp This parameter may be any of the following:
4590 * <div><ul class="mdetail-params">
4591 * <li>a <b><code>String</code></b> : representing the <code>{@link Ext.Component#itemId itemId}</code>
4592 * or <code>{@link Ext.Component#id id}</code> of the child component </li>
4593 * <li>a <b><code>Number</code></b> : representing the position of the child component
4594 * within the <code>{@link #items}</code> <b>property</b></li>
4596 * <p>For additional information see {@link Ext.util.MixedCollection#get}.
4597 * @return Ext.Component The component (if found).
4599 getComponent : function(comp){
4600 if(Ext.isObject(comp)){
4601 comp = comp.getItemId();
4603 return this.items.get(comp);
4607 lookupComponent : function(comp){
4608 if(Ext.isString(comp)){
4609 return Ext.ComponentMgr.get(comp);
4610 }else if(!comp.events){
4611 return this.createComponent(comp);
4617 createComponent : function(config, defaultType){
4618 if (config.render) {
4621 // add in ownerCt at creation time but then immediately
4622 // remove so that onBeforeAdd can handle it
4623 var c = Ext.create(Ext.apply({
4625 }, config), defaultType || this.defaultType);
4626 delete c.initialConfig.ownerCt;
4633 * We can only lay out if there is a view area in which to layout.
4634 * display:none on the layout target, *or any of its parent elements* will mean it has no view area.
4636 canLayout : function() {
4637 var el = this.getVisibilityEl();
4638 return el && el.dom && !el.isStyle("display", "none");
4642 * Force this container's layout to be recalculated. A call to this function is required after adding a new component
4643 * to an already rendered container, or possibly after changing sizing/position properties of child components.
4644 * @param {Boolean} shallow (optional) True to only calc the layout of this component, and let child components auto
4645 * calc layouts as required (defaults to false, which calls doLayout recursively for each subcontainer)
4646 * @param {Boolean} force (optional) True to force a layout to occur, even if the item is hidden.
4647 * @return {Ext.Container} this
4650 doLayout : function(shallow, force){
4651 var rendered = this.rendered,
4652 forceLayout = force || this.forceLayout;
4654 if(this.collapsed || !this.canLayout()){
4655 this.deferLayout = this.deferLayout || !shallow;
4659 shallow = shallow && !this.deferLayout;
4661 delete this.deferLayout;
4663 if(rendered && this.layout){
4664 this.layout.layout();
4666 if(shallow !== true && this.items){
4667 var cs = this.items.items;
4668 for(var i = 0, len = cs.length; i < len; i++){
4671 c.doLayout(false, forceLayout);
4676 this.onLayout(shallow, forceLayout);
4678 // Initial layout completed
4679 this.hasLayout = true;
4680 delete this.forceLayout;
4683 onLayout : Ext.emptyFn,
4686 shouldBufferLayout: function(){
4688 * Returns true if the container should buffer a layout.
4689 * This is true only if the container has previously been laid out
4690 * and has a parent container that is pending a layout.
4692 var hl = this.hasLayout;
4694 // Only ever buffer if we've laid out the first time and we have one pending.
4695 return hl ? !this.hasLayoutPending() : false;
4697 // Never buffer initial layout
4702 hasLayoutPending: function(){
4703 // Traverse hierarchy to see if any parent container has a pending layout.
4704 var pending = false;
4705 this.ownerCt.bubble(function(c){
4706 if(c.layoutPending){
4714 onShow : function(){
4715 // removes css classes that were added to hide
4716 Ext.Container.superclass.onShow.call(this);
4717 // If we were sized during the time we were hidden, layout.
4718 if(Ext.isDefined(this.deferLayout)){
4719 delete this.deferLayout;
4720 this.doLayout(true);
4725 * Returns the layout currently in use by the container. If the container does not currently have a layout
4726 * set, a default {@link Ext.layout.ContainerLayout} will be created and set as the container's layout.
4727 * @return {ContainerLayout} layout The container's layout
4729 getLayout : function(){
4731 var layout = new Ext.layout.AutoLayout(this.layoutConfig);
4732 this.setLayout(layout);
4738 beforeDestroy : function(){
4741 while(c = this.items.first()){
4742 this.doRemove(c, true);
4745 if(this.monitorResize){
4746 Ext.EventManager.removeResizeListener(this.doLayout, this);
4748 Ext.destroy(this.layout);
4749 Ext.Container.superclass.beforeDestroy.call(this);
4753 * Bubbles up the component/container heirarchy, calling the specified function with each component. The scope (<i>this</i>) of
4754 * function call will be the scope provided or the current component. The arguments to the function
4755 * will be the args provided or the current component. If the function returns false at any point,
4756 * the bubble is stopped.
4757 * @param {Function} fn The function to call
4758 * @param {Object} scope (optional) The scope of the function (defaults to current node)
4759 * @param {Array} args (optional) The args to call the function with (default to passing the current component)
4760 * @return {Ext.Container} this
4762 bubble : function(fn, scope, args){
4765 if(fn.apply(scope || p, args || [p]) === false){
4774 * Cascades down the component/container heirarchy from this component (called first), calling the specified function with
4775 * each component. The scope (<i>this</i>) of
4776 * function call will be the scope provided or the current component. The arguments to the function
4777 * will be the args provided or the current component. If the function returns false at any point,
4778 * the cascade is stopped on that branch.
4779 * @param {Function} fn The function to call
4780 * @param {Object} scope (optional) The scope of the function (defaults to current component)
4781 * @param {Array} args (optional) The args to call the function with (defaults to passing the current component)
4782 * @return {Ext.Container} this
4784 cascade : function(fn, scope, args){
4785 if(fn.apply(scope || this, args || [this]) !== false){
4787 var cs = this.items.items;
4788 for(var i = 0, len = cs.length; i < len; i++){
4790 cs[i].cascade(fn, scope, args);
4792 fn.apply(scope || cs[i], args || [cs[i]]);
4801 * Find a component under this container at any level by id
4802 * @param {String} id
4803 * @return Ext.Component
4805 findById : function(id){
4807 this.cascade(function(c){
4808 if(ct != c && c.id === id){
4817 * Find a component under this container at any level by xtype or class
4818 * @param {String/Class} xtype The xtype string for a component, or the class of the component directly
4819 * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
4820 * the default), or true to check whether this Component is directly of the specified xtype.
4821 * @return {Array} Array of Ext.Components
4823 findByType : function(xtype, shallow){
4824 return this.findBy(function(c){
4825 return c.isXType(xtype, shallow);
4830 * Find a component under this container at any level by property
4831 * @param {String} prop
4832 * @param {String} value
4833 * @return {Array} Array of Ext.Components
4835 find : function(prop, value){
4836 return this.findBy(function(c){
4837 return c[prop] === value;
4842 * Find a component under this container at any level by a custom function. If the passed function returns
4843 * true, the component will be included in the results. The passed function is called with the arguments (component, this container).
4844 * @param {Function} fn The function to call
4845 * @param {Object} scope (optional)
4846 * @return {Array} Array of Ext.Components
4848 findBy : function(fn, scope){
4849 var m = [], ct = this;
4850 this.cascade(function(c){
4851 if(ct != c && fn.call(scope || c, c, ct) === true){
4859 * Get a component contained by this container (alias for items.get(key))
4860 * @param {String/Number} key The index or id of the component
4861 * @return {Ext.Component} Ext.Component
4863 get : function(key){
4864 return this.items.get(key);
4868 Ext.Container.LAYOUTS = {};
4869 Ext.reg('container', Ext.Container);
4871 * @class Ext.layout.ContainerLayout
4872 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
4873 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
4875 Ext.layout.ContainerLayout = Ext.extend(Object, {
4877 * @cfg {String} extraCls
4878 * <p>An optional extra CSS class that will be added to the container. This can be useful for adding
4879 * customized styles to the container or any of its children using standard CSS rules. See
4880 * {@link Ext.Component}.{@link Ext.Component#ctCls ctCls} also.</p>
4881 * <p><b>Note</b>: <tt>extraCls</tt> defaults to <tt>''</tt> except for the following classes
4882 * which assign a value by default:
4883 * <div class="mdetail-params"><ul>
4884 * <li>{@link Ext.layout.AbsoluteLayout Absolute Layout} : <tt>'x-abs-layout-item'</tt></li>
4885 * <li>{@link Ext.layout.Box Box Layout} : <tt>'x-box-item'</tt></li>
4886 * <li>{@link Ext.layout.ColumnLayout Column Layout} : <tt>'x-column'</tt></li>
4888 * To configure the above Classes with an extra CSS class append to the default. For example,
4889 * for ColumnLayout:<pre><code>
4890 * extraCls: 'x-column custom-class'
4895 * @cfg {Boolean} renderHidden
4896 * True to hide each contained item on render (defaults to false).
4900 * A reference to the {@link Ext.Component} that is active. For example, <pre><code>
4901 * if(myPanel.layout.activeItem.id == 'item-1') { ... }
4903 * <tt>activeItem</tt> only applies to layout styles that can display items one at a time
4904 * (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout}
4905 * and {@link Ext.layout.FitLayout}). Read-only. Related to {@link Ext.Container#activeItem}.
4906 * @type {Ext.Component}
4907 * @property activeItem
4911 monitorResize:false,
4915 constructor : function(config){
4916 this.id = Ext.id(null, 'ext-layout-');
4917 Ext.apply(this, config);
4922 /* Workaround for how IE measures autoWidth elements. It prefers bottom-up measurements
4923 whereas other browser prefer top-down. We will hide all target child elements before we measure and
4924 put them back to get an accurate measurement.
4926 IEMeasureHack : function(target, viewFlag) {
4927 var tChildren = target.dom.childNodes, tLen = tChildren.length, c, d = [], e, i, ret;
4928 for (i = 0 ; i < tLen ; i++) {
4932 d[i] = e.getStyle('display');
4933 e.setStyle({display: 'none'});
4936 ret = target ? target.getViewSize(viewFlag) : {};
4937 for (i = 0 ; i < tLen ; i++) {
4941 e.setStyle({display: d[i]});
4947 // Placeholder for the derived layouts
4948 getLayoutTargetSize : Ext.EmptyFn,
4951 layout : function(){
4952 var ct = this.container, target = ct.getLayoutTarget();
4953 if(!(this.hasLayout || Ext.isEmpty(this.targetCls))){
4954 target.addClass(this.targetCls);
4956 this.onLayout(ct, target);
4957 ct.fireEvent('afterlayout', ct, this);
4961 onLayout : function(ct, target){
4962 this.renderAll(ct, target);
4966 isValidParent : function(c, target){
4967 return target && c.getPositionEl().dom.parentNode == (target.dom || target);
4971 renderAll : function(ct, target){
4972 var items = ct.items.items, i, c, len = items.length;
4973 for(i = 0; i < len; i++) {
4975 if(c && (!c.rendered || !this.isValidParent(c, target))){
4976 this.renderItem(c, i, target);
4983 * Renders the given Component into the target Element. If the Component is already rendered,
4984 * it is moved to the provided target instead.
4985 * @param {Ext.Component} c The Component to render
4986 * @param {Number} position The position within the target to render the item to
4987 * @param {Ext.Element} target The target Element
4989 renderItem : function(c, position, target){
4992 c.render(target, position);
4993 this.configureItem(c, position);
4994 } else if (!this.isValidParent(c, target)) {
4995 if (Ext.isNumber(position)) {
4996 position = target.dom.childNodes[position];
4999 target.dom.insertBefore(c.getPositionEl().dom, position || null);
5000 c.container = target;
5001 this.configureItem(c, position);
5007 // Get all rendered items to lay out.
5008 getRenderedItems: function(ct){
5009 var t = ct.getLayoutTarget(), cti = ct.items.items, len = cti.length, i, c, items = [];
5010 for (i = 0; i < len; i++) {
5011 if((c = cti[i]).rendered && this.isValidParent(c, t)){
5020 * Applies extraCls and hides the item if renderHidden is true
5022 configureItem: function(c, position){
5023 if (this.extraCls) {
5024 var t = c.getPositionEl ? c.getPositionEl() : c;
5025 t.addClass(this.extraCls);
5028 // If we are forcing a layout, do so *before* we hide so elements have height/width
5029 if (c.doLayout && this.forceLayout) {
5032 if (this.renderHidden && c != this.activeItem) {
5037 onRemove: function(c){
5038 if(this.activeItem == c){
5039 delete this.activeItem;
5041 if(c.rendered && this.extraCls){
5042 var t = c.getPositionEl ? c.getPositionEl() : c;
5043 t.removeClass(this.extraCls);
5047 afterRemove: function(c){
5048 if(c.removeRestore){
5049 c.removeMode = 'container';
5050 delete c.removeRestore;
5055 onResize: function(){
5056 var ct = this.container,
5061 if(b = ct.bufferResize && ct.shouldBufferLayout()){
5062 if(!this.resizeTask){
5063 this.resizeTask = new Ext.util.DelayedTask(this.runLayout, this);
5064 this.resizeBuffer = Ext.isNumber(b) ? b : 50;
5066 ct.layoutPending = true;
5067 this.resizeTask.delay(this.resizeBuffer);
5073 runLayout: function(){
5074 var ct = this.container;
5077 delete ct.layoutPending;
5081 setContainer : function(ct){
5083 * This monitorResize flag will be renamed soon as to avoid confusion
5084 * with the Container version which hooks onWindowResize to doLayout
5086 * monitorResize flag in this context attaches the resize event between
5087 * a container and it's layout
5089 if(this.monitorResize && ct != this.container){
5090 var old = this.container;
5092 old.un(old.resizeEvent, this.onResize, this);
5095 ct.on(ct.resizeEvent, this.onResize, this);
5098 this.container = ct;
5102 * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
5103 * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
5104 * @param {Number|String} v The encoded margins
5105 * @return {Object} An object with margin sizes for top, right, bottom and left
5107 parseMargins : function(v){
5108 if (Ext.isNumber(v)) {
5111 var ms = v.split(' '),
5115 ms[1] = ms[2] = ms[3] = ms[0];
5116 } else if(len == 2) {
5119 } else if(len == 3) {
5124 top :parseInt(ms[0], 10) || 0,
5125 right :parseInt(ms[1], 10) || 0,
5126 bottom:parseInt(ms[2], 10) || 0,
5127 left :parseInt(ms[3], 10) || 0
5132 * The {@link Ext.Template Ext.Template} used by Field rendering layout classes (such as
5133 * {@link Ext.layout.FormLayout}) to create the DOM structure of a fully wrapped,
5134 * labeled and styled form Field. A default Template is supplied, but this may be
5135 * overriden to create custom field structures. The template processes values returned from
5136 * {@link Ext.layout.FormLayout#getTemplateArgs}.
5137 * @property fieldTpl
5138 * @type Ext.Template
5140 fieldTpl: (function() {
5141 var t = new Ext.Template(
5142 '<div class="x-form-item {itemCls}" tabIndex="-1">',
5143 '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{labelSeparator}</label>',
5144 '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
5145 '</div><div class="{clearCls}"></div>',
5148 t.disableFormats = true;
5153 * Destroys this layout. This is a template method that is empty by default, but should be implemented
5154 * by subclasses that require explicit destruction to purge event handlers or remove DOM nodes.
5157 destroy : function(){
5158 // Stop any buffered layout tasks
5159 if(this.resizeTask && this.resizeTask.cancel){
5160 this.resizeTask.cancel();
5162 if(!Ext.isEmpty(this.targetCls)){
5163 var target = this.container.getLayoutTarget();
5165 target.removeClass(this.targetCls);
5170 * @class Ext.layout.AutoLayout
5171 * <p>The AutoLayout is the default layout manager delegated by {@link Ext.Container} to
5172 * render any child Components when no <tt>{@link Ext.Container#layout layout}</tt> is configured into
5173 * a {@link Ext.Container Container}.</tt>. AutoLayout provides only a passthrough of any layout calls
5174 * to any child containers.</p>
5176 Ext.layout.AutoLayout = Ext.extend(Ext.layout.ContainerLayout, {
5179 monitorResize: true,
5181 onLayout : function(ct, target){
5182 Ext.layout.AutoLayout.superclass.onLayout.call(this, ct, target);
5183 var cs = this.getRenderedItems(ct), len = cs.length, i, c;
5184 for(i = 0; i < len; i++){
5187 // Shallow layout children
5194 Ext.Container.LAYOUTS['auto'] = Ext.layout.AutoLayout;
5196 * @class Ext.layout.FitLayout
5197 * @extends Ext.layout.ContainerLayout
5198 * <p>This is a base class for layouts that contain <b>a single item</b> that automatically expands to fill the layout's
5199 * container. This class is intended to be extended or created via the <tt>layout:'fit'</tt> {@link Ext.Container#layout}
5200 * config, and should generally not need to be created directly via the new keyword.</p>
5201 * <p>FitLayout does not have any direct config options (other than inherited ones). To fit a panel to a container
5202 * using FitLayout, simply set layout:'fit' on the container and add a single panel to it. If the container has
5203 * multiple panels, only the first one will be displayed. Example usage:</p>
5205 var p = new Ext.Panel({
5206 title: 'Fit Layout',
5209 title: 'Inner Panel',
5210 html: '<p>This is the inner panel content</p>',
5216 Ext.layout.FitLayout = Ext.extend(Ext.layout.ContainerLayout, {
5222 getLayoutTargetSize : function() {
5223 var target = this.container.getLayoutTarget();
5227 // Style Sized (scrollbars not included)
5228 return target.getStyleSize();
5232 onLayout : function(ct, target){
5233 Ext.layout.FitLayout.superclass.onLayout.call(this, ct, target);
5235 this.setItemSize(this.activeItem || ct.items.itemAt(0), this.getLayoutTargetSize());
5240 setItemSize : function(item, size){
5241 if(item && size.height > 0){ // display none?
5246 Ext.Container.LAYOUTS['fit'] = Ext.layout.FitLayout;/**
5247 * @class Ext.layout.CardLayout
5248 * @extends Ext.layout.FitLayout
5249 * <p>This layout manages multiple child Components, each fitted to the Container, where only a single child Component can be
5250 * visible at any given time. This layout style is most commonly used for wizards, tab implementations, etc.
5251 * This class is intended to be extended or created via the layout:'card' {@link Ext.Container#layout} config,
5252 * and should generally not need to be created directly via the new keyword.</p>
5253 * <p>The CardLayout's focal method is {@link #setActiveItem}. Since only one panel is displayed at a time,
5254 * the only way to move from one Component to the next is by calling setActiveItem, passing the id or index of
5255 * the next panel to display. The layout itself does not provide a user interface for handling this navigation,
5256 * so that functionality must be provided by the developer.</p>
5257 * <p>In the following example, a simplistic wizard setup is demonstrated. A button bar is added
5258 * to the footer of the containing panel to provide navigation buttons. The buttons will be handled by a
5259 * common navigation routine -- for this example, the implementation of that routine has been ommitted since
5260 * it can be any type of custom logic. Note that other uses of a CardLayout (like a tab control) would require a
5261 * completely different implementation. For serious implementations, a better approach would be to extend
5262 * CardLayout to provide the custom functionality needed. Example usage:</p>
5264 var navHandler = function(direction){
5265 // This routine could contain business logic required to manage the navigation steps.
5266 // It would call setActiveItem as needed, manage navigation button state, handle any
5267 // branching logic that might be required, handle alternate actions like cancellation
5268 // or finalization, etc. A complete wizard implementation could get pretty
5269 // sophisticated depending on the complexity required, and should probably be
5270 // done as a subclass of CardLayout in a real-world implementation.
5273 var card = new Ext.Panel({
5274 title: 'Example Wizard',
5276 activeItem: 0, // make sure the active item is set on the container config!
5277 bodyStyle: 'padding:15px',
5279 // applied to each contained panel
5282 // just an example of one possible navigation scheme, using buttons
5287 handler: navHandler.createDelegate(this, [-1]),
5290 '->', // greedy spacer so that the buttons are aligned to each side
5294 handler: navHandler.createDelegate(this, [1])
5297 // the panels (or "cards") within the layout
5300 html: '<h1>Welcome to the Wizard!</h1><p>Step 1 of 3</p>'
5303 html: '<p>Step 2 of 3</p>'
5306 html: '<h1>Congratulations!</h1><p>Step 3 of 3 - Complete</p>'
5311 Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, {
5313 * @cfg {Boolean} deferredRender
5314 * True to render each contained item at the time it becomes active, false to render all contained items
5315 * as soon as the layout is rendered (defaults to false). If there is a significant amount of content or
5316 * a lot of heavy controls being rendered into panels that are not displayed by default, setting this to
5317 * true might improve performance.
5319 deferredRender : false,
5322 * @cfg {Boolean} layoutOnCardChange
5323 * True to force a layout of the active item when the active card is changed. Defaults to false.
5325 layoutOnCardChange : false,
5328 * @cfg {Boolean} renderHidden @hide
5331 renderHidden : true,
5336 * Sets the active (visible) item in the layout.
5337 * @param {String/Number} item The string component id or numeric index of the item to activate
5339 setActiveItem : function(item){
5340 var ai = this.activeItem,
5341 ct = this.container;
5342 item = ct.getComponent(item);
5344 // Is this a valid, different card?
5345 if(item && ai != item){
5347 // Changing cards, hide the current one
5350 if (ai.hidden !== true) {
5353 ai.fireEvent('deactivate', ai);
5356 var layout = item.doLayout && (this.layoutOnCardChange || !item.rendered);
5358 // Change activeItem reference
5359 this.activeItem = item;
5361 // The container is about to get a recursive layout, remove any deferLayout reference
5362 // because it will trigger a redundant layout.
5363 delete item.deferLayout;
5365 // Show the new component
5373 item.fireEvent('activate', item);
5378 renderAll : function(ct, target){
5379 if(this.deferredRender){
5380 this.renderItem(this.activeItem, undefined, target);
5382 Ext.layout.CardLayout.superclass.renderAll.call(this, ct, target);
5386 Ext.Container.LAYOUTS['card'] = Ext.layout.CardLayout;
5388 * @class Ext.layout.AnchorLayout
5389 * @extends Ext.layout.ContainerLayout
5390 * <p>This is a layout that enables anchoring of contained elements relative to the container's dimensions.
5391 * If the container is resized, all anchored items are automatically rerendered according to their
5392 * <b><tt>{@link #anchor}</tt></b> rules.</p>
5393 * <p>This class is intended to be extended or created via the layout:'anchor' {@link Ext.Container#layout}
5394 * config, and should generally not need to be created directly via the new keyword.</p>
5395 * <p>AnchorLayout does not have any direct config options (other than inherited ones). By default,
5396 * AnchorLayout will calculate anchor measurements based on the size of the container itself. However, the
5397 * container using the AnchorLayout can supply an anchoring-specific config property of <b>anchorSize</b>.
5398 * If anchorSize is specifed, the layout will use it as a virtual container for the purposes of calculating
5399 * anchor measurements based on it instead, allowing the container to be sized independently of the anchoring
5400 * logic if necessary. For example:</p>
5402 var viewport = new Ext.Viewport({
5404 anchorSize: {width:800, height:600},
5424 Ext.layout.AnchorLayout = Ext.extend(Ext.layout.ContainerLayout, {
5426 * @cfg {String} anchor
5427 * <p>This configuation option is to be applied to <b>child <tt>items</tt></b> of a container managed by
5428 * this layout (ie. configured with <tt>layout:'anchor'</tt>).</p><br/>
5430 * <p>This value is what tells the layout how an item should be anchored to the container. <tt>items</tt>
5431 * added to an AnchorLayout accept an anchoring-specific config property of <b>anchor</b> which is a string
5432 * containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%').
5433 * The following types of anchor values are supported:<div class="mdetail-params"><ul>
5435 * <li><b>Percentage</b> : Any value between 1 and 100, expressed as a percentage.<div class="sub-desc">
5436 * The first anchor is the percentage width that the item should take up within the container, and the
5437 * second is the percentage height. For example:<pre><code>
5438 // two values specified
5439 anchor: '100% 50%' // render item complete width of the container and
5440 // 1/2 height of the container
5441 // one value specified
5442 anchor: '100%' // the width value; the height will default to auto
5443 * </code></pre></div></li>
5445 * <li><b>Offsets</b> : Any positive or negative integer value.<div class="sub-desc">
5446 * This is a raw adjustment where the first anchor is the offset from the right edge of the container,
5447 * and the second is the offset from the bottom edge. For example:<pre><code>
5448 // two values specified
5449 anchor: '-50 -100' // render item the complete width of the container
5450 // minus 50 pixels and
5451 // the complete height minus 100 pixels.
5452 // one value specified
5453 anchor: '-50' // anchor value is assumed to be the right offset value
5454 // bottom offset will default to 0
5455 * </code></pre></div></li>
5457 * <li><b>Sides</b> : Valid values are <tt>'right'</tt> (or <tt>'r'</tt>) and <tt>'bottom'</tt>
5458 * (or <tt>'b'</tt>).<div class="sub-desc">
5459 * Either the container must have a fixed size or an anchorSize config value defined at render time in
5460 * order for these to have any effect.</div></li>
5462 * <li><b>Mixed</b> : <div class="sub-desc">
5463 * Anchor values can also be mixed as needed. For example, to render the width offset from the container
5464 * right edge by 50 pixels and 75% of the container's height use:
5467 * </code></pre></div></li>
5474 monitorResize : true,
5479 * @cfg {String} defaultAnchor
5481 * default anchor for all child container items applied if no anchor or specific width is set on the child item. Defaults to '100%'.
5484 defaultAnchor : '100%',
5486 parseAnchorRE : /^(r|right|b|bottom)$/i,
5488 getLayoutTargetSize : function() {
5489 var target = this.container.getLayoutTarget();
5493 // Style Sized (scrollbars not included)
5494 return target.getStyleSize();
5498 onLayout : function(ct, target){
5499 Ext.layout.AnchorLayout.superclass.onLayout.call(this, ct, target);
5500 var size = this.getLayoutTargetSize();
5502 var w = size.width, h = size.height;
5504 if(w < 20 && h < 20){
5508 // find the container anchoring size
5511 if(typeof ct.anchorSize == 'number'){
5514 aw = ct.anchorSize.width;
5515 ah = ct.anchorSize.height;
5518 aw = ct.initialConfig.width;
5519 ah = ct.initialConfig.height;
5522 var cs = this.getRenderedItems(ct), len = cs.length, i, c, a, cw, ch, el, vs, boxes = [];
5523 for(i = 0; i < len; i++){
5525 el = c.getPositionEl();
5527 // If a child container item has no anchor and no specific width, set the child to the default anchor size
5528 if (!c.anchor && c.items && !Ext.isNumber(c.width) && !(Ext.isIE6 && Ext.isStrict)){
5529 c.anchor = this.defaultAnchor;
5534 if(!a){ // cache all anchor values
5535 vs = c.anchor.split(' ');
5536 c.anchorSpec = a = {
5537 right: this.parseAnchor(vs[0], c.initialConfig.width, aw),
5538 bottom: this.parseAnchor(vs[1], c.initialConfig.height, ah)
5541 cw = a.right ? this.adjustWidthAnchor(a.right(w) - el.getMargins('lr'), c) : undefined;
5542 ch = a.bottom ? this.adjustHeightAnchor(a.bottom(h) - el.getMargins('tb'), c) : undefined;
5547 width: cw || undefined,
5548 height: ch || undefined
5553 for (i = 0, len = boxes.length; i < len; i++) {
5555 c.comp.setSize(c.width, c.height);
5560 parseAnchor : function(a, start, cstart){
5561 if(a && a != 'none'){
5564 if(this.parseAnchorRE.test(a)){
5565 var diff = cstart - start;
5573 }else if(a.indexOf('%') != -1){
5574 var ratio = parseFloat(a.replace('%', ''))*.01;
5578 return Math.floor(v*ratio);
5581 // simple offset adjustment
5583 a = parseInt(a, 10);
5598 adjustWidthAnchor : function(value, comp){
5603 adjustHeightAnchor : function(value, comp){
5608 * @property activeItem
5612 Ext.Container.LAYOUTS['anchor'] = Ext.layout.AnchorLayout;
5614 * @class Ext.layout.ColumnLayout
5615 * @extends Ext.layout.ContainerLayout
5616 * <p>This is the layout style of choice for creating structural layouts in a multi-column format where the width of
5617 * each column can be specified as a percentage or fixed width, but the height is allowed to vary based on the content.
5618 * This class is intended to be extended or created via the layout:'column' {@link Ext.Container#layout} config,
5619 * and should generally not need to be created directly via the new keyword.</p>
5620 * <p>ColumnLayout does not have any direct config options (other than inherited ones), but it does support a
5621 * specific config property of <b><tt>columnWidth</tt></b> that can be included in the config of any panel added to it. The
5622 * layout will use the columnWidth (if present) or width of each panel during layout to determine how to size each panel.
5623 * If width or columnWidth is not specified for a given panel, its width will default to the panel's width (or auto).</p>
5624 * <p>The width property is always evaluated as pixels, and must be a number greater than or equal to 1.
5625 * The columnWidth property is always evaluated as a percentage, and must be a decimal value greater than 0 and
5626 * less than 1 (e.g., .25).</p>
5627 * <p>The basic rules for specifying column widths are pretty simple. The logic makes two passes through the
5628 * set of contained panels. During the first layout pass, all panels that either have a fixed width or none
5629 * specified (auto) are skipped, but their widths are subtracted from the overall container width. During the second
5630 * pass, all panels with columnWidths are assigned pixel widths in proportion to their percentages based on
5631 * the total <b>remaining</b> container width. In other words, percentage width panels are designed to fill the space
5632 * left over by all the fixed-width and/or auto-width panels. Because of this, while you can specify any number of columns
5633 * with different percentages, the columnWidths must always add up to 1 (or 100%) when added together, otherwise your
5634 * layout may not render as expected. Example usage:</p>
5636 // All columns are percentages -- they must add up to 1
5637 var p = new Ext.Panel({
5638 title: 'Column Layout - Percentage Only',
5652 // Mix of width and columnWidth -- all columnWidth values must add up
5653 // to 1. The first column will take up exactly 120px, and the last two
5654 // columns will fill the remaining container width.
5655 var p = new Ext.Panel({
5656 title: 'Column Layout - Mixed',
5671 Ext.layout.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, {
5677 extraCls: 'x-column',
5683 targetCls: 'x-column-layout-ct',
5685 isValidParent : function(c, target){
5686 return this.innerCt && c.getPositionEl().dom.parentNode == this.innerCt.dom;
5689 getLayoutTargetSize : function() {
5690 var target = this.container.getLayoutTarget(), ret;
5692 ret = target.getViewSize();
5694 // IE in strict mode will return a width of 0 on the 1st pass of getViewSize.
5695 // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly
5697 if (Ext.isIE && Ext.isStrict && ret.width == 0){
5698 ret = target.getStyleSize();
5701 ret.width -= target.getPadding('lr');
5702 ret.height -= target.getPadding('tb');
5707 renderAll : function(ct, target) {
5709 // the innerCt prevents wrapping and shuffling while
5710 // the container is resizing
5711 this.innerCt = target.createChild({cls:'x-column-inner'});
5712 this.innerCt.createChild({cls:'x-clear'});
5714 Ext.layout.ColumnLayout.superclass.renderAll.call(this, ct, this.innerCt);
5718 onLayout : function(ct, target){
5719 var cs = ct.items.items,
5726 this.renderAll(ct, target);
5728 var size = this.getLayoutTargetSize();
5730 if(size.width < 1 && size.height < 1){ // display none?
5734 var w = size.width - this.scrollOffset,
5738 this.innerCt.setWidth(w);
5740 // some columns can be percentages while others are fixed
5741 // so we need to make 2 passes
5743 for(i = 0; i < len; i++){
5745 m = c.getPositionEl().getMargins('lr');
5748 pw -= (c.getWidth() + m);
5752 pw = pw < 0 ? 0 : pw;
5754 for(i = 0; i < len; i++){
5758 c.setSize(Math.floor(c.columnWidth * pw) - m);
5762 // Browsers differ as to when they account for scrollbars. We need to re-measure to see if the scrollbar
5763 // spaces were accounted for properly. If not, re-layout.
5765 if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) {
5766 var ts = this.getLayoutTargetSize();
5767 if (ts.width != size.width){
5768 this.adjustmentPass = true;
5769 this.onLayout(ct, target);
5773 delete this.adjustmentPass;
5777 * @property activeItem
5782 Ext.Container.LAYOUTS['column'] = Ext.layout.ColumnLayout;
5784 * @class Ext.layout.BorderLayout
5785 * @extends Ext.layout.ContainerLayout
5786 * <p>This is a multi-pane, application-oriented UI layout style that supports multiple
5787 * nested panels, automatic {@link Ext.layout.BorderLayout.Region#split split} bars between
5788 * {@link Ext.layout.BorderLayout.Region#BorderLayout.Region regions} and built-in
5789 * {@link Ext.layout.BorderLayout.Region#collapsible expanding and collapsing} of regions.</p>
5790 * <p>This class is intended to be extended or created via the <tt>layout:'border'</tt>
5791 * {@link Ext.Container#layout} config, and should generally not need to be created directly
5792 * via the new keyword.</p>
5793 * <p>BorderLayout does not have any direct config options (other than inherited ones).
5794 * All configuration options available for customizing the BorderLayout are at the
5795 * {@link Ext.layout.BorderLayout.Region} and {@link Ext.layout.BorderLayout.SplitRegion}
5797 * <p>Example usage:</p>
5799 var myBorderPanel = new Ext.Panel({
5800 {@link Ext.Component#renderTo renderTo}: document.body,
5801 {@link Ext.BoxComponent#width width}: 700,
5802 {@link Ext.BoxComponent#height height}: 500,
5803 {@link Ext.Panel#title title}: 'Border Layout',
5804 {@link Ext.Container#layout layout}: 'border',
5805 {@link Ext.Container#items items}: [{
5806 {@link Ext.Panel#title title}: 'South Region is resizable',
5807 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'south', // position for region
5808 {@link Ext.BoxComponent#height height}: 100,
5809 {@link Ext.layout.BorderLayout.Region#split split}: true, // enable resizing
5810 {@link Ext.SplitBar#minSize minSize}: 75, // defaults to {@link Ext.layout.BorderLayout.Region#minHeight 50}
5811 {@link Ext.SplitBar#maxSize maxSize}: 150,
5812 {@link Ext.layout.BorderLayout.Region#margins margins}: '0 5 5 5'
5814 // xtype: 'panel' implied by default
5815 {@link Ext.Panel#title title}: 'West Region is collapsible',
5816 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}:'west',
5817 {@link Ext.layout.BorderLayout.Region#margins margins}: '5 0 0 5',
5818 {@link Ext.BoxComponent#width width}: 200,
5819 {@link Ext.layout.BorderLayout.Region#collapsible collapsible}: true, // make collapsible
5820 {@link Ext.layout.BorderLayout.Region#cmargins cmargins}: '5 5 0 5', // adjust top margin when collapsed
5821 {@link Ext.Component#id id}: 'west-region-container',
5822 {@link Ext.Container#layout layout}: 'fit',
5823 {@link Ext.Panel#unstyled unstyled}: true
5825 {@link Ext.Panel#title title}: 'Center Region',
5826 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'center', // center region is required, no width/height specified
5827 {@link Ext.Component#xtype xtype}: 'container',
5828 {@link Ext.Container#layout layout}: 'fit',
5829 {@link Ext.layout.BorderLayout.Region#margins margins}: '5 5 0 0'
5833 * <p><b><u>Notes</u></b>:</p><div class="mdetail-params"><ul>
5834 * <li>Any container using the BorderLayout <b>must</b> have a child item with <tt>region:'center'</tt>.
5835 * The child item in the center region will always be resized to fill the remaining space not used by
5836 * the other regions in the layout.</li>
5837 * <li>Any child items with a region of <tt>west</tt> or <tt>east</tt> must have <tt>width</tt> defined
5838 * (an integer representing the number of pixels that the region should take up).</li>
5839 * <li>Any child items with a region of <tt>north</tt> or <tt>south</tt> must have <tt>height</tt> defined.</li>
5840 * <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
5841 * Components within a BorderLayout, have them wrapped by an additional Container which is directly
5842 * managed by the BorderLayout. If the region is to be collapsible, the Container used directly
5843 * by the BorderLayout manager should be a Panel. In the following example a Container (an Ext.Panel)
5844 * is added to the west region:
5845 * <div style="margin-left:16px"><pre><code>
5846 wrc = {@link Ext#getCmp Ext.getCmp}('west-region-container');
5847 wrc.{@link Ext.Panel#removeAll removeAll}();
5848 wrc.{@link Ext.Container#add add}({
5849 title: 'Added Panel',
5850 html: 'Some content'
5852 wrc.{@link Ext.Container#doLayout doLayout}();
5853 * </code></pre></div>
5855 * <li> To reference a {@link Ext.layout.BorderLayout.Region Region}:
5856 * <div style="margin-left:16px"><pre><code>
5857 wr = myBorderPanel.layout.west;
5858 * </code></pre></div>
5862 Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {
5870 targetCls: 'x-border-layout-ct',
5872 getLayoutTargetSize : function() {
5873 var target = this.container.getLayoutTarget();
5874 return target ? target.getViewSize() : {};
5878 onLayout : function(ct, target){
5879 var collapsed, i, c, pos, items = ct.items.items, len = items.length;
5882 for(i = 0; i < len; i++) {
5888 c.collapsed = false;
5890 c.render(target, i);
5891 c.getPositionEl().addClass('x-border-panel');
5893 this[pos] = pos != 'center' && c.split ?
5894 new Ext.layout.BorderLayout.SplitRegion(this, c.initialConfig, pos) :
5895 new Ext.layout.BorderLayout.Region(this, c.initialConfig, pos);
5896 this[pos].render(target, c);
5898 this.rendered = true;
5901 var size = this.getLayoutTargetSize();
5902 if(size.width < 20 || size.height < 20){ // display none?
5904 this.restoreCollapsed = collapsed;
5907 }else if(this.restoreCollapsed){
5908 collapsed = this.restoreCollapsed;
5909 delete this.restoreCollapsed;
5912 var w = size.width, h = size.height,
5913 centerW = w, centerH = h, centerY = 0, centerX = 0,
5914 n = this.north, s = this.south, west = this.west, e = this.east, c = this.center,
5915 b, m, totalWidth, totalHeight;
5916 if(!c && Ext.layout.BorderLayout.WARN !== false){
5917 throw 'No center region defined in BorderLayout ' + ct.id;
5920 if(n && n.isVisible()){
5923 b.width = w - (m.left+m.right);
5926 centerY = b.height + b.y + m.bottom;
5930 if(s && s.isVisible()){
5933 b.width = w - (m.left+m.right);
5935 totalHeight = (b.height + m.top + m.bottom);
5936 b.y = h - totalHeight + m.top;
5937 centerH -= totalHeight;
5940 if(west && west.isVisible()){
5942 m = west.getMargins();
5943 b.height = centerH - (m.top+m.bottom);
5945 b.y = centerY + m.top;
5946 totalWidth = (b.width + m.left + m.right);
5947 centerX += totalWidth;
5948 centerW -= totalWidth;
5949 west.applyLayout(b);
5951 if(e && e.isVisible()){
5954 b.height = centerH - (m.top+m.bottom);
5955 totalWidth = (b.width + m.left + m.right);
5956 b.x = w - totalWidth + m.left;
5957 b.y = centerY + m.top;
5958 centerW -= totalWidth;
5964 x: centerX + m.left,
5966 width: centerW - (m.left+m.right),
5967 height: centerH - (m.top+m.bottom)
5969 c.applyLayout(centerBox);
5972 for(i = 0, len = collapsed.length; i < len; i++){
5973 collapsed[i].collapse(false);
5976 if(Ext.isIE && Ext.isStrict){ // workaround IE strict repainting issue
5979 // Putting a border layout into an overflowed container is NOT correct and will make a second layout pass necessary.
5980 if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) {
5981 var ts = this.getLayoutTargetSize();
5982 if (ts.width != size.width || ts.height != size.height){
5983 this.adjustmentPass = true;
5984 this.onLayout(ct, target);
5987 delete this.adjustmentPass;
5990 destroy: function() {
5991 var r = ['north', 'south', 'east', 'west'], i, region;
5992 for (i = 0; i < r.length; i++) {
5993 region = this[r[i]];
5997 }else if (region.split){
5998 region.split.destroy(true);
6002 Ext.layout.BorderLayout.superclass.destroy.call(this);
6006 * @property activeItem
6012 * @class Ext.layout.BorderLayout.Region
6013 * <p>This is a region of a {@link Ext.layout.BorderLayout BorderLayout} that acts as a subcontainer
6014 * within the layout. Each region has its own {@link Ext.layout.ContainerLayout layout} that is
6015 * independent of other regions and the containing BorderLayout, and can be any of the
6016 * {@link Ext.layout.ContainerLayout valid Ext layout types}.</p>
6017 * <p>Region size is managed automatically and cannot be changed by the user -- for
6018 * {@link #split resizable regions}, see {@link Ext.layout.BorderLayout.SplitRegion}.</p>
6020 * Create a new Region.
6021 * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region.
6022 * @param {Object} config The configuration options
6023 * @param {String} position The region position. Valid values are: <tt>north</tt>, <tt>south</tt>,
6024 * <tt>east</tt>, <tt>west</tt> and <tt>center</tt>. Every {@link Ext.layout.BorderLayout BorderLayout}
6025 * <b>must have a center region</b> for the primary content -- all other regions are optional.
6027 Ext.layout.BorderLayout.Region = function(layout, config, pos){
6028 Ext.apply(this, config);
6029 this.layout = layout;
6030 this.position = pos;
6032 if(typeof this.margins == 'string'){
6033 this.margins = this.layout.parseMargins(this.margins);
6035 this.margins = Ext.applyIf(this.margins || {}, this.defaultMargins);
6036 if(this.collapsible){
6037 if(typeof this.cmargins == 'string'){
6038 this.cmargins = this.layout.parseMargins(this.cmargins);
6040 if(this.collapseMode == 'mini' && !this.cmargins){
6041 this.cmargins = {left:0,top:0,right:0,bottom:0};
6043 this.cmargins = Ext.applyIf(this.cmargins || {},
6044 pos == 'north' || pos == 'south' ? this.defaultNSCMargins : this.defaultEWCMargins);
6049 Ext.layout.BorderLayout.Region.prototype = {
6051 * @cfg {Boolean} animFloat
6052 * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated
6053 * panel that will close again once the user mouses out of that panel (or clicks out if
6054 * <tt>{@link #autoHide} = false</tt>). Setting <tt>{@link #animFloat} = false</tt> will
6055 * prevent the open and close of these floated panels from being animated (defaults to <tt>true</tt>).
6058 * @cfg {Boolean} autoHide
6059 * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated
6060 * panel. If <tt>autoHide = true</tt>, the panel will automatically hide after the user mouses
6061 * out of the panel. If <tt>autoHide = false</tt>, the panel will continue to display until the
6062 * user clicks outside of the panel (defaults to <tt>true</tt>).
6065 * @cfg {String} collapseMode
6066 * <tt>collapseMode</tt> supports two configuration values:<div class="mdetail-params"><ul>
6067 * <li><b><tt>undefined</tt></b> (default)<div class="sub-desc">By default, {@link #collapsible}
6068 * regions are collapsed by clicking the expand/collapse tool button that renders into the region's
6069 * title bar.</div></li>
6070 * <li><b><tt>'mini'</tt></b><div class="sub-desc">Optionally, when <tt>collapseMode</tt> is set to
6071 * <tt>'mini'</tt> the region's split bar will also display a small collapse button in the center of
6072 * the bar. In <tt>'mini'</tt> mode the region will collapse to a thinner bar than in normal mode.
6075 * <p><b>Note</b>: if a collapsible region does not have a title bar, then set <tt>collapseMode =
6076 * 'mini'</tt> and <tt>{@link #split} = true</tt> in order for the region to be {@link #collapsible}
6077 * by the user as the expand/collapse tool button (that would go in the title bar) will not be rendered.</p>
6078 * <p>See also <tt>{@link #cmargins}</tt>.</p>
6081 * @cfg {Object} margins
6082 * An object containing margins to apply to the region when in the expanded state in the
6083 * format:<pre><code>
6086 right: (right margin),
6087 bottom: (bottom margin),
6090 * <p>May also be a string containing space-separated, numeric margin values. The order of the
6091 * sides associated with each value matches the way CSS processes margin values:</p>
6092 * <p><div class="mdetail-params"><ul>
6093 * <li>If there is only one value, it applies to all sides.</li>
6094 * <li>If there are two values, the top and bottom borders are set to the first value and the
6095 * right and left are set to the second.</li>
6096 * <li>If there are three values, the top is set to the first value, the left and right are set
6097 * to the second, and the bottom is set to the third.</li>
6098 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
6100 * <p>Defaults to:</p><pre><code>
6101 * {top:0, right:0, bottom:0, left:0}
6105 * @cfg {Object} cmargins
6106 * An object containing margins to apply to the region when in the collapsed state in the
6107 * format:<pre><code>
6110 right: (right margin),
6111 bottom: (bottom margin),
6114 * <p>May also be a string containing space-separated, numeric margin values. The order of the
6115 * sides associated with each value matches the way CSS processes margin values.</p>
6117 * <li>If there is only one value, it applies to all sides.</li>
6118 * <li>If there are two values, the top and bottom borders are set to the first value and the
6119 * right and left are set to the second.</li>
6120 * <li>If there are three values, the top is set to the first value, the left and right are set
6121 * to the second, and the bottom is set to the third.</li>
6122 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
6126 * @cfg {Boolean} collapsible
6127 * <p><tt>true</tt> to allow the user to collapse this region (defaults to <tt>false</tt>). If
6128 * <tt>true</tt>, an expand/collapse tool button will automatically be rendered into the title
6129 * bar of the region, otherwise the button will not be shown.</p>
6130 * <p><b>Note</b>: that a title bar is required to display the collapse/expand toggle button -- if
6131 * no <tt>title</tt> is specified for the region's panel, the region will only be collapsible if
6132 * <tt>{@link #collapseMode} = 'mini'</tt> and <tt>{@link #split} = true</tt>.
6134 collapsible : false,
6136 * @cfg {Boolean} split
6137 * <p><tt>true</tt> to create a {@link Ext.layout.BorderLayout.SplitRegion SplitRegion} and
6138 * display a 5px wide {@link Ext.SplitBar} between this region and its neighbor, allowing the user to
6139 * resize the regions dynamically. Defaults to <tt>false</tt> creating a
6140 * {@link Ext.layout.BorderLayout.Region Region}.</p><br>
6141 * <p><b>Notes</b>:</p><div class="mdetail-params"><ul>
6142 * <li>this configuration option is ignored if <tt>region='center'</tt></li>
6143 * <li>when <tt>split == true</tt>, it is common to specify a
6144 * <tt>{@link Ext.SplitBar#minSize minSize}</tt> and <tt>{@link Ext.SplitBar#maxSize maxSize}</tt>
6145 * for the {@link Ext.BoxComponent BoxComponent} representing the region. These are not native
6146 * configs of {@link Ext.BoxComponent BoxComponent}, and are used only by this class.</li>
6147 * <li>if <tt>{@link #collapseMode} = 'mini'</tt> requires <tt>split = true</tt> to reserve space
6148 * for the collapse tool</tt></li>
6153 * @cfg {Boolean} floatable
6154 * <tt>true</tt> to allow clicking a collapsed region's bar to display the region's panel floated
6155 * above the layout, <tt>false</tt> to force the user to fully expand a collapsed region by
6156 * clicking the expand button to see it again (defaults to <tt>true</tt>).
6160 * @cfg {Number} minWidth
6161 * <p>The minimum allowable width in pixels for this region (defaults to <tt>50</tt>).
6162 * <tt>maxWidth</tt> may also be specified.</p><br>
6163 * <p><b>Note</b>: setting the <tt>{@link Ext.SplitBar#minSize minSize}</tt> /
6164 * <tt>{@link Ext.SplitBar#maxSize maxSize}</tt> supersedes any specified
6165 * <tt>minWidth</tt> / <tt>maxWidth</tt>.</p>
6169 * @cfg {Number} minHeight
6170 * The minimum allowable height in pixels for this region (defaults to <tt>50</tt>)
6171 * <tt>maxHeight</tt> may also be specified.</p><br>
6172 * <p><b>Note</b>: setting the <tt>{@link Ext.SplitBar#minSize minSize}</tt> /
6173 * <tt>{@link Ext.SplitBar#maxSize maxSize}</tt> supersedes any specified
6174 * <tt>minHeight</tt> / <tt>maxHeight</tt>.</p>
6179 defaultMargins : {left:0,top:0,right:0,bottom:0},
6181 defaultNSCMargins : {left:5,top:5,right:5,bottom:5},
6183 defaultEWCMargins : {left:5,top:0,right:5,bottom:0},
6184 floatingZIndex: 100,
6187 * True if this region is collapsed. Read-only.
6191 isCollapsed : false,
6194 * This region's panel. Read-only.
6199 * This region's layout. Read-only.
6204 * This region's layout position (north, south, east, west or center). Read-only.
6206 * @property position
6210 render : function(ct, p){
6212 p.el.enableDisplayMode();
6216 var gs = p.getState, ps = this.position;
6217 p.getState = function(){
6218 return Ext.apply(gs.call(p) || {}, this.state);
6219 }.createDelegate(this);
6222 p.allowQueuedExpand = false;
6224 beforecollapse: this.beforeCollapse,
6225 collapse: this.onCollapse,
6226 beforeexpand: this.beforeExpand,
6227 expand: this.onExpand,
6232 if(this.collapsible || this.floatable){
6233 p.collapseEl = 'el';
6234 p.slideAnchor = this.getSlideAnchor();
6236 if(p.tools && p.tools.toggle){
6237 p.tools.toggle.addClass('x-tool-collapse-'+ps);
6238 p.tools.toggle.addClassOnOver('x-tool-collapse-'+ps+'-over');
6244 getCollapsedEl : function(){
6245 if(!this.collapsedEl){
6246 if(!this.toolTemplate){
6247 var tt = new Ext.Template(
6248 '<div class="x-tool x-tool-{id}"> </div>'
6250 tt.disableFormats = true;
6252 Ext.layout.BorderLayout.Region.prototype.toolTemplate = tt;
6254 this.collapsedEl = this.targetEl.createChild({
6255 cls: "x-layout-collapsed x-layout-collapsed-"+this.position,
6256 id: this.panel.id + '-xcollapsed'
6258 this.collapsedEl.enableDisplayMode('block');
6260 if(this.collapseMode == 'mini'){
6261 this.collapsedEl.addClass('x-layout-cmini-'+this.position);
6262 this.miniCollapsedEl = this.collapsedEl.createChild({
6263 cls: "x-layout-mini x-layout-mini-"+this.position, html: " "
6265 this.miniCollapsedEl.addClassOnOver('x-layout-mini-over');
6266 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
6267 this.collapsedEl.on('click', this.onExpandClick, this, {stopEvent:true});
6269 if(this.collapsible !== false && !this.hideCollapseTool) {
6270 var t = this.toolTemplate.append(
6271 this.collapsedEl.dom,
6272 {id:'expand-'+this.position}, true);
6273 t.addClassOnOver('x-tool-expand-'+this.position+'-over');
6274 t.on('click', this.onExpandClick, this, {stopEvent:true});
6276 if(this.floatable !== false || this.titleCollapse){
6277 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
6278 this.collapsedEl.on("click", this[this.floatable ? 'collapseClick' : 'onExpandClick'], this);
6282 return this.collapsedEl;
6286 onExpandClick : function(e){
6288 this.panel.expand(false);
6290 this.panel.expand();
6295 onCollapseClick : function(e){
6296 this.panel.collapse();
6300 beforeCollapse : function(p, animate){
6301 this.lastAnim = animate;
6303 this.splitEl.hide();
6305 this.getCollapsedEl().show();
6306 var el = this.panel.getEl();
6307 this.originalZIndex = el.getStyle('z-index');
6308 el.setStyle('z-index', 100);
6309 this.isCollapsed = true;
6310 this.layout.layout();
6314 onCollapse : function(animate){
6315 this.panel.el.setStyle('z-index', 1);
6316 if(this.lastAnim === false || this.panel.animCollapse === false){
6317 this.getCollapsedEl().dom.style.visibility = 'visible';
6319 this.getCollapsedEl().slideIn(this.panel.slideAnchor, {duration:.2});
6321 this.state.collapsed = true;
6322 this.panel.saveState();
6326 beforeExpand : function(animate){
6328 this.afterSlideIn();
6330 var c = this.getCollapsedEl();
6332 if(this.position == 'east' || this.position == 'west'){
6333 this.panel.setSize(undefined, c.getHeight());
6335 this.panel.setSize(c.getWidth(), undefined);
6338 c.dom.style.visibility = 'hidden';
6339 this.panel.el.setStyle('z-index', this.floatingZIndex);
6343 onExpand : function(){
6344 this.isCollapsed = false;
6346 this.splitEl.show();
6348 this.layout.layout();
6349 this.panel.el.setStyle('z-index', this.originalZIndex);
6350 this.state.collapsed = false;
6351 this.panel.saveState();
6355 collapseClick : function(e){
6357 e.stopPropagation();
6360 e.stopPropagation();
6366 onHide : function(){
6367 if(this.isCollapsed){
6368 this.getCollapsedEl().hide();
6369 }else if(this.splitEl){
6370 this.splitEl.hide();
6375 onShow : function(){
6376 if(this.isCollapsed){
6377 this.getCollapsedEl().show();
6378 }else if(this.splitEl){
6379 this.splitEl.show();
6384 * True if this region is currently visible, else false.
6387 isVisible : function(){
6388 return !this.panel.hidden;
6392 * Returns the current margins for this region. If the region is collapsed, the
6393 * {@link #cmargins} (collapsed margins) value will be returned, otherwise the
6394 * {@link #margins} value will be returned.
6395 * @return {Object} An object containing the element's margins: <tt>{left: (left
6396 * margin), top: (top margin), right: (right margin), bottom: (bottom margin)}</tt>
6398 getMargins : function(){
6399 return this.isCollapsed && this.cmargins ? this.cmargins : this.margins;
6403 * Returns the current size of this region. If the region is collapsed, the size of the
6404 * collapsedEl will be returned, otherwise the size of the region's panel will be returned.
6405 * @return {Object} An object containing the element's size: <tt>{width: (element width),
6406 * height: (element height)}</tt>
6408 getSize : function(){
6409 return this.isCollapsed ? this.getCollapsedEl().getSize() : this.panel.getSize();
6413 * Sets the specified panel as the container element for this region.
6414 * @param {Ext.Panel} panel The new panel
6416 setPanel : function(panel){
6421 * Returns the minimum allowable width for this region.
6422 * @return {Number} The minimum width
6424 getMinWidth: function(){
6425 return this.minWidth;
6429 * Returns the minimum allowable height for this region.
6430 * @return {Number} The minimum height
6432 getMinHeight: function(){
6433 return this.minHeight;
6437 applyLayoutCollapsed : function(box){
6438 var ce = this.getCollapsedEl();
6439 ce.setLeftTop(box.x, box.y);
6440 ce.setSize(box.width, box.height);
6444 applyLayout : function(box){
6445 if(this.isCollapsed){
6446 this.applyLayoutCollapsed(box);
6448 this.panel.setPosition(box.x, box.y);
6449 this.panel.setSize(box.width, box.height);
6454 beforeSlide: function(){
6455 this.panel.beforeEffect();
6459 afterSlide : function(){
6460 this.panel.afterEffect();
6464 initAutoHide : function(){
6465 if(this.autoHide !== false){
6466 if(!this.autoHideHd){
6467 this.autoHideSlideTask = new Ext.util.DelayedTask(this.slideIn, this);
6469 "mouseout": function(e){
6470 if(!e.within(this.el, true)){
6471 this.autoHideSlideTask.delay(500);
6474 "mouseover" : function(e){
6475 this.autoHideSlideTask.cancel();
6480 this.el.on(this.autoHideHd);
6481 this.collapsedEl.on(this.autoHideHd);
6486 clearAutoHide : function(){
6487 if(this.autoHide !== false){
6488 this.el.un("mouseout", this.autoHideHd.mouseout);
6489 this.el.un("mouseover", this.autoHideHd.mouseover);
6490 this.collapsedEl.un("mouseout", this.autoHideHd.mouseout);
6491 this.collapsedEl.un("mouseover", this.autoHideHd.mouseover);
6496 clearMonitor : function(){
6497 Ext.getDoc().un("click", this.slideInIf, this);
6501 * If this Region is {@link #floatable}, this method slides this Region into full visibility <i>over the top
6502 * of the center Region</i> where it floats until either {@link #slideIn} is called, or other regions of the layout
6503 * are clicked, or the mouse exits the Region.
6505 slideOut : function(){
6506 if(this.isSlid || this.el.hasActiveFx()){
6510 var ts = this.panel.tools, dh, pc;
6511 if(ts && ts.toggle){
6516 // Temporarily clear the collapsed flag so we can onResize the panel on the slide
6517 pc = this.panel.collapsed;
6518 this.panel.collapsed = false;
6520 if(this.position == 'east' || this.position == 'west'){
6521 // Temporarily clear the deferHeight flag so we can size the height on the slide
6522 dh = this.panel.deferHeight;
6523 this.panel.deferHeight = false;
6525 this.panel.setSize(undefined, this.collapsedEl.getHeight());
6527 // Put the deferHeight flag back after setSize
6528 this.panel.deferHeight = dh;
6530 this.panel.setSize(this.collapsedEl.getWidth(), undefined);
6533 // Put the collapsed flag back after onResize
6534 this.panel.collapsed = pc;
6536 this.restoreLT = [this.el.dom.style.left, this.el.dom.style.top];
6537 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
6538 this.el.setStyle("z-index", this.floatingZIndex+2);
6539 this.panel.el.replaceClass('x-panel-collapsed', 'x-panel-floating');
6540 if(this.animFloat !== false){
6542 this.el.slideIn(this.getSlideAnchor(), {
6543 callback: function(){
6545 this.initAutoHide();
6546 Ext.getDoc().on("click", this.slideInIf, this);
6552 this.initAutoHide();
6553 Ext.getDoc().on("click", this.slideInIf, this);
6558 afterSlideIn : function(){
6559 this.clearAutoHide();
6560 this.isSlid = false;
6561 this.clearMonitor();
6562 this.el.setStyle("z-index", "");
6563 this.panel.el.replaceClass('x-panel-floating', 'x-panel-collapsed');
6564 this.el.dom.style.left = this.restoreLT[0];
6565 this.el.dom.style.top = this.restoreLT[1];
6567 var ts = this.panel.tools;
6568 if(ts && ts.toggle){
6574 * If this Region is {@link #floatable}, and this Region has been slid into floating visibility, then this method slides
6575 * this region back into its collapsed state.
6577 slideIn : function(cb){
6578 if(!this.isSlid || this.el.hasActiveFx()){
6582 this.isSlid = false;
6583 if(this.animFloat !== false){
6585 this.el.slideOut(this.getSlideAnchor(), {
6586 callback: function(){
6589 this.afterSlideIn();
6597 this.afterSlideIn();
6602 slideInIf : function(e){
6603 if(!e.within(this.el)){
6633 getAnchor : function(){
6634 return this.anchors[this.position];
6638 getCollapseAnchor : function(){
6639 return this.canchors[this.position];
6643 getSlideAnchor : function(){
6644 return this.sanchors[this.position];
6648 getAlignAdj : function(){
6649 var cm = this.cmargins;
6650 switch(this.position){
6667 getExpandAdj : function(){
6668 var c = this.collapsedEl, cm = this.cmargins;
6669 switch(this.position){
6671 return [-(cm.right+c.getWidth()+cm.left), 0];
6674 return [cm.right+c.getWidth()+cm.left, 0];
6677 return [0, -(cm.top+cm.bottom+c.getHeight())];
6680 return [0, cm.top+cm.bottom+c.getHeight()];
6685 destroy : function(){
6686 if (this.autoHideSlideTask && this.autoHideSlideTask.cancel){
6687 this.autoHideSlideTask.cancel();
6689 Ext.destroy(this.miniCollapsedEl, this.collapsedEl);
6694 * @class Ext.layout.BorderLayout.SplitRegion
6695 * @extends Ext.layout.BorderLayout.Region
6696 * <p>This is a specialized type of {@link Ext.layout.BorderLayout.Region BorderLayout region} that
6697 * has a built-in {@link Ext.SplitBar} for user resizing of regions. The movement of the split bar
6698 * is configurable to move either {@link #tickSize smooth or incrementally}.</p>
6700 * Create a new SplitRegion.
6701 * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region.
6702 * @param {Object} config The configuration options
6703 * @param {String} position The region position. Valid values are: north, south, east, west and center. Every
6704 * BorderLayout must have a center region for the primary content -- all other regions are optional.
6706 Ext.layout.BorderLayout.SplitRegion = function(layout, config, pos){
6707 Ext.layout.BorderLayout.SplitRegion.superclass.constructor.call(this, layout, config, pos);
6709 this.applyLayout = this.applyFns[pos];
6712 Ext.extend(Ext.layout.BorderLayout.SplitRegion, Ext.layout.BorderLayout.Region, {
6714 * @cfg {Number} tickSize
6715 * The increment, in pixels by which to move this Region's {@link Ext.SplitBar SplitBar}.
6716 * By default, the {@link Ext.SplitBar SplitBar} moves smoothly.
6719 * @cfg {String} splitTip
6720 * The tooltip to display when the user hovers over a
6721 * {@link Ext.layout.BorderLayout.Region#collapsible non-collapsible} region's split bar
6722 * (defaults to <tt>"Drag to resize."</tt>). Only applies if
6723 * <tt>{@link #useSplitTips} = true</tt>.
6725 splitTip : "Drag to resize.",
6727 * @cfg {String} collapsibleSplitTip
6728 * The tooltip to display when the user hovers over a
6729 * {@link Ext.layout.BorderLayout.Region#collapsible collapsible} region's split bar
6730 * (defaults to "Drag to resize. Double click to hide."). Only applies if
6731 * <tt>{@link #useSplitTips} = true</tt>.
6733 collapsibleSplitTip : "Drag to resize. Double click to hide.",
6735 * @cfg {Boolean} useSplitTips
6736 * <tt>true</tt> to display a tooltip when the user hovers over a region's split bar
6737 * (defaults to <tt>false</tt>). The tooltip text will be the value of either
6738 * <tt>{@link #splitTip}</tt> or <tt>{@link #collapsibleSplitTip}</tt> as appropriate.
6740 useSplitTips : false,
6745 orientation: Ext.SplitBar.VERTICAL,
6746 placement: Ext.SplitBar.TOP,
6747 maxFn : 'getVMaxSize',
6748 minProp: 'minHeight',
6749 maxProp: 'maxHeight'
6752 orientation: Ext.SplitBar.VERTICAL,
6753 placement: Ext.SplitBar.BOTTOM,
6754 maxFn : 'getVMaxSize',
6755 minProp: 'minHeight',
6756 maxProp: 'maxHeight'
6759 orientation: Ext.SplitBar.HORIZONTAL,
6760 placement: Ext.SplitBar.RIGHT,
6761 maxFn : 'getHMaxSize',
6762 minProp: 'minWidth',
6766 orientation: Ext.SplitBar.HORIZONTAL,
6767 placement: Ext.SplitBar.LEFT,
6768 maxFn : 'getHMaxSize',
6769 minProp: 'minWidth',
6776 west : function(box){
6777 if(this.isCollapsed){
6778 return this.applyLayoutCollapsed(box);
6780 var sd = this.splitEl.dom, s = sd.style;
6781 this.panel.setPosition(box.x, box.y);
6782 var sw = sd.offsetWidth;
6783 s.left = (box.x+box.width-sw)+'px';
6784 s.top = (box.y)+'px';
6785 s.height = Math.max(0, box.height)+'px';
6786 this.panel.setSize(box.width-sw, box.height);
6788 east : function(box){
6789 if(this.isCollapsed){
6790 return this.applyLayoutCollapsed(box);
6792 var sd = this.splitEl.dom, s = sd.style;
6793 var sw = sd.offsetWidth;
6794 this.panel.setPosition(box.x+sw, box.y);
6795 s.left = (box.x)+'px';
6796 s.top = (box.y)+'px';
6797 s.height = Math.max(0, box.height)+'px';
6798 this.panel.setSize(box.width-sw, box.height);
6800 north : function(box){
6801 if(this.isCollapsed){
6802 return this.applyLayoutCollapsed(box);
6804 var sd = this.splitEl.dom, s = sd.style;
6805 var sh = sd.offsetHeight;
6806 this.panel.setPosition(box.x, box.y);
6807 s.left = (box.x)+'px';
6808 s.top = (box.y+box.height-sh)+'px';
6809 s.width = Math.max(0, box.width)+'px';
6810 this.panel.setSize(box.width, box.height-sh);
6812 south : function(box){
6813 if(this.isCollapsed){
6814 return this.applyLayoutCollapsed(box);
6816 var sd = this.splitEl.dom, s = sd.style;
6817 var sh = sd.offsetHeight;
6818 this.panel.setPosition(box.x, box.y+sh);
6819 s.left = (box.x)+'px';
6820 s.top = (box.y)+'px';
6821 s.width = Math.max(0, box.width)+'px';
6822 this.panel.setSize(box.width, box.height-sh);
6827 render : function(ct, p){
6828 Ext.layout.BorderLayout.SplitRegion.superclass.render.call(this, ct, p);
6830 var ps = this.position;
6832 this.splitEl = ct.createChild({
6833 cls: "x-layout-split x-layout-split-"+ps, html: " ",
6834 id: this.panel.id + '-xsplit'
6837 if(this.collapseMode == 'mini'){
6838 this.miniSplitEl = this.splitEl.createChild({
6839 cls: "x-layout-mini x-layout-mini-"+ps, html: " "
6841 this.miniSplitEl.addClassOnOver('x-layout-mini-over');
6842 this.miniSplitEl.on('click', this.onCollapseClick, this, {stopEvent:true});
6845 var s = this.splitSettings[ps];
6847 this.split = new Ext.SplitBar(this.splitEl.dom, p.el, s.orientation);
6848 this.split.tickSize = this.tickSize;
6849 this.split.placement = s.placement;
6850 this.split.getMaximumSize = this[s.maxFn].createDelegate(this);
6851 this.split.minSize = this.minSize || this[s.minProp];
6852 this.split.on("beforeapply", this.onSplitMove, this);
6853 this.split.useShim = this.useShim === true;
6854 this.maxSize = this.maxSize || this[s.maxProp];
6857 this.splitEl.hide();
6860 if(this.useSplitTips){
6861 this.splitEl.dom.title = this.collapsible ? this.collapsibleSplitTip : this.splitTip;
6863 if(this.collapsible){
6864 this.splitEl.on("dblclick", this.onCollapseClick, this);
6868 //docs inherit from superclass
6869 getSize : function(){
6870 if(this.isCollapsed){
6871 return this.collapsedEl.getSize();
6873 var s = this.panel.getSize();
6874 if(this.position == 'north' || this.position == 'south'){
6875 s.height += this.splitEl.dom.offsetHeight;
6877 s.width += this.splitEl.dom.offsetWidth;
6883 getHMaxSize : function(){
6884 var cmax = this.maxSize || 10000;
6885 var center = this.layout.center;
6886 return Math.min(cmax, (this.el.getWidth()+center.el.getWidth())-center.getMinWidth());
6890 getVMaxSize : function(){
6891 var cmax = this.maxSize || 10000;
6892 var center = this.layout.center;
6893 return Math.min(cmax, (this.el.getHeight()+center.el.getHeight())-center.getMinHeight());
6897 onSplitMove : function(split, newSize){
6898 var s = this.panel.getSize();
6899 this.lastSplitSize = newSize;
6900 if(this.position == 'north' || this.position == 'south'){
6901 this.panel.setSize(s.width, newSize);
6902 this.state.height = newSize;
6904 this.panel.setSize(newSize, s.height);
6905 this.state.width = newSize;
6907 this.layout.layout();
6908 this.panel.saveState();
6913 * Returns a reference to the split bar in use by this region.
6914 * @return {Ext.SplitBar} The split bar
6916 getSplitBar : function(){
6921 destroy : function() {
6922 Ext.destroy(this.miniSplitEl, this.split, this.splitEl);
6923 Ext.layout.BorderLayout.SplitRegion.superclass.destroy.call(this);
6927 Ext.Container.LAYOUTS['border'] = Ext.layout.BorderLayout;/**
6928 * @class Ext.layout.FormLayout
6929 * @extends Ext.layout.AnchorLayout
6930 * <p>This layout manager is specifically designed for rendering and managing child Components of
6931 * {@link Ext.form.FormPanel forms}. It is responsible for rendering the labels of
6932 * {@link Ext.form.Field Field}s.</p>
6934 * <p>This layout manager is used when a Container is configured with the <tt>layout:'form'</tt>
6935 * {@link Ext.Container#layout layout} config option, and should generally not need to be created directly
6936 * via the new keyword. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
6938 * <p>In an application, it will usually be preferrable to use a {@link Ext.form.FormPanel FormPanel}
6939 * (which is configured with FormLayout as its layout class by default) since it also provides built-in
6940 * functionality for {@link Ext.form.BasicForm#doAction loading, validating and submitting} the form.</p>
6942 * <p>A {@link Ext.Container Container} <i>using</i> the FormLayout layout manager (e.g.
6943 * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>) can also accept the following
6944 * layout-specific config properties:<div class="mdetail-params"><ul>
6945 * <li><b><tt>{@link Ext.form.FormPanel#hideLabels hideLabels}</tt></b></li>
6946 * <li><b><tt>{@link Ext.form.FormPanel#labelAlign labelAlign}</tt></b></li>
6947 * <li><b><tt>{@link Ext.form.FormPanel#labelPad labelPad}</tt></b></li>
6948 * <li><b><tt>{@link Ext.form.FormPanel#labelSeparator labelSeparator}</tt></b></li>
6949 * <li><b><tt>{@link Ext.form.FormPanel#labelWidth labelWidth}</tt></b></li>
6952 * <p>Any Component (including Fields) managed by FormLayout accepts the following as a config option:
6953 * <div class="mdetail-params"><ul>
6954 * <li><b><tt>{@link Ext.Component#anchor anchor}</tt></b></li>
6957 * <p>Any Component managed by FormLayout may be rendered as a form field (with an associated label) by
6958 * configuring it with a non-null <b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b>. Components configured
6959 * in this way may be configured with the following options which affect the way the FormLayout renders them:
6960 * <div class="mdetail-params"><ul>
6961 * <li><b><tt>{@link Ext.Component#clearCls clearCls}</tt></b></li>
6962 * <li><b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b></li>
6963 * <li><b><tt>{@link Ext.Component#hideLabel hideLabel}</tt></b></li>
6964 * <li><b><tt>{@link Ext.Component#itemCls itemCls}</tt></b></li>
6965 * <li><b><tt>{@link Ext.Component#labelSeparator labelSeparator}</tt></b></li>
6966 * <li><b><tt>{@link Ext.Component#labelStyle labelStyle}</tt></b></li>
6969 * <p>Example usage:</p>
6971 // Required if showing validation messages
6972 Ext.QuickTips.init();
6974 // While you can create a basic Panel with layout:'form', practically
6975 // you should usually use a FormPanel to also get its form functionality
6976 // since it already creates a FormLayout internally.
6977 var form = new Ext.form.FormPanel({
6978 title: 'Form Layout',
6979 bodyStyle: 'padding:15px',
6981 defaultType: 'textfield',
6983 // applied to each contained item
6988 fieldLabel: 'First Name',
6991 {@link Ext.Component#labelSeparator labelSeparator}: ':' // override labelSeparator layout config
6993 fieldLabel: 'Last Name',
6996 fieldLabel: 'Email',
7001 hideLabel: true, // override hideLabels layout config
7011 {@link #labelSeparator}: '~' // superseded by assignment below
7013 // config options applicable to container when layout='form':
7015 labelAlign: 'left', // or 'right' or 'top'
7016 {@link Ext.form.FormPanel#labelSeparator labelSeparator}: '>>', // takes precedence over layoutConfig value
7017 labelWidth: 65, // defaults to 100
7018 labelPad: 8 // defaults to 5, must specify labelWidth to be honored
7022 Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, {
7025 * @cfg {String} labelSeparator
7026 * See {@link Ext.form.FormPanel}.{@link Ext.form.FormPanel#labelSeparator labelSeparator}. Configuration
7027 * of this property at the <b>container</b> level takes precedence.
7029 labelSeparator : ':',
7032 * Read only. The CSS style specification string added to field labels in this layout if not
7033 * otherwise {@link Ext.Component#labelStyle specified by each contained field}.
7035 * @property labelStyle
7039 * @cfg {Boolean} trackLabels
7040 * True to show/hide the field label when the field is hidden. Defaults to <tt>false</tt>.
7046 onRemove: function(c){
7047 Ext.layout.FormLayout.superclass.onRemove.call(this, c);
7048 if(this.trackLabels){
7049 c.un('show', this.onFieldShow, this);
7050 c.un('hide', this.onFieldHide, this);
7052 // check for itemCt, since we may be removing a fieldset or something similar
7053 var el = c.getPositionEl(),
7054 ct = c.getItemCt && c.getItemCt();
7055 if (c.rendered && ct) {
7060 Ext.destroyMembers(c, 'label', 'itemCt');
7061 if (c.customItemCt) {
7062 Ext.destroyMembers(c, 'getItemCt', 'customItemCt');
7068 setContainer : function(ct){
7069 Ext.layout.FormLayout.superclass.setContainer.call(this, ct);
7071 ct.addClass('x-form-label-'+ct.labelAlign);
7076 labelStyle: 'display:none',
7077 elementStyle: 'padding-left:0;',
7081 this.labelSeparator = ct.labelSeparator || this.labelSeparator;
7082 ct.labelWidth = ct.labelWidth || 100;
7083 if(Ext.isNumber(ct.labelWidth)){
7084 var pad = Ext.isNumber(ct.labelPad) ? ct.labelPad : 5;
7086 labelAdjust: ct.labelWidth + pad,
7087 labelStyle: 'width:' + ct.labelWidth + 'px;',
7088 elementStyle: 'padding-left:' + (ct.labelWidth + pad) + 'px'
7091 if(ct.labelAlign == 'top'){
7093 labelStyle: 'width:auto;',
7095 elementStyle: 'padding-left:0;'
7102 isHide: function(c){
7103 return c.hideLabel || this.container.hideLabels;
7106 onFieldShow: function(c){
7107 c.getItemCt().removeClass('x-hide-' + c.hideMode);
7109 // Composite fields will need to layout after the container is made visible
7110 if (c.isComposite) {
7115 onFieldHide: function(c){
7116 c.getItemCt().addClass('x-hide-' + c.hideMode);
7120 getLabelStyle: function(s){
7121 var ls = '', items = [this.labelStyle, s];
7122 for (var i = 0, len = items.length; i < len; ++i){
7125 if (ls.substr(-1, 1) != ';'){
7134 * @cfg {Ext.Template} fieldTpl
7135 * A {@link Ext.Template#compile compile}d {@link Ext.Template} for rendering
7136 * the fully wrapped, labeled and styled form Field. Defaults to:</p><pre><code>
7138 '<div class="x-form-item {itemCls}" tabIndex="-1">',
7139 '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{labelSeparator}</label>',
7140 '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
7141 '</div><div class="{clearCls}"></div>',
7145 * <p>This may be specified to produce a different DOM structure when rendering form Fields.</p>
7146 * <p>A description of the properties within the template follows:</p><div class="mdetail-params"><ul>
7147 * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper
7148 * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt>
7149 * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt>
7150 * supplied at the container level.</div></li>
7151 * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li>
7152 * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc">
7153 * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the
7154 * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li>
7155 * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this
7156 * field (defaults to <tt>''</tt>)</div></li>
7157 * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after
7158 * the text of the label for this field (defaults to a colon <tt>':'</tt> or the
7159 * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li>
7160 * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li>
7161 * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div
7162 * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li>
7164 * <p>Also see <tt>{@link #getTemplateArgs}</tt></p>
7171 renderItem : function(c, position, target){
7172 if(c && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){
7173 var args = this.getTemplateArgs(c);
7174 if(Ext.isNumber(position)){
7175 position = target.dom.childNodes[position] || null;
7178 c.itemCt = this.fieldTpl.insertBefore(position, args, true);
7180 c.itemCt = this.fieldTpl.append(target, args, true);
7183 // Non form fields don't have getItemCt, apply it here
7184 // This will get cleaned up in onRemove
7186 getItemCt: function(){
7192 c.label = c.getItemCt().child('label.x-form-item-label');
7194 c.render('x-form-el-' + c.id);
7195 }else if(!this.isValidParent(c, target)){
7196 Ext.fly('x-form-el-' + c.id).appendChild(c.getPositionEl());
7198 if(this.trackLabels){
7200 this.onFieldHide(c);
7204 show: this.onFieldShow,
7205 hide: this.onFieldHide
7208 this.configureItem(c);
7210 Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments);
7215 * <p>Provides template arguments for rendering the fully wrapped, labeled and styled form Field.</p>
7216 * <p>This method returns an object hash containing properties used by the layout's {@link #fieldTpl}
7217 * to create a correctly wrapped, labeled and styled form Field. This may be overriden to
7218 * create custom layouts. The properties which must be returned are:</p><div class="mdetail-params"><ul>
7219 * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper
7220 * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt>
7221 * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt>
7222 * supplied at the container level.</div></li>
7223 * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li>
7224 * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc">
7225 * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the
7226 * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li>
7227 * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this
7228 * field (defaults to the field's configured fieldLabel property)</div></li>
7229 * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after
7230 * the text of the label for this field (defaults to a colon <tt>':'</tt> or the
7231 * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li>
7232 * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li>
7233 * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div
7234 * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li>
7236 * @param (Ext.form.Field} field The {@link Ext.form.Field Field} being rendered.
7237 * @return {Object} An object hash containing the properties required to render the Field.
7239 getTemplateArgs: function(field) {
7240 var noLabelSep = !field.fieldLabel || field.hideLabel;
7244 label : field.fieldLabel,
7245 itemCls : (field.itemCls || this.container.itemCls || '') + (field.hideLabel ? ' x-hide-label' : ''),
7246 clearCls : field.clearCls || 'x-form-clear-left',
7247 labelStyle : this.getLabelStyle(field.labelStyle),
7248 elementStyle : this.elementStyle || '',
7249 labelSeparator: noLabelSep ? '' : (Ext.isDefined(field.labelSeparator) ? field.labelSeparator : this.labelSeparator)
7254 adjustWidthAnchor: function(value, c){
7255 if(c.label && !this.isHide(c) && (this.container.labelAlign != 'top')){
7256 var adjust = Ext.isIE6 || (Ext.isIE && !Ext.isStrict);
7257 return value - this.labelAdjust + (adjust ? -3 : 0);
7262 adjustHeightAnchor : function(value, c){
7263 if(c.label && !this.isHide(c) && (this.container.labelAlign == 'top')){
7264 return value - c.label.getHeight();
7270 isValidParent : function(c, target){
7271 return target && this.container.getEl().contains(c.getPositionEl());
7275 * @property activeItem
7280 Ext.Container.LAYOUTS['form'] = Ext.layout.FormLayout;
7282 * @class Ext.layout.AccordionLayout
7283 * @extends Ext.layout.FitLayout
7284 * <p>This is a layout that manages multiple Panels in an expandable accordion style such that only
7285 * <b>one Panel can be expanded at any given time</b>. Each Panel has built-in support for expanding and collapsing.</p>
7286 * <p>Note: Only Ext.Panels <b>and all subclasses of Ext.Panel</b> may be used in an accordion layout Container.</p>
7287 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
7288 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
7289 * <p>Example usage:</p>
7291 var accordion = new Ext.Panel({
7292 title: 'Accordion Layout',
7295 // applied to each contained panel
7296 bodyStyle: 'padding:15px'
7299 // layout-specific configs go here
7300 titleCollapse: false,
7306 html: '<p>Panel content!</p>'
7309 html: '<p>Panel content!</p>'
7312 html: '<p>Panel content!</p>'
7317 Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, {
7319 * @cfg {Boolean} fill
7320 * True to adjust the active item's height to fill the available space in the container, false to use the
7321 * item's current height, or auto height if not explicitly set (defaults to true).
7325 * @cfg {Boolean} autoWidth
7326 * True to set each contained item's width to 'auto', false to use the item's current width (defaults to true).
7327 * Note that some components, in particular the {@link Ext.grid.GridPanel grid}, will not function properly within
7328 * layouts if they have auto width, so in such cases this config should be set to false.
7332 * @cfg {Boolean} titleCollapse
7333 * True to allow expand/collapse of each contained panel by clicking anywhere on the title bar, false to allow
7334 * expand/collapse only when the toggle tool button is clicked (defaults to true). When set to false,
7335 * {@link #hideCollapseTool} should be false also.
7337 titleCollapse : true,
7339 * @cfg {Boolean} hideCollapseTool
7340 * True to hide the contained panels' collapse/expand toggle buttons, false to display them (defaults to false).
7341 * When set to true, {@link #titleCollapse} should be true also.
7343 hideCollapseTool : false,
7345 * @cfg {Boolean} collapseFirst
7346 * True to make sure the collapse/expand toggle button always renders first (to the left of) any other tools
7347 * in the contained panels' title bars, false to render it last (defaults to false).
7349 collapseFirst : false,
7351 * @cfg {Boolean} animate
7352 * True to slide the contained panels open and closed during expand/collapse using animation, false to open and
7353 * close directly with no animation (defaults to false). Note: to defer to the specific config setting of each
7354 * contained panel for this property, set this to undefined at the layout level.
7358 * @cfg {Boolean} sequence
7359 * <b>Experimental</b>. If animate is set to true, this will result in each animation running in sequence.
7363 * @cfg {Boolean} activeOnTop
7364 * True to swap the position of each panel as it is expanded so that it becomes the first item in the container,
7365 * false to keep the panels in the rendered order. <b>This is NOT compatible with "animate:true"</b> (defaults to false).
7367 activeOnTop : false,
7371 renderItem : function(c){
7372 if(this.animate === false){
7373 c.animCollapse = false;
7375 c.collapsible = true;
7379 if(this.titleCollapse){
7380 c.titleCollapse = true;
7382 if(this.hideCollapseTool){
7383 c.hideCollapseTool = true;
7385 if(this.collapseFirst !== undefined){
7386 c.collapseFirst = this.collapseFirst;
7388 if(!this.activeItem && !c.collapsed){
7389 this.setActiveItem(c, true);
7390 }else if(this.activeItem && this.activeItem != c){
7393 Ext.layout.AccordionLayout.superclass.renderItem.apply(this, arguments);
7394 c.header.addClass('x-accordion-hd');
7395 c.on('beforeexpand', this.beforeExpand, this);
7398 onRemove: function(c){
7399 Ext.layout.AccordionLayout.superclass.onRemove.call(this, c);
7401 c.header.removeClass('x-accordion-hd');
7403 c.un('beforeexpand', this.beforeExpand, this);
7407 beforeExpand : function(p, anim){
7408 var ai = this.activeItem;
7411 delete this.activeItem;
7413 ai.collapse({callback:function(){
7414 p.expand(anim || true);
7419 ai.collapse(this.animate);
7423 if(this.activeOnTop){
7424 p.el.dom.parentNode.insertBefore(p.el.dom, p.el.dom.parentNode.firstChild);
7426 // Items have been hidden an possibly rearranged, we need to get the container size again.
7431 setItemSize : function(item, size){
7432 if(this.fill && item){
7433 var hh = 0, i, ct = this.getRenderedItems(this.container), len = ct.length, p;
7434 // Add up all the header heights
7435 for (i = 0; i < len; i++) {
7436 if((p = ct[i]) != item && !p.hidden){
7437 hh += p.header.getHeight();
7440 // Subtract the header heights from the container size
7442 // Call setSize on the container to set the correct height. For Panels, deferedHeight
7443 // will simply store this size for when the expansion is done.
7449 * Sets the active (expanded) item in the layout.
7450 * @param {String/Number} item The string component id or numeric index of the item to activate
7452 setActiveItem : function(item){
7453 this.setActive(item, true);
7457 setActive : function(item, expand){
7458 var ai = this.activeItem;
7459 item = this.container.getComponent(item);
7461 if(item.rendered && item.collapsed && expand){
7465 ai.fireEvent('deactivate', ai);
7467 this.activeItem = item;
7468 item.fireEvent('activate', item);
7473 Ext.Container.LAYOUTS.accordion = Ext.layout.AccordionLayout;
7476 Ext.layout.Accordion = Ext.layout.AccordionLayout;/**
7477 * @class Ext.layout.TableLayout
7478 * @extends Ext.layout.ContainerLayout
7479 * <p>This layout allows you to easily render content into an HTML table. The total number of columns can be
7480 * specified, and rowspan and colspan can be used to create complex layouts within the table.
7481 * This class is intended to be extended or created via the layout:'table' {@link Ext.Container#layout} config,
7482 * and should generally not need to be created directly via the new keyword.</p>
7483 * <p>Note that when creating a layout via config, the layout-specific config properties must be passed in via
7484 * the {@link Ext.Container#layoutConfig} object which will then be applied internally to the layout. In the
7485 * case of TableLayout, the only valid layout config property is {@link #columns}. However, the items added to a
7486 * TableLayout can supply the following table-specific config properties:</p>
7488 * <li><b>rowspan</b> Applied to the table cell containing the item.</li>
7489 * <li><b>colspan</b> Applied to the table cell containing the item.</li>
7490 * <li><b>cellId</b> An id applied to the table cell containing the item.</li>
7491 * <li><b>cellCls</b> A CSS class name added to the table cell containing the item.</li>
7493 * <p>The basic concept of building up a TableLayout is conceptually very similar to building up a standard
7494 * HTML table. You simply add each panel (or "cell") that you want to include along with any span attributes
7495 * specified as the special config properties of rowspan and colspan which work exactly like their HTML counterparts.
7496 * Rather than explicitly creating and nesting rows and columns as you would in HTML, you simply specify the
7497 * total column count in the layoutConfig and start adding panels in their natural order from left to right,
7498 * top to bottom. The layout will automatically figure out, based on the column count, rowspans and colspans,
7499 * how to position each panel within the table. Just like with HTML tables, your rowspans and colspans must add
7500 * up correctly in your overall layout or you'll end up with missing and/or extra cells! Example usage:</p>
7502 // This code will generate a layout table that is 3 columns by 2 rows
7503 // with some spanning included. The basic layout will be:
7504 // +--------+-----------------+
7506 // | |--------+--------|
7508 // +--------+--------+--------+
7509 var table = new Ext.Panel({
7510 title: 'Table Layout',
7513 // applied to each contained panel
7514 bodyStyle:'padding:20px'
7517 // The total column count must be specified here
7521 html: '<p>Cell A content</p>',
7524 html: '<p>Cell B content</p>',
7527 html: '<p>Cell C content</p>',
7528 cellCls: 'highlight'
7530 html: '<p>Cell D content</p>'
7535 Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, {
7537 * @cfg {Number} columns
7538 * The total number of columns to create in the table for this layout. If not specified, all Components added to
7539 * this layout will be rendered into a single row using one column per Component.
7543 monitorResize:false,
7547 targetCls: 'x-table-layout-ct',
7550 * @cfg {Object} tableAttrs
7551 * <p>An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification
7552 * used to create the layout's <tt><table></tt> element. Example:</p><pre><code>
7569 setContainer : function(ct){
7570 Ext.layout.TableLayout.superclass.setContainer.call(this, ct);
7572 this.currentRow = 0;
7573 this.currentColumn = 0;
7578 onLayout : function(ct, target){
7579 var cs = ct.items.items, len = cs.length, c, i;
7582 target.addClass('x-table-layout-ct');
7584 this.table = target.createChild(
7585 Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true);
7587 this.renderAll(ct, target);
7591 getRow : function(index){
7592 var row = this.table.tBodies[0].childNodes[index];
7594 row = document.createElement('tr');
7595 this.table.tBodies[0].appendChild(row);
7601 getNextCell : function(c){
7602 var cell = this.getNextNonSpan(this.currentColumn, this.currentRow);
7603 var curCol = this.currentColumn = cell[0], curRow = this.currentRow = cell[1];
7604 for(var rowIndex = curRow; rowIndex < curRow + (c.rowspan || 1); rowIndex++){
7605 if(!this.cells[rowIndex]){
7606 this.cells[rowIndex] = [];
7608 for(var colIndex = curCol; colIndex < curCol + (c.colspan || 1); colIndex++){
7609 this.cells[rowIndex][colIndex] = true;
7612 var td = document.createElement('td');
7616 var cls = 'x-table-layout-cell';
7618 cls += ' ' + c.cellCls;
7622 td.colSpan = c.colspan;
7625 td.rowSpan = c.rowspan;
7627 this.getRow(curRow).appendChild(td);
7632 getNextNonSpan: function(colIndex, rowIndex){
7633 var cols = this.columns;
7634 while((cols && colIndex >= cols) || (this.cells[rowIndex] && this.cells[rowIndex][colIndex])) {
7635 if(cols && colIndex >= cols){
7642 return [colIndex, rowIndex];
7646 renderItem : function(c, position, target){
7647 // Ensure we have our inner table to get cells to render into.
7649 this.table = target.createChild(
7650 Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true);
7652 if(c && !c.rendered){
7653 c.render(this.getNextCell(c));
7654 this.configureItem(c, position);
7655 }else if(c && !this.isValidParent(c, target)){
7656 var container = this.getNextCell(c);
7657 container.insertBefore(c.getPositionEl().dom, null);
7658 c.container = Ext.get(container);
7659 this.configureItem(c, position);
7664 isValidParent : function(c, target){
7665 return c.getPositionEl().up('table', 5).dom.parentNode === (target.dom || target);
7669 * @property activeItem
7674 Ext.Container.LAYOUTS['table'] = Ext.layout.TableLayout;/**
7675 * @class Ext.layout.AbsoluteLayout
7676 * @extends Ext.layout.AnchorLayout
7677 * <p>This is a layout that inherits the anchoring of <b>{@link Ext.layout.AnchorLayout}</b> and adds the
7678 * ability for x/y positioning using the standard x and y component config options.</p>
7679 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
7680 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
7681 * <p>Example usage:</p>
7683 var form = new Ext.form.FormPanel({
7684 title: 'Absolute Layout',
7687 // layout-specific configs go here
7688 extraCls: 'x-abs-layout-item',
7691 url:'save-form.php',
7692 defaultType: 'textfield',
7702 anchor:'100%' // anchor width by percentage
7712 anchor: '100%' // anchor width by percentage
7718 anchor: '100% 100%' // anchor width and height
7723 Ext.layout.AbsoluteLayout = Ext.extend(Ext.layout.AnchorLayout, {
7725 extraCls: 'x-abs-layout-item',
7729 onLayout : function(ct, target){
7731 this.paddingLeft = target.getPadding('l');
7732 this.paddingTop = target.getPadding('t');
7733 Ext.layout.AbsoluteLayout.superclass.onLayout.call(this, ct, target);
7737 adjustWidthAnchor : function(value, comp){
7738 return value ? value - comp.getPosition(true)[0] + this.paddingLeft : value;
7742 adjustHeightAnchor : function(value, comp){
7743 return value ? value - comp.getPosition(true)[1] + this.paddingTop : value;
7746 * @property activeItem
7750 Ext.Container.LAYOUTS['absolute'] = Ext.layout.AbsoluteLayout;
7752 * @class Ext.layout.BoxLayout
7753 * @extends Ext.layout.ContainerLayout
7754 * <p>Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.</p>
7756 Ext.layout.BoxLayout = Ext.extend(Ext.layout.ContainerLayout, {
7758 * @cfg {Object} defaultMargins
7759 * <p>If the individual contained items do not have a <tt>margins</tt>
7760 * property specified, the default margins from this property will be
7761 * applied to each item.</p>
7762 * <br><p>This property may be specified as an object containing margins
7763 * to apply in the format:</p><pre><code>
7766 right: (right margin),
7767 bottom: (bottom margin),
7770 * <p>This property may also be specified as a string containing
7771 * space-separated, numeric margin values. The order of the sides associated
7772 * with each value matches the way CSS processes margin values:</p>
7773 * <div class="mdetail-params"><ul>
7774 * <li>If there is only one value, it applies to all sides.</li>
7775 * <li>If there are two values, the top and bottom borders are set to the
7776 * first value and the right and left are set to the second.</li>
7777 * <li>If there are three values, the top is set to the first value, the left
7778 * and right are set to the second, and the bottom is set to the third.</li>
7779 * <li>If there are four values, they apply to the top, right, bottom, and
7780 * left, respectively.</li>
7782 * <p>Defaults to:</p><pre><code>
7783 * {top:0, right:0, bottom:0, left:0}
7786 defaultMargins : {left:0,top:0,right:0,bottom:0},
7788 * @cfg {String} padding
7789 * <p>Sets the padding to be applied to all child items managed by this layout.</p>
7790 * <p>This property must be specified as a string containing
7791 * space-separated, numeric padding values. The order of the sides associated
7792 * with each value matches the way CSS processes padding values:</p>
7793 * <div class="mdetail-params"><ul>
7794 * <li>If there is only one value, it applies to all sides.</li>
7795 * <li>If there are two values, the top and bottom borders are set to the
7796 * first value and the right and left are set to the second.</li>
7797 * <li>If there are three values, the top is set to the first value, the left
7798 * and right are set to the second, and the bottom is set to the third.</li>
7799 * <li>If there are four values, they apply to the top, right, bottom, and
7800 * left, respectively.</li>
7802 * <p>Defaults to: <code>"0"</code></p>
7805 // documented in subclasses
7809 monitorResize : true,
7812 extraCls : 'x-box-item',
7813 targetCls : 'x-box-layout-ct',
7814 innerCls : 'x-box-inner',
7816 constructor : function(config){
7817 Ext.layout.BoxLayout.superclass.constructor.call(this, config);
7819 if (Ext.isString(this.defaultMargins)) {
7820 this.defaultMargins = this.parseMargins(this.defaultMargins);
7826 * Runs the child box calculations and caches them in childBoxCache. Subclasses can used these cached values
7829 onLayout: function(container, target) {
7830 Ext.layout.BoxLayout.superclass.onLayout.call(this, container, target);
7832 var items = this.getVisibleItems(container),
7833 tSize = this.getLayoutTargetSize();
7837 * @property layoutTargetLastSize
7839 * Private cache of the last measured size of the layout target. This should never be used except by
7840 * BoxLayout subclasses during their onLayout run.
7842 this.layoutTargetLastSize = tSize;
7846 * @property childBoxCache
7848 * Array of the last calculated height, width, top and left positions of each visible rendered component
7849 * within the Box layout.
7851 this.childBoxCache = this.calculateChildBoxes(items, tSize);
7853 this.updateInnerCtSize(tSize, this.childBoxCache);
7854 this.updateChildBoxes(this.childBoxCache.boxes);
7856 // Putting a box layout into an overflowed container is NOT correct and will make a second layout pass necessary.
7857 this.handleTargetOverflow(tSize, container, target);
7861 * Resizes and repositions each child component
7862 * @param {Array} boxes The box measurements
7864 updateChildBoxes: function(boxes) {
7865 for (var i = 0, length = boxes.length; i < length; i++) {
7867 comp = box.component;
7869 if (box.dirtySize) {
7870 comp.setSize(box.width, box.height);
7872 // Don't set positions to NaN
7873 if (isNaN(box.left) || isNaN(box.top)) {
7876 comp.setPosition(box.left, box.top);
7882 * Called by onRender just before the child components are sized and positioned. This resizes the innerCt
7883 * to make sure all child items fit within it. We call this before sizing the children because if our child
7884 * items are larger than the previous innerCt size the browser will insert scrollbars and then remove them
7885 * again immediately afterwards, giving a performance hit.
7886 * Subclasses should provide an implementation.
7887 * @param {Object} currentSize The current height and width of the innerCt
7888 * @param {Array} calculations The new box calculations of all items to be laid out
7890 updateInnerCtSize: Ext.emptyFn,
7894 * This should be called after onLayout of any BoxLayout subclass. If the target's overflow is not set to 'hidden',
7895 * we need to lay out a second time because the scrollbars may have modified the height and width of the layout
7896 * target. Having a Box layout inside such a target is therefore not recommended.
7897 * @param {Object} previousTargetSize The size and height of the layout target before we just laid out
7898 * @param {Ext.Container} container The container
7899 * @param {Ext.Element} target The target element
7901 handleTargetOverflow: function(previousTargetSize, container, target) {
7902 var overflow = target.getStyle('overflow');
7904 if (overflow && overflow != 'hidden' &&!this.adjustmentPass) {
7905 var newTargetSize = this.getLayoutTargetSize();
7906 if (newTargetSize.width != previousTargetSize.width || newTargetSize.height != previousTargetSize.height){
7907 this.adjustmentPass = true;
7908 this.onLayout(container, target);
7912 delete this.adjustmentPass;
7916 isValidParent : function(c, target){
7917 return this.innerCt && c.getPositionEl().dom.parentNode == this.innerCt.dom;
7922 * Returns all items that are both rendered and visible
7923 * @return {Array} All matching items
7925 getVisibleItems: function(ct) {
7926 var ct = ct || this.container,
7927 t = ct.getLayoutTarget(),
7928 cti = ct.items.items,
7933 for (i = 0; i < len; i++) {
7934 if((c = cti[i]).rendered && this.isValidParent(c, t) && c.hidden !== true && c.collapsed !== true){
7943 renderAll : function(ct, target){
7945 // the innerCt prevents wrapping and shuffling while
7946 // the container is resizing
7947 this.innerCt = target.createChild({cls:this.innerCls});
7948 this.padding = this.parseMargins(this.padding);
7950 Ext.layout.BoxLayout.superclass.renderAll.call(this, ct, this.innerCt);
7953 getLayoutTargetSize : function(){
7954 var target = this.container.getLayoutTarget(), ret;
7956 ret = target.getViewSize();
7958 // IE in strict mode will return a width of 0 on the 1st pass of getViewSize.
7959 // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly
7961 if (Ext.isIE && Ext.isStrict && ret.width == 0){
7962 ret = target.getStyleSize();
7965 ret.width -= target.getPadding('lr');
7966 ret.height -= target.getPadding('tb');
7972 renderItem : function(c){
7973 if(Ext.isString(c.margins)){
7974 c.margins = this.parseMargins(c.margins);
7975 }else if(!c.margins){
7976 c.margins = this.defaultMargins;
7978 Ext.layout.BoxLayout.superclass.renderItem.apply(this, arguments);
7983 * @class Ext.layout.VBoxLayout
7984 * @extends Ext.layout.BoxLayout
7985 * <p>A layout that arranges items vertically down a Container. This layout optionally divides available vertical
7986 * space between child items containing a numeric <code>flex</code> configuration.</p>
7987 * This layout may also be used to set the widths of child items by configuring it with the {@link #align} option.
7989 Ext.layout.VBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
7991 * @cfg {String} align
7992 * Controls how the child items of the container are aligned. Acceptable configuration values for this
7994 * <div class="mdetail-params"><ul>
7995 * <li><b><tt>left</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned horizontally
7996 * at the <b>left</b> side of the container</div></li>
7997 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are aligned horizontally at the
7998 * <b>mid-width</b> of the container</div></li>
7999 * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched horizontally to fill
8000 * the width of the container</div></li>
8001 * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched horizontally to
8002 * the size of the largest item.</div></li>
8005 align : 'left', // left, center, stretch, strechmax
8009 * @cfg {String} pack
8010 * Controls how the child items of the container are packed together. Acceptable configuration values
8011 * for this property are:
8012 * <div class="mdetail-params"><ul>
8013 * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
8014 * <b>top</b> side of container</div></li>
8015 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
8016 * <b>mid-height</b> of container</div></li>
8017 * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>bottom</b>
8018 * side of container</div></li>
8023 * @cfg {Number} flex
8024 * This configuation option is to be applied to <b>child <tt>items</tt></b> of the container managed
8025 * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>vertically</b>
8026 * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
8027 * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
8028 * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
8033 * See parent documentation
8035 updateInnerCtSize: function(tSize, calcs) {
8036 var innerCtHeight = tSize.height,
8037 innerCtWidth = calcs.meta.maxWidth + this.padding.left + this.padding.right;
8039 if (this.align == 'stretch') {
8040 innerCtWidth = tSize.width;
8041 } else if (this.align == 'center') {
8042 innerCtWidth = Math.max(tSize.width, innerCtWidth);
8045 //we set the innerCt size first because if our child items are larger than the previous innerCt size
8046 //the browser will insert scrollbars and then remove them again immediately afterwards
8047 this.innerCt.setSize(innerCtWidth || undefined, innerCtHeight || undefined);
8052 * Calculates the size and positioning of each item in the VBox. This iterates over all of the rendered,
8053 * visible items and returns a height, width, top and left for each, as well as a reference to each. Also
8054 * returns meta data such as maxHeight which are useful when resizing layout wrappers such as this.innerCt.
8055 * @param {Array} visibleItems The array of all rendered, visible items to be calculated for
8056 * @param {Object} targetSize Object containing target size and height
8057 * @return {Object} Object containing box measurements for each child, plus meta data
8059 calculateChildBoxes: function(visibleItems, targetSize) {
8060 var visibleCount = visibleItems.length,
8062 padding = this.padding,
8063 topOffset = padding.top,
8064 leftOffset = padding.left,
8065 paddingVert = topOffset + padding.bottom,
8066 paddingHoriz = leftOffset + padding.right,
8068 width = targetSize.width - this.scrollOffset,
8069 height = targetSize.height,
8070 availWidth = Math.max(0, width - paddingHoriz),
8072 isStart = this.pack == 'start',
8073 isCenter = this.pack == 'center',
8074 isEnd = this.pack == 'end',
8080 //used to cache the calculated size and position values for each child item
8083 //used in the for loops below, just declared here for brevity
8084 child, childWidth, childHeight, childSize, childMargins, canLayout, i, calcs, flexedHeight, horizMargins, stretchWidth;
8086 //gather the total flex of all flexed items and the width taken up by fixed width items
8087 for (i = 0; i < visibleCount; i++) {
8088 child = visibleItems[i];
8089 childHeight = child.height;
8090 childWidth = child.width;
8091 canLayout = !child.hasLayout && Ext.isFunction(child.doLayout);
8094 // Static height (numeric) requires no calcs
8095 if (!Ext.isNumber(childHeight)) {
8097 // flex and not 'auto' height
8098 if (child.flex && !childHeight) {
8099 totalFlex += child.flex;
8101 // Not flexed or 'auto' height or undefined height
8103 //Render and layout sub-containers without a flex or width defined, as otherwise we
8104 //don't know how wide the sub-container should be and cannot calculate flexed widths
8105 if (!childHeight && canLayout) {
8109 childSize = child.getSize();
8110 childWidth = childSize.width;
8111 childHeight = childSize.height;
8115 childMargins = child.margins;
8117 nonFlexHeight += (childHeight || 0) + childMargins.top + childMargins.bottom;
8119 // Max width for align - force layout of non-layed out subcontainers without a numeric width
8120 if (!Ext.isNumber(childWidth)) {
8124 childWidth = child.getWidth();
8127 maxWidth = Math.max(maxWidth, childWidth + childMargins.left + childMargins.right);
8129 //cache the size of each child component
8132 height : childHeight || undefined,
8133 width : childWidth || undefined
8137 //the height available to the flexed items
8138 var availableHeight = Math.max(0, (height - nonFlexHeight - paddingVert));
8141 topOffset += availableHeight / 2;
8143 topOffset += availableHeight;
8146 //temporary variables used in the flex height calculations below
8147 var remainingHeight = availableHeight,
8148 remainingFlex = totalFlex;
8150 //calculate the height of each flexed item, and the left + top positions of every item
8151 for (i = 0; i < visibleCount; i++) {
8152 child = visibleItems[i];
8155 childMargins = child.margins;
8156 horizMargins = childMargins.left + childMargins.right;
8158 topOffset += childMargins.top;
8160 if (isStart && child.flex && !child.height) {
8161 flexedHeight = Math.ceil((child.flex / remainingFlex) * remainingHeight);
8162 remainingHeight -= flexedHeight;
8163 remainingFlex -= child.flex;
8165 calcs.height = flexedHeight;
8166 calcs.dirtySize = true;
8169 calcs.left = leftOffset + childMargins.left;
8170 calcs.top = topOffset;
8172 switch (this.align) {
8174 stretchWidth = availWidth - horizMargins;
8175 calcs.width = stretchWidth.constrain(child.minWidth || 0, child.maxWidth || 1000000);
8176 calcs.dirtySize = true;
8179 stretchWidth = maxWidth - horizMargins;
8180 calcs.width = stretchWidth.constrain(child.minWidth || 0, child.maxWidth || 1000000);
8181 calcs.dirtySize = true;
8184 var diff = availWidth - calcs.width - horizMargins;
8186 calcs.left = leftOffset + horizMargins + (diff / 2);
8190 topOffset += calcs.height + childMargins.bottom;
8202 Ext.Container.LAYOUTS.vbox = Ext.layout.VBoxLayout;
8205 * @class Ext.layout.HBoxLayout
8206 * @extends Ext.layout.BoxLayout
8207 * <p>A layout that arranges items horizontally across a Container. This layout optionally divides available horizontal
8208 * space between child items containing a numeric <code>flex</code> configuration.</p>
8209 * This layout may also be used to set the heights of child items by configuring it with the {@link #align} option.
8211 Ext.layout.HBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
8213 * @cfg {String} align
8214 * Controls how the child items of the container are aligned. Acceptable configuration values for this
8216 * <div class="mdetail-params"><ul>
8217 * <li><b><tt>top</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned vertically
8218 * at the <b>top</b> of the container</div></li>
8219 * <li><b><tt>middle</tt></b> : <div class="sub-desc">child items are aligned vertically in the
8220 * <b>middle</b> of the container</div></li>
8221 * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched vertically to fill
8222 * the height of the container</div></li>
8223 * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched vertically to
8224 * the height of the largest item.</div></li>
8226 align: 'top', // top, middle, stretch, strechmax
8232 * See parent documentation
8234 updateInnerCtSize: function(tSize, calcs) {
8235 var innerCtWidth = tSize.width,
8236 innerCtHeight = calcs.meta.maxHeight + this.padding.top + this.padding.bottom;
8238 if (this.align == 'stretch') {
8239 innerCtHeight = tSize.height;
8240 } else if (this.align == 'middle') {
8241 innerCtHeight = Math.max(tSize.height, innerCtHeight);
8244 this.innerCt.setSize(innerCtWidth || undefined, innerCtHeight || undefined);
8248 * @cfg {String} pack
8249 * Controls how the child items of the container are packed together. Acceptable configuration values
8250 * for this property are:
8251 * <div class="mdetail-params"><ul>
8252 * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
8253 * <b>left</b> side of container</div></li>
8254 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
8255 * <b>mid-width</b> of container</div></li>
8256 * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>right</b>
8257 * side of container</div></li>
8261 * @cfg {Number} flex
8262 * This configuation option is to be applied to <b>child <tt>items</tt></b> of the container managed
8263 * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>horizontally</b>
8264 * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
8265 * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
8266 * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
8271 * Calculates the size and positioning of each item in the HBox. This iterates over all of the rendered,
8272 * visible items and returns a height, width, top and left for each, as well as a reference to each. Also
8273 * returns meta data such as maxHeight which are useful when resizing layout wrappers such as this.innerCt.
8274 * @param {Array} visibleItems The array of all rendered, visible items to be calculated for
8275 * @param {Object} targetSize Object containing target size and height
8276 * @return {Object} Object containing box measurements for each child, plus meta data
8278 calculateChildBoxes: function(visibleItems, targetSize) {
8279 var visibleCount = visibleItems.length,
8281 padding = this.padding,
8282 topOffset = padding.top,
8283 leftOffset = padding.left,
8284 paddingVert = topOffset + padding.bottom,
8285 paddingHoriz = leftOffset + padding.right,
8287 width = targetSize.width - this.scrollOffset,
8288 height = targetSize.height,
8289 availHeight = Math.max(0, height - paddingVert),
8291 isStart = this.pack == 'start',
8292 isCenter = this.pack == 'center',
8293 isEnd = this.pack == 'end',
8294 // isRestore = ['stretch', 'stretchmax'].indexOf(this.align) == -1,
8300 //used to cache the calculated size and position values for each child item
8303 //used in the for loops below, just declared here for brevity
8304 child, childWidth, childHeight, childSize, childMargins, canLayout, i, calcs, flexedWidth, vertMargins, stretchHeight;
8306 //gather the total flex of all flexed items and the width taken up by fixed width items
8307 for (i = 0; i < visibleCount; i++) {
8308 child = visibleItems[i];
8309 childHeight = child.height;
8310 childWidth = child.width;
8311 canLayout = !child.hasLayout && Ext.isFunction(child.doLayout);
8313 // Static width (numeric) requires no calcs
8314 if (!Ext.isNumber(childWidth)) {
8316 // flex and not 'auto' width
8317 if (child.flex && !childWidth) {
8318 totalFlex += child.flex;
8320 // Not flexed or 'auto' width or undefined width
8322 //Render and layout sub-containers without a flex or width defined, as otherwise we
8323 //don't know how wide the sub-container should be and cannot calculate flexed widths
8324 if (!childWidth && canLayout) {
8328 childSize = child.getSize();
8329 childWidth = childSize.width;
8330 childHeight = childSize.height;
8334 childMargins = child.margins;
8336 nonFlexWidth += (childWidth || 0) + childMargins.left + childMargins.right;
8338 // Max height for align - force layout of non-layed out subcontainers without a numeric height
8339 if (!Ext.isNumber(childHeight)) {
8343 childHeight = child.getHeight();
8346 maxHeight = Math.max(maxHeight, childHeight + childMargins.top + childMargins.bottom);
8348 //cache the size of each child component
8351 height : childHeight || undefined,
8352 width : childWidth || undefined
8356 //the width available to the flexed items
8357 var availableWidth = Math.max(0, (width - nonFlexWidth - paddingHoriz));
8360 leftOffset += availableWidth / 2;
8362 leftOffset += availableWidth;
8365 //temporary variables used in the flex width calculations below
8366 var remainingWidth = availableWidth,
8367 remainingFlex = totalFlex;
8369 //calculate the widths of each flexed item, and the left + top positions of every item
8370 for (i = 0; i < visibleCount; i++) {
8371 child = visibleItems[i];
8374 childMargins = child.margins;
8375 vertMargins = childMargins.top + childMargins.bottom;
8377 leftOffset += childMargins.left;
8379 if (isStart && child.flex && !child.width) {
8380 flexedWidth = Math.ceil((child.flex / remainingFlex) * remainingWidth);
8381 remainingWidth -= flexedWidth;
8382 remainingFlex -= child.flex;
8384 calcs.width = flexedWidth;
8385 calcs.dirtySize = true;
8388 calcs.left = leftOffset;
8389 calcs.top = topOffset + childMargins.top;
8391 switch (this.align) {
8393 stretchHeight = availHeight - vertMargins;
8394 calcs.height = stretchHeight.constrain(child.minHeight || 0, child.maxHeight || 1000000);
8395 calcs.dirtySize = true;
8398 stretchHeight = maxHeight - vertMargins;
8399 calcs.height = stretchHeight.constrain(child.minHeight || 0, child.maxHeight || 1000000);
8400 calcs.dirtySize = true;
8403 var diff = availHeight - calcs.height - vertMargins;
8405 calcs.top = topOffset + vertMargins + (diff / 2);
8408 leftOffset += calcs.width + childMargins.right;
8414 maxHeight: maxHeight
8420 Ext.Container.LAYOUTS.hbox = Ext.layout.HBoxLayout;
8422 * @class Ext.layout.ToolbarLayout
8423 * @extends Ext.layout.ContainerLayout
8424 * Layout manager used by Ext.Toolbar. This is highly specialised for use by Toolbars and would not
8425 * usually be used by any other class.
8427 Ext.layout.ToolbarLayout = Ext.extend(Ext.layout.ContainerLayout, {
8428 monitorResize : true,
8433 * @property triggerWidth
8435 * The width allocated for the menu trigger at the extreme right end of the Toolbar
8440 * @property noItemsMenuText
8442 * HTML fragment to render into the toolbar overflow menu if there are no items to display
8444 noItemsMenuText : '<div class="x-toolbar-no-items">(None)</div>',
8448 * @property lastOverflow
8450 * Used internally to record whether the last layout caused an overflow or not
8452 lastOverflow: false,
8456 * @property tableHTML
8458 * String used to build the HTML injected to support the Toolbar's layout. The align property is
8459 * injected into this string inside the td.x-toolbar-left element during onLayout.
8462 '<table cellspacing="0" class="x-toolbar-ct">',
8465 '<td class="x-toolbar-left" align="{0}">',
8466 '<table cellspacing="0">',
8468 '<tr class="x-toolbar-left-row"></tr>',
8472 '<td class="x-toolbar-right" align="right">',
8473 '<table cellspacing="0" class="x-toolbar-right-ct">',
8477 '<table cellspacing="0">',
8479 '<tr class="x-toolbar-right-row"></tr>',
8484 '<table cellspacing="0">',
8486 '<tr class="x-toolbar-extras-row"></tr>',
8501 * Create the wrapping Toolbar HTML and render/move all the items into the correct places
8503 onLayout : function(ct, target) {
8504 //render the Toolbar <table> HTML if it's not already present
8506 var align = ct.buttonAlign == 'center' ? 'center' : 'left';
8508 target.addClass('x-toolbar-layout-ct');
8509 target.insertHtml('beforeEnd', String.format(this.tableHTML, align));
8511 this.leftTr = target.child('tr.x-toolbar-left-row', true);
8512 this.rightTr = target.child('tr.x-toolbar-right-row', true);
8513 this.extrasTr = target.child('tr.x-toolbar-extras-row', true);
8515 if (this.hiddenItem == undefined) {
8517 * @property hiddenItems
8519 * Holds all items that are currently hidden due to there not being enough space to render them
8520 * These items will appear on the expand menu.
8522 this.hiddenItems = [];
8526 var side = ct.buttonAlign == 'right' ? this.rightTr : this.leftTr,
8527 items = ct.items.items,
8530 //render each item if not already rendered, place it into the correct (left or right) target
8531 for (var i = 0, len = items.length, c; i < len; i++, position++) {
8535 side = this.rightTr;
8537 } else if (!c.rendered) {
8538 c.render(this.insertCell(c, side, position));
8540 if (!c.xtbHidden && !this.isValidParent(c, side.childNodes[position])) {
8541 var td = this.insertCell(c, side, position);
8542 td.appendChild(c.getPositionEl().dom);
8543 c.container = Ext.get(td);
8548 //strip extra empty cells
8549 this.cleanup(this.leftTr);
8550 this.cleanup(this.rightTr);
8551 this.cleanup(this.extrasTr);
8552 this.fitToSize(target);
8557 * Removes any empty nodes from the given element
8558 * @param {Ext.Element} el The element to clean up
8560 cleanup : function(el) {
8561 var cn = el.childNodes, i, c;
8563 for (i = cn.length-1; i >= 0 && (c = cn[i]); i--) {
8564 if (!c.firstChild) {
8572 * Inserts the given Toolbar item into the given element
8573 * @param {Ext.Component} c The component to add
8574 * @param {Ext.Element} target The target to add the component to
8575 * @param {Number} position The position to add the component at
8577 insertCell : function(c, target, position) {
8578 var td = document.createElement('td');
8579 td.className = 'x-toolbar-cell';
8581 target.insertBefore(td, target.childNodes[position] || null);
8588 * Hides an item because it will not fit in the available width. The item will be unhidden again
8589 * if the Toolbar is resized to be large enough to show it
8590 * @param {Ext.Component} item The item to hide
8592 hideItem : function(item) {
8593 this.hiddenItems.push(item);
8595 item.xtbHidden = true;
8596 item.xtbWidth = item.getPositionEl().dom.parentNode.offsetWidth;
8602 * Unhides an item that was previously hidden due to there not being enough space left on the Toolbar
8603 * @param {Ext.Component} item The item to show
8605 unhideItem : function(item) {
8607 item.xtbHidden = false;
8608 this.hiddenItems.remove(item);
8613 * Returns the width of the given toolbar item. If the item is currently hidden because there
8614 * is not enough room to render it, its previous width is returned
8615 * @param {Ext.Component} c The component to measure
8616 * @return {Number} The width of the item
8618 getItemWidth : function(c) {
8619 return c.hidden ? (c.xtbWidth || 0) : c.getPositionEl().dom.parentNode.offsetWidth;
8624 * Called at the end of onLayout. At this point the Toolbar has already been resized, so we need
8625 * to fit the items into the available width. We add up the width required by all of the items in
8626 * the toolbar - if we don't have enough space we hide the extra items and render the expand menu
8628 * @param {Ext.Element} target The Element the Toolbar is currently laid out within
8630 fitToSize : function(target) {
8631 if (this.container.enableOverflow === false) {
8635 var width = target.dom.clientWidth,
8636 tableWidth = target.dom.firstChild.offsetWidth,
8637 clipWidth = width - this.triggerWidth,
8638 lastWidth = this.lastWidth || 0,
8640 hiddenItems = this.hiddenItems,
8641 hasHiddens = hiddenItems.length != 0,
8642 isLarger = width >= lastWidth;
8644 this.lastWidth = width;
8646 if (tableWidth > width || (hasHiddens && isLarger)) {
8647 var items = this.container.items.items,
8652 for (var i = 0; i < len; i++) {
8656 loopWidth += this.getItemWidth(item);
8657 if (loopWidth > clipWidth) {
8658 if (!(item.hidden || item.xtbHidden)) {
8659 this.hideItem(item);
8661 } else if (item.xtbHidden) {
8662 this.unhideItem(item);
8668 //test for number of hidden items again here because they may have changed above
8669 hasHiddens = hiddenItems.length != 0;
8674 if (!this.lastOverflow) {
8675 this.container.fireEvent('overflowchange', this.container, true);
8676 this.lastOverflow = true;
8678 } else if (this.more) {
8680 this.more.destroy();
8683 if (this.lastOverflow) {
8684 this.container.fireEvent('overflowchange', this.container, false);
8685 this.lastOverflow = false;
8692 * Returns a menu config for a given component. This config is used to create a menu item
8693 * to be added to the expander menu
8694 * @param {Ext.Component} component The component to create the config for
8695 * @param {Boolean} hideOnClick Passed through to the menu item
8697 createMenuConfig : function(component, hideOnClick){
8698 var config = Ext.apply({}, component.initialConfig),
8699 group = component.toggleGroup;
8701 Ext.copyTo(config, component, [
8702 'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu'
8706 text : component.overflowText || component.text,
8707 hideOnClick: hideOnClick
8710 if (group || component.enableToggle) {
8713 checked: component.pressed,
8715 checkchange: function(item, checked){
8716 component.toggle(checked);
8722 delete config.ownerCt;
8723 delete config.xtype;
8731 * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually.
8732 * @param {Ext.menu.Menu} menu The menu to add to
8733 * @param {Ext.Component} component The component to add
8735 addComponentToMenu : function(menu, component) {
8736 if (component instanceof Ext.Toolbar.Separator) {
8739 } else if (Ext.isFunction(component.isXType)) {
8740 if (component.isXType('splitbutton')) {
8741 menu.add(this.createMenuConfig(component, true));
8743 } else if (component.isXType('button')) {
8744 menu.add(this.createMenuConfig(component, !component.menu));
8746 } else if (component.isXType('buttongroup')) {
8747 component.items.each(function(item){
8748 this.addComponentToMenu(menu, item);
8756 * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as
8757 * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item
8759 clearMenu : function(){
8760 var menu = this.moreMenu;
8761 if (menu && menu.items) {
8762 menu.items.each(function(item){
8770 * Called before the expand menu is shown, this rebuilds the menu since it was last shown because
8771 * it is possible that the items hidden due to space limitations on the Toolbar have changed since.
8772 * @param {Ext.menu.Menu} m The menu
8774 beforeMoreShow : function(menu) {
8775 var items = this.container.items.items,
8780 var needsSep = function(group, item){
8781 return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator);
8786 for (var i = 0; i < len; i++) {
8788 if (item.xtbHidden) {
8789 if (prev && (needsSep(item, prev) || needsSep(prev, item))) {
8792 this.addComponentToMenu(menu, item);
8797 // put something so the menu isn't empty if no compatible items found
8798 if (menu.items.length < 1) {
8799 menu.add(this.noItemsMenuText);
8805 * Creates the expand trigger and menu, adding them to the <tr> at the extreme right of the
8808 initMore : function(){
8812 * @property moreMenu
8813 * @type Ext.menu.Menu
8814 * The expand menu - holds items for every Toolbar item that cannot be shown
8815 * because the Toolbar is currently not wide enough.
8817 this.moreMenu = new Ext.menu.Menu({
8818 ownerCt : this.container,
8820 beforeshow: this.beforeMoreShow,
8829 * The expand button which triggers the overflow menu to be shown
8831 this.more = new Ext.Button({
8832 iconCls: 'x-toolbar-more-icon',
8833 cls : 'x-toolbar-more',
8834 menu : this.moreMenu,
8835 ownerCt: this.container
8838 var td = this.insertCell(this.more, this.extrasTr, 100);
8839 this.more.render(td);
8843 destroy : function(){
8844 Ext.destroy(this.more, this.moreMenu);
8846 delete this.rightTr;
8847 delete this.extrasTr;
8848 Ext.layout.ToolbarLayout.superclass.destroy.call(this);
8852 Ext.Container.LAYOUTS.toolbar = Ext.layout.ToolbarLayout;
8854 * @class Ext.layout.MenuLayout
8855 * @extends Ext.layout.ContainerLayout
8856 * <p>Layout manager used by {@link Ext.menu.Menu}. Generally this class should not need to be used directly.</p>
8858 Ext.layout.MenuLayout = Ext.extend(Ext.layout.ContainerLayout, {
8859 monitorResize : true,
8863 setContainer : function(ct){
8864 this.monitorResize = !ct.floating;
8865 // This event is only fired by the menu in IE, used so we don't couple
8866 // the menu with the layout.
8867 ct.on('autosize', this.doAutoSize, this);
8868 Ext.layout.MenuLayout.superclass.setContainer.call(this, ct);
8871 renderItem : function(c, position, target){
8872 if (!this.itemTpl) {
8873 this.itemTpl = Ext.layout.MenuLayout.prototype.itemTpl = new Ext.XTemplate(
8874 '<li id="{itemId}" class="{itemCls}">',
8875 '<tpl if="needsIcon">',
8876 '<img src="{icon}" class="{iconCls}"/>',
8882 if(c && !c.rendered){
8883 if(Ext.isNumber(position)){
8884 position = target.dom.childNodes[position];
8886 var a = this.getItemArgs(c);
8888 // The Component's positionEl is the <li> it is rendered into
8889 c.render(c.positionEl = position ?
8890 this.itemTpl.insertBefore(position, a, true) :
8891 this.itemTpl.append(target, a, true));
8893 // Link the containing <li> to the item.
8894 c.positionEl.menuItemId = c.getItemId();
8896 // If rendering a regular Component, and it needs an icon,
8897 // move the Component rightwards.
8898 if (!a.isMenuItem && a.needsIcon) {
8899 c.positionEl.addClass('x-menu-list-item-indent');
8901 this.configureItem(c, position);
8902 }else if(c && !this.isValidParent(c, target)){
8903 if(Ext.isNumber(position)){
8904 position = target.dom.childNodes[position];
8906 target.dom.insertBefore(c.getActionEl().dom, position || null);
8910 getItemArgs : function(c) {
8911 var isMenuItem = c instanceof Ext.menu.Item;
8913 isMenuItem: isMenuItem,
8914 needsIcon: !isMenuItem && (c.icon || c.iconCls),
8915 icon: c.icon || Ext.BLANK_IMAGE_URL,
8916 iconCls: 'x-menu-item-icon ' + (c.iconCls || ''),
8917 itemId: 'x-menu-el-' + c.id,
8918 itemCls: 'x-menu-list-item '
8922 // Valid if the Component is in a <li> which is part of our target <ul>
8923 isValidParent : function(c, target) {
8924 return c.el.up('li.x-menu-list-item', 5).dom.parentNode === (target.dom || target);
8927 onLayout : function(ct, target){
8928 Ext.layout.MenuLayout.superclass.onLayout.call(this, ct, target);
8932 doAutoSize : function(){
8933 var ct = this.container, w = ct.width;
8938 ct.setWidth(Ext.isStrict && (Ext.isIE7 || Ext.isIE8) ? 'auto' : ct.minWidth);
8939 var el = ct.getEl(), t = el.dom.offsetWidth; // force recalc
8940 ct.setWidth(ct.getLayoutTarget().getWidth() + el.getFrameWidth('lr'));
8945 Ext.Container.LAYOUTS['menu'] = Ext.layout.MenuLayout;
8947 * @class Ext.Viewport
8948 * @extends Ext.Container
8949 * <p>A specialized container representing the viewable application area (the browser viewport).</p>
8950 * <p>The Viewport renders itself to the document body, and automatically sizes itself to the size of
8951 * the browser viewport and manages window resizing. There may only be one Viewport created
8952 * in a page. Inner layouts are available by virtue of the fact that all {@link Ext.Panel Panel}s
8953 * added to the Viewport, either through its {@link #items}, or through the items, or the {@link #add}
8954 * method of any of its child Panels may themselves have a layout.</p>
8955 * <p>The Viewport does not provide scrolling, so child Panels within the Viewport should provide
8956 * for scrolling if needed using the {@link #autoScroll} config.</p>
8957 * <p>An example showing a classic application border layout:</p><pre><code>
8962 html: '<h1 class="x-panel-header">Page Title</h1>',
8969 title: 'Navigation',
8971 // the west region might typically utilize a {@link Ext.tree.TreePanel TreePanel} or a Panel with {@link Ext.layout.AccordionLayout Accordion layout}
8974 title: 'Title for Panel',
8976 html: 'Information goes here',
8982 title: 'Title for the Grid Panel',
8987 // remaining grid configuration not shown ...
8988 // notice that the GridPanel is added directly as the region
8989 // it is not "overnested" inside another Panel
8992 xtype: 'tabpanel', // TabPanel itself has no title
8994 title: 'Default Tab',
8995 html: 'The first tab\'s content. Others may be added dynamically'
9001 * Create a new Viewport
9002 * @param {Object} config The config object
9005 Ext.Viewport = Ext.extend(Ext.Container, {
9007 * Privatize config options which, if used, would interfere with the
9008 * correct operation of the Viewport as the sole manager of the
9009 * layout of the document body.
9012 * @cfg {Mixed} applyTo @hide
9015 * @cfg {Boolean} allowDomMove @hide
9018 * @cfg {Boolean} hideParent @hide
9021 * @cfg {Mixed} renderTo @hide
9024 * @cfg {Boolean} hideParent @hide
9027 * @cfg {Number} height @hide
9030 * @cfg {Number} width @hide
9033 * @cfg {Boolean} autoHeight @hide
9036 * @cfg {Boolean} autoWidth @hide
9039 * @cfg {Boolean} deferHeight @hide
9042 * @cfg {Boolean} monitorResize @hide
9045 initComponent : function() {
9046 Ext.Viewport.superclass.initComponent.call(this);
9047 document.getElementsByTagName('html')[0].className += ' x-viewport';
9048 this.el = Ext.getBody();
9049 this.el.setHeight = Ext.emptyFn;
9050 this.el.setWidth = Ext.emptyFn;
9051 this.el.setSize = Ext.emptyFn;
9052 this.el.dom.scroll = 'no';
9053 this.allowDomMove = false;
9054 this.autoWidth = true;
9055 this.autoHeight = true;
9056 Ext.EventManager.onWindowResize(this.fireResize, this);
9057 this.renderTo = this.el;
9060 fireResize : function(w, h){
9061 this.fireEvent('resize', this, w, h, w, h);
9064 Ext.reg('viewport', Ext.Viewport);
9067 * @extends Ext.Container
9068 * <p>Panel is a container that has specific functionality and structural components that make
9069 * it the perfect building block for application-oriented user interfaces.</p>
9070 * <p>Panels are, by virtue of their inheritance from {@link Ext.Container}, capable
9071 * of being configured with a {@link Ext.Container#layout layout}, and containing child Components.</p>
9072 * <p>When either specifying child {@link Ext.Component#items items} of a Panel, or dynamically {@link Ext.Container#add adding} Components
9073 * to a Panel, remember to consider how you wish the Panel to arrange those child elements, and whether
9074 * 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
9075 * default, Panels use the {@link Ext.layout.ContainerLayout ContainerLayout} scheme. This simply renders
9076 * child components, appending them one after the other inside the Container, and <b>does not apply any sizing</b>
9078 * <p>A Panel may also contain {@link #bbar bottom} and {@link #tbar top} toolbars, along with separate
9079 * {@link #header}, {@link #footer} and {@link #body} sections (see {@link #frame} for additional
9081 * <p>Panel also provides built-in {@link #collapsible expandable and collapsible behavior}, along with
9082 * a variety of {@link #tools prebuilt tool buttons} that can be wired up to provide other customized
9083 * behavior. Panels can be easily dropped into any {@link Ext.Container Container} or layout, and the
9084 * layout and rendering pipeline is {@link Ext.Container#add completely managed by the framework}.</p>
9086 * @param {Object} config The config object
9089 Ext.Panel = Ext.extend(Ext.Container, {
9091 * The Panel's header {@link Ext.Element Element}. Read-only.
9092 * <p>This Element is used to house the {@link #title} and {@link #tools}</p>
9093 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
9098 * The Panel's body {@link Ext.Element Element} which may be used to contain HTML content.
9099 * The content may be specified in the {@link #html} config, or it may be loaded using the
9100 * {@link autoLoad} config, or through the Panel's {@link #getUpdater Updater}. Read-only.
9101 * <p>If this is used to load visible HTML elements in either way, then
9102 * the Panel may not be used as a Layout for hosting nested Panels.</p>
9103 * <p>If this Panel is intended to be used as the host of a Layout (See {@link #layout}
9104 * then the body Element must not be loaded or changed - it is under the control
9105 * of the Panel's Layout.
9106 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
9111 * The Panel's bwrap {@link Ext.Element Element} used to contain other Panel elements
9112 * (tbar, body, bbar, footer). See {@link #bodyCfg}. Read-only.
9117 * True if this panel is collapsed. Read-only.
9119 * @property collapsed
9122 * @cfg {Object} bodyCfg
9123 * <p>A {@link Ext.DomHelper DomHelper} element specification object may be specified for any
9124 * Panel Element.</p>
9125 * <p>By default, the Default element in the table below will be used for the html markup to
9126 * create a child element with the commensurate Default class name (<code>baseCls</code> will be
9127 * replaced by <code>{@link #baseCls}</code>):</p>
9129 * Panel Default Default Custom Additional Additional
9130 * Element element class element class style
9131 * ======== ========================== ========= ============== ===========
9132 * {@link #header} div {@link #baseCls}+'-header' {@link #headerCfg} headerCssClass headerStyle
9133 * {@link #bwrap} div {@link #baseCls}+'-bwrap' {@link #bwrapCfg} bwrapCssClass bwrapStyle
9134 * + tbar div {@link #baseCls}+'-tbar' {@link #tbarCfg} tbarCssClass tbarStyle
9135 * + {@link #body} div {@link #baseCls}+'-body' {@link #bodyCfg} {@link #bodyCssClass} {@link #bodyStyle}
9136 * + bbar div {@link #baseCls}+'-bbar' {@link #bbarCfg} bbarCssClass bbarStyle
9137 * + {@link #footer} div {@link #baseCls}+'-footer' {@link #footerCfg} footerCssClass footerStyle
9139 * <p>Configuring a Custom element may be used, for example, to force the {@link #body} Element
9140 * to use a different form of markup than is created by default. An example of this might be
9141 * to {@link Ext.Element#createChild create a child} Panel containing a custom content, such as
9142 * a header, or forcing centering of all Panel content by having the body be a <center>
9146 title: 'Message Title',
9147 renderTo: Ext.getBody(),
9148 width: 200, height: 130,
9151 cls: 'x-panel-body', // Default class not applied if Custom element specified
9156 cls: 'x-panel-footer' // same as the Default class
9159 footerCssClass: 'custom-footer', // additional css class, see {@link Ext.element#addClass addClass}
9160 footerStyle: 'background-color:red' // see {@link #bodyStyle}
9163 * <p>The example above also explicitly creates a <code>{@link #footer}</code> with custom markup and
9164 * styling applied.</p>
9167 * @cfg {Object} headerCfg
9168 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
9169 * of this Panel's {@link #header} Element. See <code>{@link #bodyCfg}</code> also.</p>
9172 * @cfg {Object} bwrapCfg
9173 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
9174 * of this Panel's {@link #bwrap} Element. See <code>{@link #bodyCfg}</code> also.</p>
9177 * @cfg {Object} tbarCfg
9178 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
9179 * of this Panel's {@link #tbar} Element. See <code>{@link #bodyCfg}</code> also.</p>
9182 * @cfg {Object} bbarCfg
9183 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
9184 * of this Panel's {@link #bbar} Element. See <code>{@link #bodyCfg}</code> also.</p>
9187 * @cfg {Object} footerCfg
9188 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
9189 * of this Panel's {@link #footer} Element. See <code>{@link #bodyCfg}</code> also.</p>
9192 * @cfg {Boolean} closable
9193 * Panels themselves do not directly support being closed, but some Panel subclasses do (like
9194 * {@link Ext.Window}) or a Panel Class within an {@link Ext.TabPanel}. Specify <code>true</code>
9195 * to enable closing in such situations. Defaults to <code>false</code>.
9198 * The Panel's footer {@link Ext.Element Element}. Read-only.
9199 * <p>This Element is used to house the Panel's <code>{@link #buttons}</code> or <code>{@link #fbar}</code>.</p>
9200 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
9205 * @cfg {Mixed} applyTo
9206 * <p>The id of the node, a DOM node or an existing Element corresponding to a DIV that is already present in
9207 * the document that specifies some panel-specific structural markup. When <code>applyTo</code> is used,
9208 * constituent parts of the panel can be specified by CSS class name within the main element, and the panel
9209 * will automatically create those components from that markup. Any required components not specified in the
9210 * markup will be autogenerated if necessary.</p>
9211 * <p>The following class names are supported (baseCls will be replaced by {@link #baseCls}):</p>
9212 * <ul><li>baseCls + '-header'</li>
9213 * <li>baseCls + '-header-text'</li>
9214 * <li>baseCls + '-bwrap'</li>
9215 * <li>baseCls + '-tbar'</li>
9216 * <li>baseCls + '-body'</li>
9217 * <li>baseCls + '-bbar'</li>
9218 * <li>baseCls + '-footer'</li></ul>
9219 * <p>Using this config, a call to render() is not required. If applyTo is specified, any value passed for
9220 * {@link #renderTo} will be ignored and the target element's parent node will automatically be used as the
9221 * panel's container.</p>
9224 * @cfg {Object/Array} tbar
9225 * <p>The top toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
9226 * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render.
9227 * To access the top toolbar after render, use {@link #getTopToolbar}.</p>
9228 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
9229 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
9230 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
9231 * submission parameters are collected from the DOM tree.</p>
9234 * @cfg {Object/Array} bbar
9235 * <p>The bottom toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
9236 * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render.
9237 * To access the bottom toolbar after render, use {@link #getBottomToolbar}.</p>
9238 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
9239 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
9240 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
9241 * submission parameters are collected from the DOM tree.</p>
9243 /** @cfg {Object/Array} fbar
9244 * <p>A {@link Ext.Toolbar Toolbar} object, a Toolbar config, or an array of
9245 * {@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>
9246 * <p>After render, the <code>fbar</code> property will be an {@link Ext.Toolbar Toolbar} instance.</p>
9247 * <p>If <code>{@link #buttons}</code> are specified, they will supersede the <code>fbar</code> configuration property.</p>
9248 * The Panel's <code>{@link #buttonAlign}</code> configuration affects the layout of these items, for example:
9250 var w = new Ext.Window({
9253 bbar: new Ext.Toolbar({
9260 {@link #buttonAlign}: 'left', // anything but 'center' or 'right' and you can use '-', and '->'
9261 // to control the alignment of fbar items
9269 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
9270 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
9271 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
9272 * submission parameters are collected from the DOM tree.</p>
9275 * @cfg {Boolean} header
9276 * <code>true</code> to create the Panel's header element explicitly, <code>false</code> to skip creating
9277 * it. If a <code>{@link #title}</code> is set the header will be created automatically, otherwise it will not.
9278 * If a <code>{@link #title}</code> is set but <code>header</code> is explicitly set to <code>false</code>, the header
9279 * will not be rendered.
9282 * @cfg {Boolean} footer
9283 * <code>true</code> to create the footer element explicitly, false to skip creating it. The footer
9284 * will be created automatically if <code>{@link #buttons}</code> or a <code>{@link #fbar}</code> have
9285 * been configured. See <code>{@link #bodyCfg}</code> for an example.
9288 * @cfg {String} title
9289 * The title text to be used as innerHTML (html tags are accepted) to display in the panel
9290 * <code>{@link #header}</code> (defaults to ''). When a <code>title</code> is specified the
9291 * <code>{@link #header}</code> element will automatically be created and displayed unless
9292 * {@link #header} is explicitly set to <code>false</code>. If you do not want to specify a
9293 * <code>title</code> at config time, but you may want one later, you must either specify a non-empty
9294 * <code>title</code> (a blank space ' ' will do) or <code>header:true</code> so that the container
9295 * element will get created.
9298 * @cfg {Array} buttons
9299 * <code>buttons</code> will be used as <code>{@link Ext.Container#items items}</code> for the toolbar in
9300 * the footer (<code>{@link #fbar}</code>). Typically the value of this configuration property will be
9301 * an array of {@link Ext.Button}s or {@link Ext.Button} configuration objects.
9302 * If an item is configured with <code>minWidth</code> or the Panel is configured with <code>minButtonWidth</code>,
9303 * that width will be applied to the item.
9306 * @cfg {Object/String/Function} autoLoad
9307 * A valid url spec according to the Updater {@link Ext.Updater#update} method.
9308 * If autoLoad is not null, the panel will attempt to load its contents
9309 * immediately upon render.<p>
9310 * The URL will become the default URL for this panel's {@link #body} element,
9311 * so it may be {@link Ext.Element#refresh refresh}ed at any time.</p>
9314 * @cfg {Boolean} frame
9315 * <code>false</code> by default to render with plain 1px square borders. <code>true</code> to render with
9316 * 9 elements, complete with custom rounded corners (also see {@link Ext.Element#boxWrap}).
9317 * <p>The template generated for each condition is depicted below:</p><pre><code>
9320 <div id="developer-specified-id-goes-here" class="x-panel">
9322 <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:false)</span></div>
9324 <div class="x-panel-bwrap">
9325 <div class="x-panel-body"><p>html value goes here</p></div>
9329 // frame = true (create 9 elements)
9330 <div id="developer-specified-id-goes-here" class="x-panel">
9331 <div class="x-panel-tl"><div class="x-panel-tr"><div class="x-panel-tc">
9332 <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:true)</span></div>
9333 </div></div></div>
9335 <div class="x-panel-bwrap">
9336 <div class="x-panel-ml"><div class="x-panel-mr"><div class="x-panel-mc">
9337 <div class="x-panel-body"><p>html value goes here</p></div>
9338 </div></div></div>
9340 <div class="x-panel-bl"><div class="x-panel-br"><div class="x-panel-bc"/>
9341 </div></div></div>
9346 * @cfg {Boolean} border
9347 * True to display the borders of the panel's body element, false to hide them (defaults to true). By default,
9348 * the border is a 2px wide inset border, but this can be further altered by setting {@link #bodyBorder} to false.
9351 * @cfg {Boolean} bodyBorder
9352 * True to display an interior border on the body element of the panel, false to hide it (defaults to true).
9353 * This only applies when {@link #border} == true. If border == true and bodyBorder == false, the border will display
9354 * as a 1px wide inset border, giving the entire body element an inset appearance.
9357 * @cfg {String/Object/Function} bodyCssClass
9358 * Additional css class selector to be applied to the {@link #body} element in the format expected by
9359 * {@link Ext.Element#addClass} (defaults to null). See {@link #bodyCfg}.
9362 * @cfg {String/Object/Function} bodyStyle
9363 * Custom CSS styles to be applied to the {@link #body} element in the format expected by
9364 * {@link Ext.Element#applyStyles} (defaults to null). See {@link #bodyCfg}.
9367 * @cfg {String} iconCls
9368 * The CSS class selector that specifies a background image to be used as the header icon (defaults to '').
9369 * <p>An example of specifying a custom icon class would be something like:
9371 // specify the property in the config for the class:
9375 // css class that specifies background image to be used as the icon image:
9376 .my-icon { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
9380 * @cfg {Boolean} collapsible
9381 * True to make the panel collapsible and have the expand/collapse toggle button automatically rendered into
9382 * the header tool button area, false to keep the panel statically sized with no button (defaults to false).
9385 * @cfg {Array} tools
9386 * An array of tool button configs to be added to the header tool area. When rendered, each tool is
9387 * stored as an {@link Ext.Element Element} referenced by a public property called <code><b></b>tools.<i><tool-type></i></code>
9388 * <p>Each tool config may contain the following properties:
9389 * <div class="mdetail-params"><ul>
9390 * <li><b>id</b> : String<div class="sub-desc"><b>Required.</b> The type
9391 * of tool to create. By default, this assigns a CSS class of the form <code>x-tool-<i><tool-type></i></code> to the
9392 * resulting tool Element. Ext provides CSS rules, and an icon sprite containing images for the tool types listed below.
9393 * The developer may implement custom tools by supplying alternate CSS rules and background images:
9395 * <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>
9396 * <div class="x-tool x-tool-close" style="float:left; margin-right:5;"> </div><div><code> close</code></div>
9397 * <div class="x-tool x-tool-minimize" style="float:left; margin-right:5;"> </div><div><code> minimize</code></div>
9398 * <div class="x-tool x-tool-maximize" style="float:left; margin-right:5;"> </div><div><code> maximize</code></div>
9399 * <div class="x-tool x-tool-restore" style="float:left; margin-right:5;"> </div><div><code> restore</code></div>
9400 * <div class="x-tool x-tool-gear" style="float:left; margin-right:5;"> </div><div><code> gear</code></div>
9401 * <div class="x-tool x-tool-pin" style="float:left; margin-right:5;"> </div><div><code> pin</code></div>
9402 * <div class="x-tool x-tool-unpin" style="float:left; margin-right:5;"> </div><div><code> unpin</code></div>
9403 * <div class="x-tool x-tool-right" style="float:left; margin-right:5;"> </div><div><code> right</code></div>
9404 * <div class="x-tool x-tool-left" style="float:left; margin-right:5;"> </div><div><code> left</code></div>
9405 * <div class="x-tool x-tool-up" style="float:left; margin-right:5;"> </div><div><code> up</code></div>
9406 * <div class="x-tool x-tool-down" style="float:left; margin-right:5;"> </div><div><code> down</code></div>
9407 * <div class="x-tool x-tool-refresh" style="float:left; margin-right:5;"> </div><div><code> refresh</code></div>
9408 * <div class="x-tool x-tool-minus" style="float:left; margin-right:5;"> </div><div><code> minus</code></div>
9409 * <div class="x-tool x-tool-plus" style="float:left; margin-right:5;"> </div><div><code> plus</code></div>
9410 * <div class="x-tool x-tool-help" style="float:left; margin-right:5;"> </div><div><code> help</code></div>
9411 * <div class="x-tool x-tool-search" style="float:left; margin-right:5;"> </div><div><code> search</code></div>
9412 * <div class="x-tool x-tool-save" style="float:left; margin-right:5;"> </div><div><code> save</code></div>
9413 * <div class="x-tool x-tool-print" style="float:left; margin-right:5;"> </div><div><code> print</code></div>
9415 * <li><b>handler</b> : Function<div class="sub-desc"><b>Required.</b> The function to
9416 * call when clicked. Arguments passed are:<ul>
9417 * <li><b>event</b> : Ext.EventObject<div class="sub-desc">The click event.</div></li>
9418 * <li><b>toolEl</b> : Ext.Element<div class="sub-desc">The tool Element.</div></li>
9419 * <li><b>panel</b> : Ext.Panel<div class="sub-desc">The host Panel</div></li>
9420 * <li><b>tc</b> : Object<div class="sub-desc">The tool configuration object</div></li>
9422 * <li><b>stopEvent</b> : Boolean<div class="sub-desc">Defaults to true. Specify as false to allow click event to propagate.</div></li>
9423 * <li><b>scope</b> : Object<div class="sub-desc">The scope in which to call the handler.</div></li>
9424 * <li><b>qtip</b> : String/Object<div class="sub-desc">A tip string, or
9425 * a config argument to {@link Ext.QuickTip#register}</div></li>
9426 * <li><b>hidden</b> : Boolean<div class="sub-desc">True to initially render hidden.</div></li>
9427 * <li><b>on</b> : Object<div class="sub-desc">A listener config object specifiying
9428 * event listeners in the format of an argument to {@link #addListener}</div></li>
9430 * <p>Note that, apart from the toggle tool which is provided when a panel is collapsible, these
9431 * tools only provide the visual button. Any required functionality must be provided by adding
9432 * handlers that implement the necessary behavior.</p>
9433 * <p>Example usage:</p>
9437 qtip: 'Refresh form Data',
9439 handler: function(event, toolEl, panel){
9446 handler: function(event, toolEl, panel){
9451 * <p>For the custom id of <code>'help'</code> define two relevant css classes with a link to
9452 * a 15x15 image:</p>
9454 .x-tool-help {background-image: url(images/help.png);}
9455 .x-tool-help-over {background-image: url(images/help_over.png);}
9456 // if using an image sprite:
9457 .x-tool-help {background-image: url(images/help.png) no-repeat 0 0;}
9458 .x-tool-help-over {background-position:-15px 0;}
9462 * @cfg {Ext.Template/Ext.XTemplate} toolTemplate
9463 * <p>A Template used to create {@link #tools} in the {@link #header} Element. Defaults to:</p><pre><code>
9464 new Ext.Template('<div class="x-tool x-tool-{id}">&#160;</div>')</code></pre>
9465 * <p>This may may be overridden to provide a custom DOM structure for tools based upon a more
9466 * complex XTemplate. The template's data is a single tool configuration object (Not the entire Array)
9467 * as specified in {@link #tools}. In the following example an <a> tag is used to provide a
9468 * visual indication when hovering over the tool:</p><pre><code>
9469 var win = new Ext.Window({
9472 href: '/MyPdfDoc.pdf'
9474 toolTemplate: new Ext.XTemplate(
9475 '<tpl if="id==\'download\'">',
9476 '<a class="x-tool x-tool-pdf" href="{href}"></a>',
9478 '<tpl if="id!=\'download\'">',
9479 '<div class="x-tool x-tool-{id}">&#160;</div>',
9486 * <p>Note that the CSS class 'x-tool-pdf' should have an associated style rule which provides an
9487 * appropriate background image, something like:</p>
9489 a.x-tool-pdf {background-image: url(../shared/extjs/images/pdf.gif)!important;}
9493 * @cfg {Boolean} hideCollapseTool
9494 * <code>true</code> to hide the expand/collapse toggle button when <code>{@link #collapsible} == true</code>,
9495 * <code>false</code> to display it (defaults to <code>false</code>).
9498 * @cfg {Boolean} titleCollapse
9499 * <code>true</code> to allow expanding and collapsing the panel (when <code>{@link #collapsible} = true</code>)
9500 * by clicking anywhere in the header bar, <code>false</code>) to allow it only by clicking to tool button
9501 * (defaults to <code>false</code>)). If this panel is a child item of a border layout also see the
9502 * {@link Ext.layout.BorderLayout.Region BorderLayout.Region}
9503 * <code>{@link Ext.layout.BorderLayout.Region#floatable floatable}</code> config option.
9507 * @cfg {Mixed} floating
9508 * <p>This property is used to configure the underlying {@link Ext.Layer}. Acceptable values for this
9509 * configuration property are:</p><div class="mdetail-params"><ul>
9510 * <li><b><code>false</code></b> : <b>Default.</b><div class="sub-desc">Display the panel inline where it is
9511 * rendered.</div></li>
9512 * <li><b><code>true</code></b> : <div class="sub-desc">Float the panel (absolute position it with automatic
9513 * shimming and shadow).<ul>
9514 * <div class="sub-desc">Setting floating to true will create an Ext.Layer for this panel and display the
9515 * panel at negative offsets so that it is hidden.</div>
9516 * <div class="sub-desc">Since the panel will be absolute positioned, the position must be set explicitly
9517 * <i>after</i> render (e.g., <code>myPanel.setPosition(100,100);</code>).</div>
9518 * <div class="sub-desc"><b>Note</b>: when floating a panel you should always assign a fixed width,
9519 * otherwise it will be auto width and will expand to fill to the right edge of the viewport.</div>
9521 * <li><b><code>{@link Ext.Layer object}</code></b> : <div class="sub-desc">The specified object will be used
9522 * as the configuration object for the {@link Ext.Layer} that will be created.</div></li>
9526 * @cfg {Boolean/String} shadow
9527 * <code>true</code> (or a valid Ext.Shadow {@link Ext.Shadow#mode} value) to display a shadow behind the
9528 * panel, <code>false</code> to display no shadow (defaults to <code>'sides'</code>). Note that this option
9529 * only applies when <code>{@link #floating} = true</code>.
9532 * @cfg {Number} shadowOffset
9533 * The number of pixels to offset the shadow if displayed (defaults to <code>4</code>). Note that this
9534 * option only applies when <code>{@link #floating} = true</code>.
9537 * @cfg {Boolean} shim
9538 * <code>false</code> to disable the iframe shim in browsers which need one (defaults to <code>true</code>).
9539 * Note that this option only applies when <code>{@link #floating} = true</code>.
9542 * @cfg {Object/Array} keys
9543 * A {@link Ext.KeyMap} config object (in the format expected by {@link Ext.KeyMap#addBinding}
9544 * used to assign custom key handling to this panel (defaults to <code>null</code>).
9547 * @cfg {Boolean/Object} draggable
9548 * <p><code>true</code> to enable dragging of this Panel (defaults to <code>false</code>).</p>
9549 * <p>For custom drag/drop implementations, an <b>Ext.Panel.DD</b> config could also be passed
9550 * in this config instead of <code>true</code>. Ext.Panel.DD is an internal, undocumented class which
9551 * moves a proxy Element around in place of the Panel's element, but provides no other behaviour
9552 * during dragging or on drop. It is a subclass of {@link Ext.dd.DragSource}, so behaviour may be
9553 * added by implementing the interface methods of {@link Ext.dd.DragDrop} e.g.:
9559 renderTo: Ext.getBody(),
9565 // Config option of Ext.Panel.DD class.
9566 // It's a floating Panel, so do not show a placeholder proxy in the original position.
9569 // Called for each mousemove event while dragging the DD object.
9570 onDrag : function(e){
9571 // Record the x,y position of the drag proxy so that we can
9572 // position the Panel at end of drag.
9573 var pel = this.proxy.getEl();
9574 this.x = pel.getLeft(true);
9575 this.y = pel.getTop(true);
9577 // Keep the Shadow aligned if there is one.
9578 var s = this.panel.getEl().shadow;
9580 s.realign(this.x, this.y, pel.getWidth(), pel.getHeight());
9584 // Called on the mouseup event.
9585 endDrag : function(e){
9586 this.panel.setPosition(this.x, this.y);
9593 * @cfg {Boolean} disabled
9594 * Render this panel disabled (default is <code>false</code>). An important note when using the disabled
9595 * config on panels is that IE will often fail to initialize the disabled mask element correectly if
9596 * the panel's layout has not yet completed by the time the Panel is disabled during the render process.
9597 * If you experience this issue, you may need to instead use the {@link #afterlayout} event to initialize
9598 * the disabled state:
9607 single: true // important, as many layouts can occur
9614 * @cfg {Boolean} autoHeight
9615 * <code>true</code> to use height:'auto', <code>false</code> to use fixed height (defaults to <code>false</code>).
9616 * <b>Note</b>: Setting <code>autoHeight: true</code> means that the browser will manage the panel's height
9617 * based on its contents, and that Ext will not manage it at all. If the panel is within a layout that
9618 * manages dimensions (<code>fit</code>, <code>border</code>, etc.) then setting <code>autoHeight: true</code>
9619 * can cause issues with scrolling and will not generally work as expected since the panel will take
9620 * on the height of its contents rather than the height required by the Ext layout.
9625 * @cfg {String} baseCls
9626 * The base CSS class to apply to this panel's element (defaults to <code>'x-panel'</code>).
9627 * <p>Another option available by default is to specify <code>'x-plain'</code> which strips all styling
9628 * except for required attributes for Ext layouts to function (e.g. overflow:hidden).
9629 * See <code>{@link #unstyled}</code> also.</p>
9631 baseCls : 'x-panel',
9633 * @cfg {String} collapsedCls
9634 * A CSS class to add to the panel's element after it has been collapsed (defaults to
9635 * <code>'x-panel-collapsed'</code>).
9637 collapsedCls : 'x-panel-collapsed',
9639 * @cfg {Boolean} maskDisabled
9640 * <code>true</code> to mask the panel when it is {@link #disabled}, <code>false</code> to not mask it (defaults
9641 * to <code>true</code>). Either way, the panel will always tell its contained elements to disable themselves
9642 * when it is disabled, but masking the panel can provide an additional visual cue that the panel is
9645 maskDisabled : true,
9647 * @cfg {Boolean} animCollapse
9648 * <code>true</code> to animate the transition when the panel is collapsed, <code>false</code> to skip the
9649 * animation (defaults to <code>true</code> if the {@link Ext.Fx} class is available, otherwise <code>false</code>).
9651 animCollapse : Ext.enableFx,
9653 * @cfg {Boolean} headerAsText
9654 * <code>true</code> to display the panel <code>{@link #title}</code> in the <code>{@link #header}</code>,
9655 * <code>false</code> to hide it (defaults to <code>true</code>).
9657 headerAsText : true,
9659 * @cfg {String} buttonAlign
9660 * The alignment of any {@link #buttons} added to this panel. Valid values are <code>'right'</code>,
9661 * <code>'left'</code> and <code>'center'</code> (defaults to <code>'right'</code>).
9663 buttonAlign : 'right',
9665 * @cfg {Boolean} collapsed
9666 * <code>true</code> to render the panel collapsed, <code>false</code> to render it expanded (defaults to
9667 * <code>false</code>).
9671 * @cfg {Boolean} collapseFirst
9672 * <code>true</code> to make sure the collapse/expand toggle button always renders first (to the left of)
9673 * any other tools in the panel's title bar, <code>false</code> to render it last (defaults to <code>true</code>).
9675 collapseFirst : true,
9677 * @cfg {Number} minButtonWidth
9678 * Minimum width in pixels of all {@link #buttons} in this panel (defaults to <code>75</code>)
9680 minButtonWidth : 75,
9682 * @cfg {Boolean} unstyled
9683 * Overrides the <code>{@link #baseCls}</code> setting to <code>{@link #baseCls} = 'x-plain'</code> which renders
9684 * the panel unstyled except for required attributes for Ext layouts to function (e.g. overflow:hidden).
9687 * @cfg {String} elements
9688 * A comma-delimited list of panel elements to initialize when the panel is rendered. Normally, this list will be
9689 * generated automatically based on the items added to the panel at config time, but sometimes it might be useful to
9690 * make sure a structural element is rendered even if not specified at config time (for example, you may want
9691 * to add a button or toolbar dynamically after the panel has been rendered). Adding those elements to this
9692 * list will allocate the required placeholders in the panel when it is rendered. Valid values are<div class="mdetail-params"><ul>
9693 * <li><code>header</code></li>
9694 * <li><code>tbar</code> (top bar)</li>
9695 * <li><code>body</code></li>
9696 * <li><code>bbar</code> (bottom bar)</li>
9697 * <li><code>footer</code></li>
9699 * Defaults to '<code>body</code>'.
9703 * @cfg {Boolean} preventBodyReset
9704 * Defaults to <code>false</code>. When set to <code>true</code>, an extra css class <code>'x-panel-normal'</code>
9705 * will be added to the panel's element, effectively applying css styles suggested by the W3C
9706 * (see http://www.w3.org/TR/CSS21/sample.html) to the Panel's <b>body</b> element (not the header,
9709 preventBodyReset : false,
9712 * @cfg {Number/String} padding
9713 * A shortcut for setting a padding style on the body element. The value can either be
9714 * a number to be applied to all sides, or a normal css string describing padding.
9715 * Defaults to <tt>undefined</tt>.
9720 /** @cfg {String} resizeEvent
9721 * The event to listen to for resizing in layouts. Defaults to <tt>'bodyresize'</tt>.
9723 resizeEvent: 'bodyresize',
9725 // protected - these could be used to customize the behavior of the window,
9726 // but changing them would not be useful without further mofifications and
9727 // could lead to unexpected or undesirable results.
9728 toolTarget : 'header',
9729 collapseEl : 'bwrap',
9733 // private, notify box this class will handle heights
9740 collapseDefaults : {
9745 initComponent : function(){
9746 Ext.Panel.superclass.initComponent.call(this);
9751 * Fires after the Panel has been resized.
9752 * @param {Ext.Panel} p the Panel which has been resized.
9753 * @param {Number} width The Panel body's new width.
9754 * @param {Number} height The Panel body's new height.
9758 * @event titlechange
9759 * Fires after the Panel title has been {@link #title set} or {@link #setTitle changed}.
9760 * @param {Ext.Panel} p the Panel which has had its title changed.
9761 * @param {String} The new title.
9766 * Fires after the Panel icon class has been {@link #iconCls set} or {@link #setIconClass changed}.
9767 * @param {Ext.Panel} p the Panel which has had its {@link #iconCls icon class} changed.
9768 * @param {String} The new icon class.
9769 * @param {String} The old icon class.
9774 * Fires after the Panel has been collapsed.
9775 * @param {Ext.Panel} p the Panel that has been collapsed.
9780 * Fires after the Panel has been expanded.
9781 * @param {Ext.Panel} p The Panel that has been expanded.
9785 * @event beforecollapse
9786 * Fires before the Panel is collapsed. A handler can return false to cancel the collapse.
9787 * @param {Ext.Panel} p the Panel being collapsed.
9788 * @param {Boolean} animate True if the collapse is animated, else false.
9792 * @event beforeexpand
9793 * Fires before the Panel is expanded. A handler can return false to cancel the expand.
9794 * @param {Ext.Panel} p The Panel being expanded.
9795 * @param {Boolean} animate True if the expand is animated, else false.
9799 * @event beforeclose
9800 * Fires before the Panel is closed. Note that Panels do not directly support being closed, but some
9801 * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel. This event only
9802 * applies to such subclasses.
9803 * A handler can return false to cancel the close.
9804 * @param {Ext.Panel} p The Panel being closed.
9809 * Fires after the Panel is closed. Note that Panels do not directly support being closed, but some
9810 * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel.
9811 * @param {Ext.Panel} p The Panel that has been closed.
9816 * Fires after the Panel has been visually activated.
9817 * Note that Panels do not directly support being activated, but some Panel subclasses
9818 * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
9819 * activate and deactivate events under the control of the TabPanel.
9820 * @param {Ext.Panel} p The Panel that has been activated.
9825 * Fires after the Panel has been visually deactivated.
9826 * Note that Panels do not directly support being deactivated, but some Panel subclasses
9827 * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
9828 * activate and deactivate events under the control of the TabPanel.
9829 * @param {Ext.Panel} p The Panel that has been deactivated.
9835 this.baseCls = 'x-plain';
9842 this.elements += ',tbar';
9843 this.topToolbar = this.createToolbar(this.tbar);
9848 this.elements += ',bbar';
9849 this.bottomToolbar = this.createToolbar(this.bbar);
9853 if(this.header === true){
9854 this.elements += ',header';
9856 }else if(this.headerCfg || (this.title && this.header !== false)){
9857 this.elements += ',header';
9860 if(this.footerCfg || this.footer === true){
9861 this.elements += ',footer';
9866 this.fbar = this.buttons;
9867 this.buttons = null;
9870 this.createFbar(this.fbar);
9873 this.on('render', this.doAutoLoad, this, {delay:10});
9878 createFbar : function(fbar){
9879 var min = this.minButtonWidth;
9880 this.elements += ',footer';
9881 this.fbar = this.createToolbar(fbar, {
9882 buttonAlign: this.buttonAlign,
9883 toolbarCls: 'x-panel-fbar',
9884 enableOverflow: false,
9885 defaults: function(c){
9887 minWidth: c.minWidth || min
9891 // @compat addButton and buttons could possibly be removed
9894 * This Panel's Array of buttons as created from the <code>{@link #buttons}</code>
9895 * config property. Read only.
9899 this.fbar.items.each(function(c){
9900 c.minWidth = c.minWidth || this.minButtonWidth;
9902 this.buttons = this.fbar.items.items;
9906 createToolbar: function(tb, options){
9908 // Convert array to proper toolbar config
9909 if(Ext.isArray(tb)){
9914 result = tb.events ? Ext.apply(tb, options) : this.createComponent(Ext.apply({}, tb, options), 'toolbar');
9915 this.toolbars.push(result);
9920 createElement : function(name, pnode){
9922 pnode.appendChild(this[name].dom);
9926 if(name === 'bwrap' || this.elements.indexOf(name) != -1){
9927 if(this[name+'Cfg']){
9928 this[name] = Ext.fly(pnode).createChild(this[name+'Cfg']);
9930 var el = document.createElement('div');
9931 el.className = this[name+'Cls'];
9932 this[name] = Ext.get(pnode.appendChild(el));
9934 if(this[name+'CssClass']){
9935 this[name].addClass(this[name+'CssClass']);
9937 if(this[name+'Style']){
9938 this[name].applyStyles(this[name+'Style']);
9944 onRender : function(ct, position){
9945 Ext.Panel.superclass.onRender.call(this, ct, position);
9946 this.createClasses();
9954 if(this.collapsible && !this.hideCollapseTool){
9955 this.tools = this.tools ? this.tools.slice(0) : [];
9956 this.tools[this.collapseFirst?'unshift':'push']({
9958 handler : this.toggleCollapse,
9965 this.elements += (this.header !== false) ? ',header' : '';
9969 el.addClass(this.baseCls);
9970 if(d.firstChild){ // existing markup
9971 this.header = el.down('.'+this.headerCls);
9972 this.bwrap = el.down('.'+this.bwrapCls);
9973 var cp = this.bwrap ? this.bwrap : el;
9974 this.tbar = cp.down('.'+this.tbarCls);
9975 this.body = cp.down('.'+this.bodyCls);
9976 this.bbar = cp.down('.'+this.bbarCls);
9977 this.footer = cp.down('.'+this.footerCls);
9978 this.fromMarkup = true;
9980 if (this.preventBodyReset === true) {
9981 el.addClass('x-panel-reset');
9984 el.addClass(this.cls);
9988 this.elements += ',footer';
9991 // This block allows for maximum flexibility and performance when using existing markup
9993 // framing requires special markup
9995 el.insertHtml('afterBegin', String.format(Ext.Element.boxMarkup, this.baseCls));
9997 this.createElement('header', d.firstChild.firstChild.firstChild);
9998 this.createElement('bwrap', d);
10000 // append the mid and bottom frame to the bwrap
10001 bw = this.bwrap.dom;
10002 var ml = d.childNodes[1], bl = d.childNodes[2];
10003 bw.appendChild(ml);
10004 bw.appendChild(bl);
10006 var mc = bw.firstChild.firstChild.firstChild;
10007 this.createElement('tbar', mc);
10008 this.createElement('body', mc);
10009 this.createElement('bbar', mc);
10010 this.createElement('footer', bw.lastChild.firstChild.firstChild);
10013 this.bwrap.dom.lastChild.className += ' x-panel-nofooter';
10016 * Store a reference to this element so:
10017 * a) We aren't looking it up all the time
10018 * b) The last element is reported incorrectly when using a loadmask
10020 this.ft = Ext.get(this.bwrap.dom.lastChild);
10021 this.mc = Ext.get(mc);
10023 this.createElement('header', d);
10024 this.createElement('bwrap', d);
10026 // append the mid and bottom frame to the bwrap
10027 bw = this.bwrap.dom;
10028 this.createElement('tbar', bw);
10029 this.createElement('body', bw);
10030 this.createElement('bbar', bw);
10031 this.createElement('footer', bw);
10034 this.body.addClass(this.bodyCls + '-noheader');
10036 this.tbar.addClass(this.tbarCls + '-noheader');
10041 if(Ext.isDefined(this.padding)){
10042 this.body.setStyle('padding', this.body.addUnits(this.padding));
10045 if(this.border === false){
10046 this.el.addClass(this.baseCls + '-noborder');
10047 this.body.addClass(this.bodyCls + '-noborder');
10049 this.header.addClass(this.headerCls + '-noborder');
10052 this.footer.addClass(this.footerCls + '-noborder');
10055 this.tbar.addClass(this.tbarCls + '-noborder');
10058 this.bbar.addClass(this.bbarCls + '-noborder');
10062 if(this.bodyBorder === false){
10063 this.body.addClass(this.bodyCls + '-noborder');
10066 this.bwrap.enableDisplayMode('block');
10069 this.header.unselectable();
10071 // for tools, we need to wrap any existing header markup
10072 if(this.headerAsText){
10073 this.header.dom.innerHTML =
10074 '<span class="' + this.headerTextCls + '">'+this.header.dom.innerHTML+'</span>';
10077 this.setIconClass(this.iconCls);
10083 this.makeFloating(this.floating);
10086 if(this.collapsible && this.titleCollapse && this.header){
10087 this.mon(this.header, 'click', this.toggleCollapse, this);
10088 this.header.setStyle('cursor', 'pointer');
10091 this.addTool.apply(this, ts);
10094 // Render Toolbars.
10096 this.footer.addClass('x-panel-btns');
10097 this.fbar.ownerCt = this;
10098 this.fbar.render(this.footer);
10099 this.footer.createChild({cls:'x-clear'});
10101 if(this.tbar && this.topToolbar){
10102 this.topToolbar.ownerCt = this;
10103 this.topToolbar.render(this.tbar);
10105 if(this.bbar && this.bottomToolbar){
10106 this.bottomToolbar.ownerCt = this;
10107 this.bottomToolbar.render(this.bbar);
10112 * Sets the CSS class that provides the icon image for this panel. This method will replace any existing
10113 * icon class if one has already been set and fire the {@link #iconchange} event after completion.
10114 * @param {String} cls The new CSS class name
10116 setIconClass : function(cls){
10117 var old = this.iconCls;
10118 this.iconCls = cls;
10119 if(this.rendered && this.header){
10121 this.header.addClass('x-panel-icon');
10122 this.header.replaceClass(old, this.iconCls);
10124 var hd = this.header,
10125 img = hd.child('img.x-panel-inline-icon');
10127 Ext.fly(img).replaceClass(old, this.iconCls);
10129 var hdspan = hd.child('span.' + this.headerTextCls);
10131 Ext.DomHelper.insertBefore(hdspan.dom, {
10132 tag:'img', src: Ext.BLANK_IMAGE_URL, cls:'x-panel-inline-icon '+this.iconCls
10138 this.fireEvent('iconchange', this, cls, old);
10142 makeFloating : function(cfg){
10143 this.floating = true;
10144 this.el = new Ext.Layer(Ext.apply({}, cfg, {
10145 shadow: Ext.isDefined(this.shadow) ? this.shadow : 'sides',
10146 shadowOffset: this.shadowOffset,
10148 shim: this.shim === false ? false : undefined
10153 * Returns the {@link Ext.Toolbar toolbar} from the top (<code>{@link #tbar}</code>) section of the panel.
10154 * @return {Ext.Toolbar} The toolbar
10156 getTopToolbar : function(){
10157 return this.topToolbar;
10161 * Returns the {@link Ext.Toolbar toolbar} from the bottom (<code>{@link #bbar}</code>) section of the panel.
10162 * @return {Ext.Toolbar} The toolbar
10164 getBottomToolbar : function(){
10165 return this.bottomToolbar;
10169 * Returns the {@link Ext.Toolbar toolbar} from the footer (<code>{@link #fbar}</code>) section of the panel.
10170 * @return {Ext.Toolbar} The toolbar
10172 getFooterToolbar : function() {
10177 * Adds a button to this panel. Note that this method must be called prior to rendering. The preferred
10178 * approach is to add buttons via the {@link #buttons} config.
10179 * @param {String/Object} config A valid {@link Ext.Button} config. A string will become the text for a default
10180 * button config, an object will be treated as a button config object.
10181 * @param {Function} handler The function to be called on button {@link Ext.Button#click}
10182 * @param {Object} scope The scope (<code>this</code> reference) in which the button handler function is executed. Defaults to the Button.
10183 * @return {Ext.Button} The button that was added
10185 addButton : function(config, handler, scope){
10187 this.createFbar([]);
10190 if(Ext.isString(config)){
10191 config = {text: config};
10193 config = Ext.apply({
10198 return this.fbar.add(config);
10202 addTool : function(){
10203 if(!this.rendered){
10207 Ext.each(arguments, function(arg){
10208 this.tools.push(arg);
10212 // nowhere to render tools!
10213 if(!this[this.toolTarget]){
10216 if(!this.toolTemplate){
10217 // initialize the global tool template on first use
10218 var tt = new Ext.Template(
10219 '<div class="x-tool x-tool-{id}"> </div>'
10221 tt.disableFormats = true;
10223 Ext.Panel.prototype.toolTemplate = tt;
10225 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10227 if(!this.tools[tc.id]){
10228 var overCls = 'x-tool-'+tc.id+'-over';
10229 var t = this.toolTemplate.insertFirst(this[this.toolTarget], tc, true);
10230 this.tools[tc.id] = t;
10231 t.enableDisplayMode('block');
10232 this.mon(t, 'click', this.createToolHandler(t, tc, overCls, this));
10234 this.mon(t, tc.on);
10240 if(Ext.isObject(tc.qtip)){
10241 Ext.QuickTips.register(Ext.apply({
10245 t.dom.qtip = tc.qtip;
10248 t.addClassOnOver(overCls);
10253 onLayout : function(shallow, force){
10254 Ext.Panel.superclass.onLayout.apply(this, arguments);
10255 if(this.hasLayout && this.toolbars.length > 0){
10256 Ext.each(this.toolbars, function(tb){
10257 tb.doLayout(undefined, force);
10263 syncHeight : function(){
10264 var h = this.toolbarHeight,
10266 lsh = this.lastSize.height,
10269 if(this.autoHeight || !Ext.isDefined(lsh) || lsh == 'auto'){
10274 if(h != this.getToolbarHeight()){
10275 h = Math.max(0, lsh - this.getFrameHeight());
10278 this.toolbarHeight = this.getToolbarHeight();
10279 this.onBodyResize(sz.width, sz.height);
10284 onShow : function(){
10286 return this.el.show();
10288 Ext.Panel.superclass.onShow.call(this);
10292 onHide : function(){
10294 return this.el.hide();
10296 Ext.Panel.superclass.onHide.call(this);
10300 createToolHandler : function(t, tc, overCls, panel){
10301 return function(e){
10302 t.removeClass(overCls);
10303 if(tc.stopEvent !== false){
10307 tc.handler.call(tc.scope || t, e, t, panel, tc);
10313 afterRender : function(){
10314 if(this.floating && !this.hidden){
10318 this.setTitle(this.title);
10320 Ext.Panel.superclass.afterRender.call(this); // do sizing calcs last
10321 if (this.collapsed) {
10322 this.collapsed = false;
10323 this.collapse(false);
10329 getKeyMap : function(){
10331 this.keyMap = new Ext.KeyMap(this.el, this.keys);
10333 return this.keyMap;
10337 initEvents : function(){
10341 if(this.draggable){
10342 this.initDraggable();
10344 if(this.toolbars.length > 0){
10345 Ext.each(this.toolbars, function(tb){
10349 afterlayout: this.syncHeight,
10350 remove: this.syncHeight
10359 initDraggable : function(){
10361 * <p>If this Panel is configured {@link #draggable}, this property will contain
10362 * an instance of {@link Ext.dd.DragSource} which handles dragging the Panel.</p>
10363 * The developer must provide implementations of the abstract methods of {@link Ext.dd.DragSource}
10364 * in order to supply behaviour for each stage of the drag/drop process. See {@link #draggable}.
10365 * @type Ext.dd.DragSource.
10368 this.dd = new Ext.Panel.DD(this, Ext.isBoolean(this.draggable) ? null : this.draggable);
10372 beforeEffect : function(anim){
10374 this.el.beforeAction();
10376 if(anim !== false){
10377 this.el.addClass('x-panel-animated');
10382 afterEffect : function(anim){
10384 this.el.removeClass('x-panel-animated');
10387 // private - wraps up an animation param with internal callbacks
10388 createEffect : function(a, cb, scope){
10396 }else if(!a.callback){
10398 }else { // wrap it up
10399 o.callback = function(){
10401 Ext.callback(a.callback, a.scope);
10404 return Ext.applyIf(o, a);
10408 * Collapses the panel body so that it becomes hidden. Fires the {@link #beforecollapse} event which will
10409 * cancel the collapse action if it returns false.
10410 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
10411 * {@link #animCollapse} panel config)
10412 * @return {Ext.Panel} this
10414 collapse : function(animate){
10415 if(this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforecollapse', this, animate) === false){
10418 var doAnim = animate === true || (animate !== false && this.animCollapse);
10419 this.beforeEffect(doAnim);
10420 this.onCollapse(doAnim, animate);
10425 onCollapse : function(doAnim, animArg){
10427 this[this.collapseEl].slideOut(this.slideAnchor,
10428 Ext.apply(this.createEffect(animArg||true, this.afterCollapse, this),
10429 this.collapseDefaults));
10431 this[this.collapseEl].hide(this.hideMode);
10432 this.afterCollapse(false);
10437 afterCollapse : function(anim){
10438 this.collapsed = true;
10439 this.el.addClass(this.collapsedCls);
10440 if(anim !== false){
10441 this[this.collapseEl].hide(this.hideMode);
10443 this.afterEffect(anim);
10445 // Reset lastSize of all sub-components so they KNOW they are in a collapsed container
10446 this.cascade(function(c) {
10448 c.lastSize = { width: undefined, height: undefined };
10451 this.fireEvent('collapse', this);
10455 * Expands the panel body so that it becomes visible. Fires the {@link #beforeexpand} event which will
10456 * cancel the expand action if it returns false.
10457 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
10458 * {@link #animCollapse} panel config)
10459 * @return {Ext.Panel} this
10461 expand : function(animate){
10462 if(!this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforeexpand', this, animate) === false){
10465 var doAnim = animate === true || (animate !== false && this.animCollapse);
10466 this.el.removeClass(this.collapsedCls);
10467 this.beforeEffect(doAnim);
10468 this.onExpand(doAnim, animate);
10473 onExpand : function(doAnim, animArg){
10475 this[this.collapseEl].slideIn(this.slideAnchor,
10476 Ext.apply(this.createEffect(animArg||true, this.afterExpand, this),
10477 this.expandDefaults));
10479 this[this.collapseEl].show(this.hideMode);
10480 this.afterExpand(false);
10485 afterExpand : function(anim){
10486 this.collapsed = false;
10487 if(anim !== false){
10488 this[this.collapseEl].show(this.hideMode);
10490 this.afterEffect(anim);
10491 if (this.deferLayout) {
10492 delete this.deferLayout;
10493 this.doLayout(true);
10495 this.fireEvent('expand', this);
10499 * Shortcut for performing an {@link #expand} or {@link #collapse} based on the current state of the panel.
10500 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
10501 * {@link #animCollapse} panel config)
10502 * @return {Ext.Panel} this
10504 toggleCollapse : function(animate){
10505 this[this.collapsed ? 'expand' : 'collapse'](animate);
10510 onDisable : function(){
10511 if(this.rendered && this.maskDisabled){
10514 Ext.Panel.superclass.onDisable.call(this);
10518 onEnable : function(){
10519 if(this.rendered && this.maskDisabled){
10522 Ext.Panel.superclass.onEnable.call(this);
10526 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
10530 if(Ext.isDefined(w) || Ext.isDefined(h)){
10531 if(!this.collapsed){
10532 // First, set the the Panel's body width.
10533 // If we have auto-widthed it, get the resulting full offset width so we can size the Toolbars to match
10534 // The Toolbars must not buffer this resize operation because we need to know their heights.
10536 if(Ext.isNumber(w)){
10537 this.body.setWidth(w = this.adjustBodyWidth(w - this.getFrameWidth()));
10538 } else if (w == 'auto') {
10539 w = this.body.setWidth('auto').dom.offsetWidth;
10541 w = this.body.dom.offsetWidth;
10545 this.tbar.setWidth(w);
10546 if(this.topToolbar){
10547 this.topToolbar.setSize(w);
10551 this.bbar.setWidth(w);
10552 if(this.bottomToolbar){
10553 this.bottomToolbar.setSize(w);
10554 // The bbar does not move on resize without this.
10556 this.bbar.setStyle('position', 'static');
10557 this.bbar.setStyle('position', '');
10562 this.footer.setWidth(w);
10564 this.fbar.setSize(Ext.isIE ? (w - this.footer.getFrameWidth('lr')) : 'auto');
10568 // At this point, the Toolbars must be layed out for getFrameHeight to find a result.
10569 if(Ext.isNumber(h)){
10570 h = Math.max(0, h - this.getFrameHeight());
10571 //h = Math.max(0, h - (this.getHeight() - this.body.getHeight()));
10572 this.body.setHeight(h);
10573 }else if(h == 'auto'){
10574 this.body.setHeight(h);
10577 if(this.disabled && this.el._mask){
10578 this.el._mask.setSize(this.el.dom.clientWidth, this.el.getHeight());
10581 // Adds an event to set the correct height afterExpand. This accounts for the deferHeight flag in panel
10582 this.queuedBodySize = {width: w, height: h};
10583 if(!this.queuedExpand && this.allowQueuedExpand !== false){
10584 this.queuedExpand = true;
10585 this.on('expand', function(){
10586 delete this.queuedExpand;
10587 this.onResize(this.queuedBodySize.width, this.queuedBodySize.height);
10588 }, this, {single:true});
10591 this.onBodyResize(w, h);
10594 Ext.Panel.superclass.onResize.call(this, adjWidth, adjHeight, rawWidth, rawHeight);
10599 onBodyResize: function(w, h){
10600 this.fireEvent('bodyresize', this, w, h);
10604 getToolbarHeight: function(){
10607 Ext.each(this.toolbars, function(tb){
10608 h += tb.getHeight();
10615 adjustBodyHeight : function(h){
10620 adjustBodyWidth : function(w){
10625 onPosition : function(){
10630 * Returns the width in pixels of the framing elements of this panel (not including the body width). To
10631 * retrieve the body width see {@link #getInnerWidth}.
10632 * @return {Number} The frame width
10634 getFrameWidth : function(){
10635 var w = this.el.getFrameWidth('lr') + this.bwrap.getFrameWidth('lr');
10638 var l = this.bwrap.dom.firstChild;
10639 w += (Ext.fly(l).getFrameWidth('l') + Ext.fly(l.firstChild).getFrameWidth('r'));
10640 w += this.mc.getFrameWidth('lr');
10646 * Returns the height in pixels of the framing elements of this panel (including any top and bottom bars and
10647 * header and footer elements, but not including the body height). To retrieve the body height see {@link #getInnerHeight}.
10648 * @return {Number} The frame height
10650 getFrameHeight : function() {
10651 var h = Math.max(0, this.getHeight() - this.body.getHeight());
10659 var h = this.el.getFrameWidth('tb') + this.bwrap.getFrameWidth('tb');
10660 h += (this.tbar ? this.tbar.getHeight() : 0) +
10661 (this.bbar ? this.bbar.getHeight() : 0);
10664 h += this.el.dom.firstChild.offsetHeight + this.ft.dom.offsetHeight + this.mc.getFrameWidth('tb');
10666 h += (this.header ? this.header.getHeight() : 0) +
10667 (this.footer ? this.footer.getHeight() : 0);
10674 * Returns the width in pixels of the body element (not including the width of any framing elements).
10675 * For the frame width see {@link #getFrameWidth}.
10676 * @return {Number} The body width
10678 getInnerWidth : function(){
10679 return this.getSize().width - this.getFrameWidth();
10683 * Returns the height in pixels of the body element (not including the height of any framing elements).
10684 * For the frame height see {@link #getFrameHeight}.
10685 * @return {Number} The body height
10687 getInnerHeight : function(){
10688 return this.body.getHeight();
10690 return this.getSize().height - this.getFrameHeight();
10695 syncShadow : function(){
10697 this.el.sync(true);
10702 getLayoutTarget : function(){
10707 getContentTarget : function(){
10712 * <p>Sets the title text for the panel and optionally the {@link #iconCls icon class}.</p>
10713 * <p>In order to be able to set the title, a header element must have been created
10714 * for the Panel. This is triggered either by configuring the Panel with a non-blank <code>{@link #title}</code>,
10715 * or configuring it with <code><b>{@link #header}: true</b></code>.</p>
10716 * @param {String} title The title text to set
10717 * @param {String} iconCls (optional) {@link #iconCls iconCls} A user-defined CSS class that provides the icon image for this panel
10719 setTitle : function(title, iconCls){
10720 this.title = title;
10721 if(this.header && this.headerAsText){
10722 this.header.child('span').update(title);
10725 this.setIconClass(iconCls);
10727 this.fireEvent('titlechange', this, title);
10732 * Get the {@link Ext.Updater} for this panel. Enables you to perform Ajax updates of this panel's body.
10733 * @return {Ext.Updater} The Updater
10735 getUpdater : function(){
10736 return this.body.getUpdater();
10740 * Loads this content panel immediately with content returned from an XHR call.
10741 * @param {Object/String/Function} config A config object containing any of the following options:
10744 url: 'your-url.php',
10745 params: {param1: 'foo', param2: 'bar'}, // or a URL encoded string
10746 callback: yourFunction,
10747 scope: yourObject, // optional scope for the callback
10750 text: 'Loading...',
10755 * The only required property is url. The optional properties nocache, text and scripts
10756 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their
10757 * associated property on this panel Updater instance.
10758 * @return {Ext.Panel} this
10761 var um = this.body.getUpdater();
10762 um.update.apply(um, arguments);
10767 beforeDestroy : function(){
10768 Ext.Panel.superclass.beforeDestroy.call(this);
10770 this.header.removeAllListeners();
10773 for(var k in this.tools){
10774 Ext.destroy(this.tools[k]);
10777 if(this.toolbars.length > 0){
10778 Ext.each(this.toolbars, function(tb){
10779 tb.un('afterlayout', this.syncHeight, this);
10780 tb.un('remove', this.syncHeight, this);
10783 if(Ext.isArray(this.buttons)){
10784 while(this.buttons.length) {
10785 Ext.destroy(this.buttons[0]);
10807 Ext.destroy(this.toolbars);
10811 createClasses : function(){
10812 this.headerCls = this.baseCls + '-header';
10813 this.headerTextCls = this.baseCls + '-header-text';
10814 this.bwrapCls = this.baseCls + '-bwrap';
10815 this.tbarCls = this.baseCls + '-tbar';
10816 this.bodyCls = this.baseCls + '-body';
10817 this.bbarCls = this.baseCls + '-bbar';
10818 this.footerCls = this.baseCls + '-footer';
10822 createGhost : function(cls, useShim, appendTo){
10823 var el = document.createElement('div');
10824 el.className = 'x-panel-ghost ' + (cls ? cls : '');
10826 el.appendChild(this.el.dom.firstChild.cloneNode(true));
10828 Ext.fly(el.appendChild(document.createElement('ul'))).setHeight(this.bwrap.getHeight());
10829 el.style.width = this.el.dom.offsetWidth + 'px';;
10831 this.container.dom.appendChild(el);
10833 Ext.getDom(appendTo).appendChild(el);
10835 if(useShim !== false && this.el.useShim !== false){
10836 var layer = new Ext.Layer({shadow:false, useDisplay:true, constrain:false}, el);
10840 return new Ext.Element(el);
10845 doAutoLoad : function(){
10846 var u = this.body.getUpdater();
10848 u.setRenderer(this.renderer);
10850 u.update(Ext.isObject(this.autoLoad) ? this.autoLoad : {url: this.autoLoad});
10854 * Retrieve a tool by id.
10855 * @param {String} id
10856 * @return {Object} tool
10858 getTool : function(id) {
10859 return this.tools[id];
10863 * @cfg {String} autoEl @hide
10866 Ext.reg('panel', Ext.Panel);
10868 * @class Ext.Editor
10869 * @extends Ext.Component
10870 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
10872 * Create a new Editor
10873 * @param {Object} config The config object
10876 Ext.Editor = function(field, config){
10878 this.field = Ext.create(field.field, 'textfield');
10879 config = Ext.apply({}, field); // copy so we don't disturb original config
10880 delete config.field;
10882 this.field = field;
10884 Ext.Editor.superclass.constructor.call(this, config);
10887 Ext.extend(Ext.Editor, Ext.Component, {
10889 * @cfg {Ext.form.Field} field
10890 * The Field object (or descendant) or config object for field
10893 * @cfg {Boolean} allowBlur
10894 * True to {@link #completeEdit complete the editing process} if in edit mode when the
10895 * field is blurred. Defaults to <tt>true</tt>.
10899 * @cfg {Boolean/String} autoSize
10900 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
10901 * or "height" to adopt the height only, "none" to always use the field dimensions. (defaults to false)
10904 * @cfg {Boolean} revertInvalid
10905 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
10906 * validation fails (defaults to true)
10909 * @cfg {Boolean} ignoreNoChange
10910 * True to skip the edit completion process (no save, no events fired) if the user completes an edit and
10911 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
10912 * will never be ignored.
10915 * @cfg {Boolean} hideEl
10916 * False to keep the bound element visible while the editor is displayed (defaults to true)
10919 * @cfg {Mixed} value
10920 * The data value of the underlying field (defaults to "")
10924 * @cfg {String} alignment
10925 * The position to align to (see {@link Ext.Element#alignTo} for more details, defaults to "c-c?").
10929 * @cfg {Array} offsets
10930 * The offsets to use when aligning (see {@link Ext.Element#alignTo} for more details. Defaults to <tt>[0, 0]</tt>.
10934 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
10935 * for bottom-right shadow (defaults to "frame")
10939 * @cfg {Boolean} constrain True to constrain the editor to the viewport
10943 * @cfg {Boolean} swallowKeys Handle the keydown/keypress events so they don't propagate (defaults to true)
10945 swallowKeys : true,
10947 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed. Defaults to <tt>true</tt>.
10949 completeOnEnter : true,
10951 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed. Defaults to <tt>true</tt>.
10953 cancelOnEsc : true,
10955 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
10959 initComponent : function(){
10960 Ext.Editor.superclass.initComponent.call(this);
10963 * @event beforestartedit
10964 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
10965 * false from the handler of this event.
10966 * @param {Editor} this
10967 * @param {Ext.Element} boundEl The underlying element bound to this editor
10968 * @param {Mixed} value The field value being set
10973 * Fires when this editor is displayed
10974 * @param {Ext.Element} boundEl The underlying element bound to this editor
10975 * @param {Mixed} value The starting field value
10979 * @event beforecomplete
10980 * Fires after a change has been made to the field, but before the change is reflected in the underlying
10981 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
10982 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
10983 * event will not fire since no edit actually occurred.
10984 * @param {Editor} this
10985 * @param {Mixed} value The current field value
10986 * @param {Mixed} startValue The original field value
10991 * Fires after editing is complete and any changed value has been written to the underlying field.
10992 * @param {Editor} this
10993 * @param {Mixed} value The current field value
10994 * @param {Mixed} startValue The original field value
10998 * @event canceledit
10999 * Fires after editing has been canceled and the editor's value has been reset.
11000 * @param {Editor} this
11001 * @param {Mixed} value The user-entered field value that was discarded
11002 * @param {Mixed} startValue The original field value that was set back into the editor after cancel
11006 * @event specialkey
11007 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
11008 * {@link Ext.EventObject#getKey} to determine which key was pressed.
11009 * @param {Ext.form.Field} this
11010 * @param {Ext.EventObject} e The event object
11017 onRender : function(ct, position){
11018 this.el = new Ext.Layer({
11019 shadow: this.shadow,
11023 shadowOffset: this.shadowOffset || 4,
11025 constrain: this.constrain
11028 this.el.setZIndex(this.zIndex);
11030 this.el.setStyle("overflow", Ext.isGecko ? "auto" : "hidden");
11031 if(this.field.msgTarget != 'title'){
11032 this.field.msgTarget = 'qtip';
11034 this.field.inEditor = true;
11035 this.mon(this.field, {
11038 specialkey: this.onSpecialKey
11040 if(this.field.grow){
11041 this.mon(this.field, "autosize", this.el.sync, this.el, {delay:1});
11043 this.field.render(this.el).show();
11044 this.field.getEl().dom.name = '';
11045 if(this.swallowKeys){
11046 this.field.el.swallowEvent([
11047 'keypress', // *** Opera
11048 'keydown' // *** all other browsers
11054 onSpecialKey : function(field, e){
11055 var key = e.getKey(),
11056 complete = this.completeOnEnter && key == e.ENTER,
11057 cancel = this.cancelOnEsc && key == e.ESC;
11058 if(complete || cancel){
11061 this.completeEdit();
11065 if(field.triggerBlur){
11066 field.triggerBlur();
11069 this.fireEvent('specialkey', field, e);
11073 * Starts the editing process and shows the editor.
11074 * @param {Mixed} el The element to edit
11075 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
11076 * to the innerHTML of el.
11078 startEdit : function(el, value){
11080 this.completeEdit();
11082 this.boundEl = Ext.get(el);
11083 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
11084 if(!this.rendered){
11085 this.render(this.parentEl || document.body);
11087 if(this.fireEvent("beforestartedit", this, this.boundEl, v) !== false){
11088 this.startValue = v;
11089 this.field.reset();
11090 this.field.setValue(v);
11091 this.realign(true);
11092 this.editing = true;
11098 doAutoSize : function(){
11100 var sz = this.boundEl.getSize(),
11101 fs = this.field.getSize();
11103 switch(this.autoSize){
11105 this.setSize(sz.width, fs.height);
11108 this.setSize(fs.width, sz.height);
11111 this.setSize(fs.width, fs.height);
11114 this.setSize(sz.width, sz.height);
11120 * Sets the height and width of this editor.
11121 * @param {Number} width The new width
11122 * @param {Number} height The new height
11124 setSize : function(w, h){
11125 delete this.field.lastSize;
11126 this.field.setSize(w, h);
11128 if(Ext.isGecko2 || Ext.isOpera){
11129 // prevent layer scrollbars
11130 this.el.setSize(w, h);
11137 * Realigns the editor to the bound field based on the current alignment config value.
11138 * @param {Boolean} autoSize (optional) True to size the field to the dimensions of the bound element.
11140 realign : function(autoSize){
11141 if(autoSize === true){
11144 this.el.alignTo(this.boundEl, this.alignment, this.offsets);
11148 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
11149 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
11151 completeEdit : function(remainVisible){
11155 // Assert combo values first
11156 if (this.field.assertValue) {
11157 this.field.assertValue();
11159 var v = this.getValue();
11160 if(!this.field.isValid()){
11161 if(this.revertInvalid !== false){
11162 this.cancelEdit(remainVisible);
11166 if(String(v) === String(this.startValue) && this.ignoreNoChange){
11167 this.hideEdit(remainVisible);
11170 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
11171 v = this.getValue();
11172 if(this.updateEl && this.boundEl){
11173 this.boundEl.update(v);
11175 this.hideEdit(remainVisible);
11176 this.fireEvent("complete", this, v, this.startValue);
11181 onShow : function(){
11183 if(this.hideEl !== false){
11184 this.boundEl.hide();
11186 this.field.show().focus(false, true);
11187 this.fireEvent("startedit", this.boundEl, this.startValue);
11191 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
11192 * reverted to the original starting value.
11193 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
11194 * cancel (defaults to false)
11196 cancelEdit : function(remainVisible){
11198 var v = this.getValue();
11199 this.setValue(this.startValue);
11200 this.hideEdit(remainVisible);
11201 this.fireEvent("canceledit", this, v, this.startValue);
11206 hideEdit: function(remainVisible){
11207 if(remainVisible !== true){
11208 this.editing = false;
11214 onBlur : function(){
11215 // selectSameEditor flag allows the same editor to be started without onBlur firing on itself
11216 if(this.allowBlur === true && this.editing && this.selectSameEditor !== true){
11217 this.completeEdit();
11222 onHide : function(){
11224 this.completeEdit();
11228 if(this.field.collapse){
11229 this.field.collapse();
11232 if(this.hideEl !== false){
11233 this.boundEl.show();
11238 * Sets the data value of the editor
11239 * @param {Mixed} value Any valid value supported by the underlying field
11241 setValue : function(v){
11242 this.field.setValue(v);
11246 * Gets the data value of the editor
11247 * @return {Mixed} The data value
11249 getValue : function(){
11250 return this.field.getValue();
11253 beforeDestroy : function(){
11254 Ext.destroyMembers(this, 'field');
11256 delete this.parentEl;
11257 delete this.boundEl;
11260 Ext.reg('editor', Ext.Editor);
11262 * @class Ext.ColorPalette
11263 * @extends Ext.Component
11264 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
11265 * Here's an example of typical usage:
11267 var cp = new Ext.ColorPalette({value:'993300'}); // initial selected color
11268 cp.render('my-div');
11270 cp.on('select', function(palette, selColor){
11271 // do something with selColor
11275 * Create a new ColorPalette
11276 * @param {Object} config The config object
11277 * @xtype colorpalette
11279 Ext.ColorPalette = Ext.extend(Ext.Component, {
11281 * @cfg {String} tpl An existing XTemplate instance to be used in place of the default template for rendering the component.
11284 * @cfg {String} itemCls
11285 * The CSS class to apply to the containing element (defaults to 'x-color-palette')
11287 itemCls : 'x-color-palette',
11289 * @cfg {String} value
11290 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
11291 * the hex codes are case-sensitive.
11295 * @cfg {String} clickEvent
11296 * The DOM event that will cause a color to be selected. This can be any valid event name (dblclick, contextmenu).
11297 * Defaults to <tt>'click'</tt>.
11299 clickEvent :'click',
11301 ctype : 'Ext.ColorPalette',
11304 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the {@link #select} event
11306 allowReselect : false,
11309 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
11310 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
11311 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
11312 * of colors with the width setting until the box is symmetrical.</p>
11313 * <p>You can override individual colors if needed:</p>
11315 var cp = new Ext.ColorPalette();
11316 cp.colors[0] = 'FF0000'; // change the first box to red
11319 Or you can provide a custom array of your own for complete control:
11321 var cp = new Ext.ColorPalette();
11322 cp.colors = ['000000', '993300', '333300'];
11327 '000000', '993300', '333300', '003300', '003366', '000080', '333399', '333333',
11328 '800000', 'FF6600', '808000', '008000', '008080', '0000FF', '666699', '808080',
11329 'FF0000', 'FF9900', '99CC00', '339966', '33CCCC', '3366FF', '800080', '969696',
11330 'FF00FF', 'FFCC00', 'FFFF00', '00FF00', '00FFFF', '00CCFF', '993366', 'C0C0C0',
11331 'FF99CC', 'FFCC99', 'FFFF99', 'CCFFCC', 'CCFFFF', '99CCFF', 'CC99FF', 'FFFFFF'
11335 * @cfg {Function} handler
11336 * Optional. A function that will handle the select event of this palette.
11337 * The handler is passed the following parameters:<div class="mdetail-params"><ul>
11338 * <li><code>palette</code> : ColorPalette<div class="sub-desc">The {@link #palette Ext.ColorPalette}.</div></li>
11339 * <li><code>color</code> : String<div class="sub-desc">The 6-digit color hex code (without the # symbol).</div></li>
11343 * @cfg {Object} scope
11344 * The scope (<tt><b>this</b></tt> reference) in which the <code>{@link #handler}</code>
11345 * function will be called. Defaults to this ColorPalette instance.
11349 initComponent : function(){
11350 Ext.ColorPalette.superclass.initComponent.call(this);
11354 * Fires when a color is selected
11355 * @param {ColorPalette} this
11356 * @param {String} color The 6-digit color hex code (without the # symbol)
11362 this.on('select', this.handler, this.scope, true);
11367 onRender : function(container, position){
11372 Ext.ColorPalette.superclass.onRender.call(this, container, position);
11373 var t = this.tpl || new Ext.XTemplate(
11374 '<tpl for="."><a href="#" class="color-{.}" hidefocus="on"><em><span style="background:#{.}" unselectable="on"> </span></em></a></tpl>'
11376 t.overwrite(this.el, this.colors);
11377 this.mon(this.el, this.clickEvent, this.handleClick, this, {delegate: 'a'});
11378 if(this.clickEvent != 'click'){
11379 this.mon(this.el, 'click', Ext.emptyFn, this, {delegate: 'a', preventDefault: true});
11384 afterRender : function(){
11385 Ext.ColorPalette.superclass.afterRender.call(this);
11387 var s = this.value;
11389 this.select(s, true);
11394 handleClick : function(e, t){
11395 e.preventDefault();
11396 if(!this.disabled){
11397 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
11398 this.select(c.toUpperCase());
11403 * Selects the specified color in the palette (fires the {@link #select} event)
11404 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
11405 * @param {Boolean} suppressEvent (optional) True to stop the select event from firing. Defaults to <tt>false</tt>.
11407 select : function(color, suppressEvent){
11408 color = color.replace('#', '');
11409 if(color != this.value || this.allowReselect){
11412 el.child('a.color-'+this.value).removeClass('x-color-palette-sel');
11414 el.child('a.color-'+color).addClass('x-color-palette-sel');
11415 this.value = color;
11416 if(suppressEvent !== true){
11417 this.fireEvent('select', this, color);
11423 * @cfg {String} autoEl @hide
11426 Ext.reg('colorpalette', Ext.ColorPalette);/**
11427 * @class Ext.DatePicker
11428 * @extends Ext.Component
11429 * <p>A popup date picker. This class is used by the {@link Ext.form.DateField DateField} class
11430 * to allow browsing and selection of valid dates.</p>
11431 * <p>All the string values documented below may be overridden by including an Ext locale file in
11434 * Create a new DatePicker
11435 * @param {Object} config The config object
11436 * @xtype datepicker
11438 Ext.DatePicker = Ext.extend(Ext.BoxComponent, {
11440 * @cfg {String} todayText
11441 * The text to display on the button that selects the current date (defaults to <code>'Today'</code>)
11443 todayText : 'Today',
11445 * @cfg {String} okText
11446 * The text to display on the ok button (defaults to <code>' OK '</code> to give the user extra clicking room)
11448 okText : ' OK ',
11450 * @cfg {String} cancelText
11451 * The text to display on the cancel button (defaults to <code>'Cancel'</code>)
11453 cancelText : 'Cancel',
11455 * @cfg {Function} handler
11456 * Optional. A function that will handle the select event of this picker.
11457 * The handler is passed the following parameters:<div class="mdetail-params"><ul>
11458 * <li><code>picker</code> : DatePicker<div class="sub-desc">This DatePicker.</div></li>
11459 * <li><code>date</code> : Date<div class="sub-desc">The selected date.</div></li>
11463 * @cfg {Object} scope
11464 * The scope (<code><b>this</b></code> reference) in which the <code>{@link #handler}</code>
11465 * function will be called. Defaults to this DatePicker instance.
11468 * @cfg {String} todayTip
11469 * A string used to format the message for displaying in a tooltip over the button that
11470 * selects the current date. Defaults to <code>'{0} (Spacebar)'</code> where
11471 * the <code>{0}</code> token is replaced by today's date.
11473 todayTip : '{0} (Spacebar)',
11475 * @cfg {String} minText
11476 * The error text to display if the minDate validation fails (defaults to <code>'This date is before the minimum date'</code>)
11478 minText : 'This date is before the minimum date',
11480 * @cfg {String} maxText
11481 * The error text to display if the maxDate validation fails (defaults to <code>'This date is after the maximum date'</code>)
11483 maxText : 'This date is after the maximum date',
11485 * @cfg {String} format
11486 * The default date format string which can be overriden for localization support. The format must be
11487 * valid according to {@link Date#parseDate} (defaults to <code>'m/d/y'</code>).
11491 * @cfg {String} disabledDaysText
11492 * The tooltip to display when the date falls on a disabled day (defaults to <code>'Disabled'</code>)
11494 disabledDaysText : 'Disabled',
11496 * @cfg {String} disabledDatesText
11497 * The tooltip text to display when the date falls on a disabled date (defaults to <code>'Disabled'</code>)
11499 disabledDatesText : 'Disabled',
11501 * @cfg {Array} monthNames
11502 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
11504 monthNames : Date.monthNames,
11506 * @cfg {Array} dayNames
11507 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
11509 dayNames : Date.dayNames,
11511 * @cfg {String} nextText
11512 * The next month navigation button tooltip (defaults to <code>'Next Month (Control+Right)'</code>)
11514 nextText : 'Next Month (Control+Right)',
11516 * @cfg {String} prevText
11517 * The previous month navigation button tooltip (defaults to <code>'Previous Month (Control+Left)'</code>)
11519 prevText : 'Previous Month (Control+Left)',
11521 * @cfg {String} monthYearText
11522 * The header month selector tooltip (defaults to <code>'Choose a month (Control+Up/Down to move years)'</code>)
11524 monthYearText : 'Choose a month (Control+Up/Down to move years)',
11526 * @cfg {Number} startDay
11527 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
11531 * @cfg {Boolean} showToday
11532 * False to hide the footer area containing the Today button and disable the keyboard handler for spacebar
11533 * that selects the current date (defaults to <code>true</code>).
11537 * @cfg {Date} minDate
11538 * Minimum allowable date (JavaScript date object, defaults to null)
11541 * @cfg {Date} maxDate
11542 * Maximum allowable date (JavaScript date object, defaults to null)
11545 * @cfg {Array} disabledDays
11546 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
11549 * @cfg {RegExp} disabledDatesRE
11550 * JavaScript regular expression used to disable a pattern of dates (defaults to null). The {@link #disabledDates}
11551 * config will generate this regex internally, but if you specify disabledDatesRE it will take precedence over the
11552 * disabledDates value.
11555 * @cfg {Array} disabledDates
11556 * An array of 'dates' to disable, as strings. These strings will be used to build a dynamic regular
11557 * expression so they are very powerful. Some examples:
11559 * <li>['03/08/2003', '09/16/2003'] would disable those exact dates</li>
11560 * <li>['03/08', '09/16'] would disable those days for every year</li>
11561 * <li>['^03/08'] would only match the beginning (useful if you are using short years)</li>
11562 * <li>['03/../2006'] would disable every day in March 2006</li>
11563 * <li>['^03'] would disable every day in every March</li>
11565 * Note that the format of the dates included in the array should exactly match the {@link #format} config.
11566 * In order to support regular expressions, if you are using a date format that has '.' in it, you will have to
11567 * escape the dot when restricting dates. For example: ['03\\.08\\.03'].
11571 // Set by other components to stop the picker focus being updated when the value changes.
11572 focusOnSelect: true,
11574 // default value used to initialise each date in the DatePicker
11575 // (note: 12 noon was chosen because it steers well clear of all DST timezone changes)
11576 initHour: 12, // 24-hour format
11579 initComponent : function(){
11580 Ext.DatePicker.superclass.initComponent.call(this);
11582 this.value = this.value ?
11583 this.value.clearTime(true) : new Date().clearTime();
11588 * Fires when a date is selected
11589 * @param {DatePicker} this DatePicker
11590 * @param {Date} date The selected date
11596 this.on('select', this.handler, this.scope || this);
11599 this.initDisabledDays();
11603 initDisabledDays : function(){
11604 if(!this.disabledDatesRE && this.disabledDates){
11605 var dd = this.disabledDates,
11606 len = dd.length - 1,
11609 Ext.each(dd, function(d, i){
11610 re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i];
11615 this.disabledDatesRE = new RegExp(re + ')');
11620 * Replaces any existing disabled dates with new values and refreshes the DatePicker.
11621 * @param {Array/RegExp} disabledDates An array of date strings (see the {@link #disabledDates} config
11622 * for details on supported values), or a JavaScript regular expression used to disable a pattern of dates.
11624 setDisabledDates : function(dd){
11625 if(Ext.isArray(dd)){
11626 this.disabledDates = dd;
11627 this.disabledDatesRE = null;
11629 this.disabledDatesRE = dd;
11631 this.initDisabledDays();
11632 this.update(this.value, true);
11636 * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.
11637 * @param {Array} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config
11638 * for details on supported values.
11640 setDisabledDays : function(dd){
11641 this.disabledDays = dd;
11642 this.update(this.value, true);
11646 * Replaces any existing {@link #minDate} with the new value and refreshes the DatePicker.
11647 * @param {Date} value The minimum date that can be selected
11649 setMinDate : function(dt){
11651 this.update(this.value, true);
11655 * Replaces any existing {@link #maxDate} with the new value and refreshes the DatePicker.
11656 * @param {Date} value The maximum date that can be selected
11658 setMaxDate : function(dt){
11660 this.update(this.value, true);
11664 * Sets the value of the date field
11665 * @param {Date} value The date to set
11667 setValue : function(value){
11668 this.value = value.clearTime(true);
11669 this.update(this.value);
11673 * Gets the current selected value of the date field
11674 * @return {Date} The selected date
11676 getValue : function(){
11681 focus : function(){
11682 this.update(this.activeDate);
11686 onEnable: function(initial){
11687 Ext.DatePicker.superclass.onEnable.call(this);
11688 this.doDisabled(false);
11689 this.update(initial ? this.value : this.activeDate);
11697 onDisable : function(){
11698 Ext.DatePicker.superclass.onDisable.call(this);
11699 this.doDisabled(true);
11700 if(Ext.isIE && !Ext.isIE8){
11701 /* Really strange problem in IE6/7, when disabled, have to explicitly
11702 * repaint each of the nodes to get them to display correctly, simply
11703 * calling repaint on the main element doesn't appear to be enough.
11705 Ext.each([].concat(this.textNodes, this.el.query('th span')), function(el){
11706 Ext.fly(el).repaint();
11712 doDisabled : function(disabled){
11713 this.keyNav.setDisabled(disabled);
11714 this.prevRepeater.setDisabled(disabled);
11715 this.nextRepeater.setDisabled(disabled);
11716 if(this.showToday){
11717 this.todayKeyListener.setDisabled(disabled);
11718 this.todayBtn.setDisabled(disabled);
11723 onRender : function(container, position){
11725 '<table cellspacing="0">',
11726 '<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>',
11727 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'],
11728 dn = this.dayNames,
11730 for(i = 0; i < 7; i++){
11731 var d = this.startDay+i;
11735 m.push('<th><span>', dn[d].substr(0,1), '</span></th>');
11737 m[m.length] = '</tr></thead><tbody><tr>';
11738 for(i = 0; i < 42; i++) {
11739 if(i % 7 === 0 && i !== 0){
11740 m[m.length] = '</tr><tr>';
11742 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
11744 m.push('</tr></tbody></table></td></tr>',
11745 this.showToday ? '<tr><td colspan="3" class="x-date-bottom" align="center"></td></tr>' : '',
11746 '</table><div class="x-date-mp"></div>');
11748 var el = document.createElement('div');
11749 el.className = 'x-date-picker';
11750 el.innerHTML = m.join('');
11752 container.dom.insertBefore(el, position);
11754 this.el = Ext.get(el);
11755 this.eventEl = Ext.get(el.firstChild);
11757 this.prevRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-left a'), {
11758 handler: this.showPrevMonth,
11760 preventDefault:true,
11764 this.nextRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-right a'), {
11765 handler: this.showNextMonth,
11767 preventDefault:true,
11771 this.monthPicker = this.el.down('div.x-date-mp');
11772 this.monthPicker.enableDisplayMode('block');
11774 this.keyNav = new Ext.KeyNav(this.eventEl, {
11775 'left' : function(e){
11777 this.showPrevMonth();
11779 this.update(this.activeDate.add('d', -1));
11783 'right' : function(e){
11785 this.showNextMonth();
11787 this.update(this.activeDate.add('d', 1));
11791 'up' : function(e){
11793 this.showNextYear();
11795 this.update(this.activeDate.add('d', -7));
11799 'down' : function(e){
11801 this.showPrevYear();
11803 this.update(this.activeDate.add('d', 7));
11807 'pageUp' : function(e){
11808 this.showNextMonth();
11811 'pageDown' : function(e){
11812 this.showPrevMonth();
11815 'enter' : function(e){
11816 e.stopPropagation();
11823 this.el.unselectable();
11825 this.cells = this.el.select('table.x-date-inner tbody td');
11826 this.textNodes = this.el.query('table.x-date-inner tbody span');
11828 this.mbtn = new Ext.Button({
11830 tooltip: this.monthYearText,
11831 renderTo: this.el.child('td.x-date-middle', true)
11833 this.mbtn.el.child('em').addClass('x-btn-arrow');
11835 if(this.showToday){
11836 this.todayKeyListener = this.eventEl.addKeyListener(Ext.EventObject.SPACE, this.selectToday, this);
11837 var today = (new Date()).dateFormat(this.format);
11838 this.todayBtn = new Ext.Button({
11839 renderTo: this.el.child('td.x-date-bottom', true),
11840 text: String.format(this.todayText, today),
11841 tooltip: String.format(this.todayTip, today),
11842 handler: this.selectToday,
11846 this.mon(this.eventEl, 'mousewheel', this.handleMouseWheel, this);
11847 this.mon(this.eventEl, 'click', this.handleDateClick, this, {delegate: 'a.x-date-date'});
11848 this.mon(this.mbtn, 'click', this.showMonthPicker, this);
11849 this.onEnable(true);
11853 createMonthPicker : function(){
11854 if(!this.monthPicker.dom.firstChild){
11855 var buf = ['<table border="0" cellspacing="0">'];
11856 for(var i = 0; i < 6; i++){
11858 '<tr><td class="x-date-mp-month"><a href="#">', Date.getShortMonthName(i), '</a></td>',
11859 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', Date.getShortMonthName(i + 6), '</a></td>',
11861 '<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>' :
11862 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
11866 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
11868 '</button><button type="button" class="x-date-mp-cancel">',
11870 '</button></td></tr>',
11873 this.monthPicker.update(buf.join(''));
11875 this.mon(this.monthPicker, 'click', this.onMonthClick, this);
11876 this.mon(this.monthPicker, 'dblclick', this.onMonthDblClick, this);
11878 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
11879 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
11881 this.mpMonths.each(function(m, a, i){
11884 m.dom.xmonth = 5 + Math.round(i * 0.5);
11886 m.dom.xmonth = Math.round((i-1) * 0.5);
11893 showMonthPicker : function(){
11894 if(!this.disabled){
11895 this.createMonthPicker();
11896 var size = this.el.getSize();
11897 this.monthPicker.setSize(size);
11898 this.monthPicker.child('table').setSize(size);
11900 this.mpSelMonth = (this.activeDate || this.value).getMonth();
11901 this.updateMPMonth(this.mpSelMonth);
11902 this.mpSelYear = (this.activeDate || this.value).getFullYear();
11903 this.updateMPYear(this.mpSelYear);
11905 this.monthPicker.slideIn('t', {duration:0.2});
11910 updateMPYear : function(y){
11912 var ys = this.mpYears.elements;
11913 for(var i = 1; i <= 10; i++){
11914 var td = ys[i-1], y2;
11916 y2 = y + Math.round(i * 0.5);
11917 td.firstChild.innerHTML = y2;
11920 y2 = y - (5-Math.round(i * 0.5));
11921 td.firstChild.innerHTML = y2;
11924 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
11929 updateMPMonth : function(sm){
11930 this.mpMonths.each(function(m, a, i){
11931 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
11936 selectMPMonth : function(m){
11941 onMonthClick : function(e, t){
11943 var el = new Ext.Element(t), pn;
11944 if(el.is('button.x-date-mp-cancel')){
11945 this.hideMonthPicker();
11947 else if(el.is('button.x-date-mp-ok')){
11948 var d = new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate());
11949 if(d.getMonth() != this.mpSelMonth){
11950 // 'fix' the JS rolling date conversion if needed
11951 d = new Date(this.mpSelYear, this.mpSelMonth, 1).getLastDateOfMonth();
11954 this.hideMonthPicker();
11956 else if((pn = el.up('td.x-date-mp-month', 2))){
11957 this.mpMonths.removeClass('x-date-mp-sel');
11958 pn.addClass('x-date-mp-sel');
11959 this.mpSelMonth = pn.dom.xmonth;
11961 else if((pn = el.up('td.x-date-mp-year', 2))){
11962 this.mpYears.removeClass('x-date-mp-sel');
11963 pn.addClass('x-date-mp-sel');
11964 this.mpSelYear = pn.dom.xyear;
11966 else if(el.is('a.x-date-mp-prev')){
11967 this.updateMPYear(this.mpyear-10);
11969 else if(el.is('a.x-date-mp-next')){
11970 this.updateMPYear(this.mpyear+10);
11975 onMonthDblClick : function(e, t){
11977 var el = new Ext.Element(t), pn;
11978 if((pn = el.up('td.x-date-mp-month', 2))){
11979 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
11980 this.hideMonthPicker();
11982 else if((pn = el.up('td.x-date-mp-year', 2))){
11983 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
11984 this.hideMonthPicker();
11989 hideMonthPicker : function(disableAnim){
11990 if(this.monthPicker){
11991 if(disableAnim === true){
11992 this.monthPicker.hide();
11994 this.monthPicker.slideOut('t', {duration:0.2});
12000 showPrevMonth : function(e){
12001 this.update(this.activeDate.add('mo', -1));
12005 showNextMonth : function(e){
12006 this.update(this.activeDate.add('mo', 1));
12010 showPrevYear : function(){
12011 this.update(this.activeDate.add('y', -1));
12015 showNextYear : function(){
12016 this.update(this.activeDate.add('y', 1));
12020 handleMouseWheel : function(e){
12022 if(!this.disabled){
12023 var delta = e.getWheelDelta();
12025 this.showPrevMonth();
12026 } else if(delta < 0){
12027 this.showNextMonth();
12033 handleDateClick : function(e, t){
12035 if(!this.disabled && t.dateValue && !Ext.fly(t.parentNode).hasClass('x-date-disabled')){
12036 this.cancelFocus = this.focusOnSelect === false;
12037 this.setValue(new Date(t.dateValue));
12038 delete this.cancelFocus;
12039 this.fireEvent('select', this, this.value);
12044 selectToday : function(){
12045 if(this.todayBtn && !this.todayBtn.disabled){
12046 this.setValue(new Date().clearTime());
12047 this.fireEvent('select', this, this.value);
12052 update : function(date, forceRefresh){
12054 var vd = this.activeDate, vis = this.isVisible();
12055 this.activeDate = date;
12056 if(!forceRefresh && vd && this.el){
12057 var t = date.getTime();
12058 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12059 this.cells.removeClass('x-date-selected');
12060 this.cells.each(function(c){
12061 if(c.dom.firstChild.dateValue == t){
12062 c.addClass('x-date-selected');
12063 if(vis && !this.cancelFocus){
12064 Ext.fly(c.dom.firstChild).focus(50);
12072 var days = date.getDaysInMonth(),
12073 firstOfMonth = date.getFirstDateOfMonth(),
12074 startingPos = firstOfMonth.getDay()-this.startDay;
12076 if(startingPos < 0){
12079 days += startingPos;
12081 var pm = date.add('mo', -1),
12082 prevStart = pm.getDaysInMonth()-startingPos,
12083 cells = this.cells.elements,
12084 textEls = this.textNodes,
12085 // convert everything to numbers so it's fast
12086 d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart, this.initHour)),
12087 today = new Date().clearTime().getTime(),
12088 sel = date.clearTime(true).getTime(),
12089 min = this.minDate ? this.minDate.clearTime(true) : Number.NEGATIVE_INFINITY,
12090 max = this.maxDate ? this.maxDate.clearTime(true) : Number.POSITIVE_INFINITY,
12091 ddMatch = this.disabledDatesRE,
12092 ddText = this.disabledDatesText,
12093 ddays = this.disabledDays ? this.disabledDays.join('') : false,
12094 ddaysText = this.disabledDaysText,
12095 format = this.format;
12097 if(this.showToday){
12098 var td = new Date().clearTime(),
12099 disable = (td < min || td > max ||
12100 (ddMatch && format && ddMatch.test(td.dateFormat(format))) ||
12101 (ddays && ddays.indexOf(td.getDay()) != -1));
12103 if(!this.disabled){
12104 this.todayBtn.setDisabled(disable);
12105 this.todayKeyListener[disable ? 'disable' : 'enable']();
12109 var setCellClass = function(cal, cell){
12111 var t = d.clearTime(true).getTime();
12112 cell.firstChild.dateValue = t;
12114 cell.className += ' x-date-today';
12115 cell.title = cal.todayText;
12118 cell.className += ' x-date-selected';
12120 Ext.fly(cell.firstChild).focus(50);
12125 cell.className = ' x-date-disabled';
12126 cell.title = cal.minText;
12130 cell.className = ' x-date-disabled';
12131 cell.title = cal.maxText;
12135 if(ddays.indexOf(d.getDay()) != -1){
12136 cell.title = ddaysText;
12137 cell.className = ' x-date-disabled';
12140 if(ddMatch && format){
12141 var fvalue = d.dateFormat(format);
12142 if(ddMatch.test(fvalue)){
12143 cell.title = ddText.replace('%0', fvalue);
12144 cell.className = ' x-date-disabled';
12150 for(; i < startingPos; i++) {
12151 textEls[i].innerHTML = (++prevStart);
12152 d.setDate(d.getDate()+1);
12153 cells[i].className = 'x-date-prevday';
12154 setCellClass(this, cells[i]);
12156 for(; i < days; i++){
12157 var intDay = i - startingPos + 1;
12158 textEls[i].innerHTML = (intDay);
12159 d.setDate(d.getDate()+1);
12160 cells[i].className = 'x-date-active';
12161 setCellClass(this, cells[i]);
12164 for(; i < 42; i++) {
12165 textEls[i].innerHTML = (++extraDays);
12166 d.setDate(d.getDate()+1);
12167 cells[i].className = 'x-date-nextday';
12168 setCellClass(this, cells[i]);
12171 this.mbtn.setText(this.monthNames[date.getMonth()] + ' ' + date.getFullYear());
12173 if(!this.internalRender){
12174 var main = this.el.dom.firstChild,
12175 w = main.offsetWidth;
12176 this.el.setWidth(w + this.el.getBorderWidth('lr'));
12177 Ext.fly(main).setWidth(w);
12178 this.internalRender = true;
12179 // opera does not respect the auto grow header center column
12180 // then, after it gets a width opera refuses to recalculate
12181 // without a second pass
12182 if(Ext.isOpera && !this.secondPass){
12183 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + 'px';
12184 this.secondPass = true;
12185 this.update.defer(10, this, [date]);
12192 beforeDestroy : function() {
12204 delete this.textNodes;
12205 delete this.cells.elements;
12210 * @cfg {String} autoEl @hide
12214 Ext.reg('datepicker', Ext.DatePicker);
12216 * @class Ext.LoadMask
12217 * A simple utility class for generically masking elements while loading data. If the {@link #store}
12218 * config option is specified, the masking will be automatically synchronized with the store's loading
12219 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
12220 * element's Updater load indicator and will be destroyed after the initial load.
12221 * <p>Example usage:</p>
12224 var myMask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait..."});
12228 * Create a new LoadMask
12229 * @param {Mixed} el The element or DOM node, or its id
12230 * @param {Object} config The config object
12232 Ext.LoadMask = function(el, config){
12233 this.el = Ext.get(el);
12234 Ext.apply(this, config);
12238 beforeload: this.onBeforeLoad,
12240 exception: this.onLoad
12242 this.removeMask = Ext.value(this.removeMask, false);
12244 var um = this.el.getUpdater();
12245 um.showLoadIndicator = false; // disable the default indicator
12248 beforeupdate: this.onBeforeLoad,
12249 update: this.onLoad,
12250 failure: this.onLoad
12252 this.removeMask = Ext.value(this.removeMask, true);
12256 Ext.LoadMask.prototype = {
12258 * @cfg {Ext.data.Store} store
12259 * Optional Store to which the mask is bound. The mask is displayed when a load request is issued, and
12260 * hidden on either load sucess, or load fail.
12263 * @cfg {Boolean} removeMask
12264 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
12265 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
12268 * @cfg {String} msg
12269 * The text to display in a centered loading message box (defaults to 'Loading...')
12271 msg : 'Loading...',
12273 * @cfg {String} msgCls
12274 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
12276 msgCls : 'x-mask-loading',
12279 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
12285 * Disables the mask to prevent it from being displayed
12287 disable : function(){
12288 this.disabled = true;
12292 * Enables the mask so that it can be displayed
12294 enable : function(){
12295 this.disabled = false;
12299 onLoad : function(){
12300 this.el.unmask(this.removeMask);
12304 onBeforeLoad : function(){
12305 if(!this.disabled){
12306 this.el.mask(this.msg, this.msgCls);
12311 * Show this LoadMask over the configured Element.
12314 this.onBeforeLoad();
12318 * Hide this LoadMask.
12325 destroy : function(){
12327 this.store.un('beforeload', this.onBeforeLoad, this);
12328 this.store.un('load', this.onLoad, this);
12329 this.store.un('exception', this.onLoad, this);
12331 var um = this.el.getUpdater();
12332 um.un('beforeupdate', this.onBeforeLoad, this);
12333 um.un('update', this.onLoad, this);
12334 um.un('failure', this.onLoad, this);
12337 };Ext.ns('Ext.slider');
12340 * @class Ext.slider.Thumb
12342 * Represents a single thumb element on a Slider. This would not usually be created manually and would instead
12343 * be created internally by an {@link Ext.slider.MultiSlider Ext.Slider}.
12345 Ext.slider.Thumb = Ext.extend(Object, {
12349 * @cfg {Ext.slider.MultiSlider} slider The Slider to render to (required)
12351 constructor: function(config) {
12354 * @type Ext.slider.MultiSlider
12355 * The slider this thumb is contained within
12357 Ext.apply(this, config || {}, {
12358 cls: 'x-slider-thumb',
12361 * @cfg {Boolean} constrain True to constrain the thumb so that it cannot overlap its siblings
12366 Ext.slider.Thumb.superclass.constructor.call(this, config);
12368 if (this.slider.vertical) {
12369 Ext.apply(this, Ext.slider.Thumb.Vertical);
12374 * Renders the thumb into a slider
12376 render: function() {
12377 this.el = this.slider.innerEl.insertFirst({cls: this.cls});
12383 * Enables the thumb if it is currently disabled
12385 enable: function() {
12386 this.disabled = false;
12387 this.el.removeClass(this.slider.disabledClass);
12391 * Disables the thumb if it is currently enabled
12393 disable: function() {
12394 this.disabled = true;
12395 this.el.addClass(this.slider.disabledClass);
12399 * Sets up an Ext.dd.DragTracker for this thumb
12401 initEvents: function() {
12404 el.addClassOnOver('x-slider-thumb-over');
12406 this.tracker = new Ext.dd.DragTracker({
12407 onBeforeStart: this.onBeforeDragStart.createDelegate(this),
12408 onStart : this.onDragStart.createDelegate(this),
12409 onDrag : this.onDrag.createDelegate(this),
12410 onEnd : this.onDragEnd.createDelegate(this),
12415 this.tracker.initEl(el);
12420 * This is tied into the internal Ext.dd.DragTracker. If the slider is currently disabled,
12421 * this returns false to disable the DragTracker too.
12422 * @return {Boolean} False if the slider is currently disabled
12424 onBeforeDragStart : function(e) {
12425 if (this.disabled) {
12428 this.slider.promoteThumb(this);
12435 * This is tied into the internal Ext.dd.DragTracker's onStart template method. Adds the drag CSS class
12436 * to the thumb and fires the 'dragstart' event
12438 onDragStart: function(e){
12439 this.el.addClass('x-slider-thumb-drag');
12440 this.dragging = true;
12441 this.dragStartValue = this.value;
12443 this.slider.fireEvent('dragstart', this.slider, e, this);
12448 * This is tied into the internal Ext.dd.DragTracker's onDrag template method. This is called every time
12449 * the DragTracker detects a drag movement. It updates the Slider's value using the position of the drag
12451 onDrag: function(e) {
12452 var slider = this.slider,
12453 index = this.index,
12454 newValue = this.getNewValue();
12456 if (this.constrain) {
12457 var above = slider.thumbs[index + 1],
12458 below = slider.thumbs[index - 1];
12460 if (below != undefined && newValue <= below.value) newValue = below.value;
12461 if (above != undefined && newValue >= above.value) newValue = above.value;
12464 slider.setValue(index, newValue, false);
12465 slider.fireEvent('drag', slider, e, this);
12468 getNewValue: function() {
12469 var slider = this.slider,
12470 pos = slider.innerEl.translatePoints(this.tracker.getXY());
12472 return Ext.util.Format.round(slider.reverseValue(pos.left), slider.decimalPrecision);
12477 * This is tied to the internal Ext.dd.DragTracker's onEnd template method. Removes the drag CSS class and
12478 * fires the 'changecomplete' event with the new value
12480 onDragEnd: function(e) {
12481 var slider = this.slider,
12482 value = this.value;
12484 this.el.removeClass('x-slider-thumb-drag');
12486 this.dragging = false;
12487 slider.fireEvent('dragend', slider, e);
12489 if (this.dragStartValue != value) {
12490 slider.fireEvent('changecomplete', slider, value, this);
12496 * @class Ext.slider.MultiSlider
12497 * @extends Ext.BoxComponent
12498 * 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:
12501 renderTo: Ext.getBody(),
12509 * Sliders can be created with more than one thumb handle by passing an array of values instead of a single one:
12512 renderTo: Ext.getBody(),
12514 values: [25, 50, 75],
12518 //this defaults to true, setting to false allows the thumbs to pass each other
12519 {@link #constrainThumbs}: false
12523 Ext.slider.MultiSlider = Ext.extend(Ext.BoxComponent, {
12525 * @cfg {Number} value The value to initialize the slider with. Defaults to minValue.
12528 * @cfg {Boolean} vertical Orient the Slider vertically rather than horizontally, defaults to false.
12532 * @cfg {Number} minValue The minimum value for the Slider. Defaults to 0.
12536 * @cfg {Number} maxValue The maximum value for the Slider. Defaults to 100.
12540 * @cfg {Number/Boolean} decimalPrecision.
12541 * <p>The number of decimal places to which to round the Slider's value. Defaults to 0.</p>
12542 * <p>To disable rounding, configure as <tt><b>false</b></tt>.</p>
12544 decimalPrecision: 0,
12546 * @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.
12550 * @cfg {Number} increment How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'.
12556 * @property clickRange
12558 * 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],
12559 * 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'
12560 * 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
12562 clickRange: [5,15],
12565 * @cfg {Boolean} clickToChange Determines whether or not clicking on the Slider axis will change the slider. Defaults to true
12567 clickToChange : true,
12569 * @cfg {Boolean} animate Turn on or off animation. Defaults to true
12574 * True while the thumb is in a drag operation
12580 * @cfg {Boolean} constrainThumbs True to disallow thumbs from overlapping one another. Defaults to true
12582 constrainThumbs: true,
12586 * @property topThumbZIndex
12588 * The number used internally to set the z index of the top thumb (see promoteThumb for details)
12590 topThumbZIndex: 10000,
12592 // private override
12593 initComponent : function(){
12594 if(!Ext.isDefined(this.value)){
12595 this.value = this.minValue;
12601 * Array containing references to each thumb
12605 Ext.slider.MultiSlider.superclass.initComponent.call(this);
12607 this.keyIncrement = Math.max(this.increment, this.keyIncrement);
12610 * @event beforechange
12611 * Fires before the slider value is changed. By returning false from an event handler,
12612 * you can cancel the event and prevent the slider from changing.
12613 * @param {Ext.Slider} slider The slider
12614 * @param {Number} newValue The new value which the slider is being changed to.
12615 * @param {Number} oldValue The old value which the slider was previously.
12621 * Fires when the slider value is changed.
12622 * @param {Ext.Slider} slider The slider
12623 * @param {Number} newValue The new value which the slider has been changed to.
12624 * @param {Ext.slider.Thumb} thumb The thumb that was changed
12629 * @event changecomplete
12630 * Fires when the slider value is changed by the user and any drag operations have completed.
12631 * @param {Ext.Slider} slider The slider
12632 * @param {Number} newValue The new value which the slider has been changed to.
12633 * @param {Ext.slider.Thumb} thumb The thumb that was changed
12639 * Fires after a drag operation has started.
12640 * @param {Ext.Slider} slider The slider
12641 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
12647 * Fires continuously during the drag operation while the mouse is moving.
12648 * @param {Ext.Slider} slider The slider
12649 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
12655 * Fires after the drag operation has completed.
12656 * @param {Ext.Slider} slider The slider
12657 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
12665 * Array of values to initalize the thumbs with
12667 if (this.values == undefined || Ext.isEmpty(this.values)) this.values = [0];
12669 var values = this.values;
12671 for (var i=0; i < values.length; i++) {
12672 this.addThumb(values[i]);
12676 Ext.apply(this, Ext.slider.Vertical);
12681 * Creates a new thumb and adds it to the slider
12682 * @param {Number} value The initial value to set on the thumb. Defaults to 0
12684 addThumb: function(value) {
12685 var thumb = new Ext.slider.Thumb({
12688 index : this.thumbs.length,
12689 constrain: this.constrainThumbs
12691 this.thumbs.push(thumb);
12693 //render the thumb now if needed
12694 if (this.rendered) thumb.render();
12699 * Moves the given thumb above all other by increasing its z-index. This is called when as drag
12700 * any thumb, so that the thumb that was just dragged is always at the highest z-index. This is
12701 * required when the thumbs are stacked on top of each other at one of the ends of the slider's
12702 * range, which can result in the user not being able to move any of them.
12703 * @param {Ext.slider.Thumb} topThumb The thumb to move to the top
12705 promoteThumb: function(topThumb) {
12706 var thumbs = this.thumbs,
12709 for (var i = 0, j = thumbs.length; i < j; i++) {
12712 if (thumb == topThumb) {
12713 zIndex = this.topThumbZIndex;
12718 thumb.el.setStyle('zIndex', zIndex);
12722 // private override
12723 onRender : function() {
12725 cls: 'x-slider ' + (this.vertical ? 'x-slider-vert' : 'x-slider-horz'),
12727 cls: 'x-slider-end',
12729 cls:'x-slider-inner',
12730 cn : [{tag:'a', cls:'x-slider-focus', href:"#", tabIndex: '-1', hidefocus:'on'}]
12735 Ext.slider.MultiSlider.superclass.onRender.apply(this, arguments);
12737 this.endEl = this.el.first();
12738 this.innerEl = this.endEl.first();
12739 this.focusEl = this.innerEl.child('.x-slider-focus');
12741 //render each thumb
12742 for (var i=0; i < this.thumbs.length; i++) {
12743 this.thumbs[i].render();
12746 //calculate the size of half a thumb
12747 var thumb = this.innerEl.child('.x-slider-thumb');
12748 this.halfThumb = (this.vertical ? thumb.getHeight() : thumb.getWidth()) / 2;
12755 * Adds keyboard and mouse listeners on this.el. Ignores click events on the internal focus element.
12756 * Creates a new DragTracker which is used to control what happens when the user drags the thumb around.
12758 initEvents : function(){
12759 this.mon(this.el, {
12761 mousedown: this.onMouseDown,
12762 keydown : this.onKeyDown
12765 this.focusEl.swallowEvent("click", true);
12770 * Mousedown handler for the slider. If the clickToChange is enabled and the click was not on the draggable 'thumb',
12771 * this calculates the new value of the slider and tells the implementation (Horizontal or Vertical) to move the thumb
12772 * @param {Ext.EventObject} e The click event
12774 onMouseDown : function(e){
12779 //see if the click was on any of the thumbs
12780 var thumbClicked = false;
12781 for (var i=0; i < this.thumbs.length; i++) {
12782 thumbClicked = thumbClicked || e.target == this.thumbs[i].el.dom;
12785 if (this.clickToChange && !thumbClicked) {
12786 var local = this.innerEl.translatePoints(e.getXY());
12787 this.onClickChange(local);
12794 * Moves the thumb to the indicated position. Note that a Vertical implementation is provided in Ext.slider.Vertical.
12795 * Only changes the value if the click was within this.clickRange.
12796 * @param {Object} local Object containing top and left values for the click event.
12798 onClickChange : function(local) {
12799 if (local.top > this.clickRange[0] && local.top < this.clickRange[1]) {
12800 //find the nearest thumb to the click event
12801 var thumb = this.getNearest(local, 'left'),
12802 index = thumb.index;
12804 this.setValue(index, Ext.util.Format.round(this.reverseValue(local.left), this.decimalPrecision), undefined, true);
12810 * Returns the nearest thumb to a click event, along with its distance
12811 * @param {Object} local Object containing top and left values from a click event
12812 * @param {String} prop The property of local to compare on. Use 'left' for horizontal sliders, 'top' for vertical ones
12813 * @return {Object} The closest thumb object and its distance from the click event
12815 getNearest: function(local, prop) {
12816 var localValue = prop == 'top' ? this.innerEl.getHeight() - local[prop] : local[prop],
12817 clickValue = this.reverseValue(localValue),
12818 nearestDistance = (this.maxValue - this.minValue) + 5, //add a small fudge for the end of the slider
12822 for (var i=0; i < this.thumbs.length; i++) {
12823 var thumb = this.thumbs[i],
12824 value = thumb.value,
12825 dist = Math.abs(value - clickValue);
12827 if (Math.abs(dist <= nearestDistance)) {
12830 nearestDistance = dist;
12838 * Handler for any keypresses captured by the slider. If the key is UP or RIGHT, the thumb is moved along to the right
12839 * by this.keyIncrement. If DOWN or LEFT it is moved left. Pressing CTRL moves the slider to the end in either direction
12840 * @param {Ext.EventObject} e The Event object
12842 onKeyDown : function(e){
12844 * The behaviour for keyboard handling with multiple thumbs is currently undefined.
12845 * There's no real sane default for it, so leave it like this until we come up
12846 * with a better way of doing it.
12848 if(this.disabled || this.thumbs.length !== 1){
12849 e.preventDefault();
12852 var k = e.getKey(),
12858 val = e.ctrlKey ? this.maxValue : this.getValue(0) + this.keyIncrement;
12859 this.setValue(0, val, undefined, true);
12864 val = e.ctrlKey ? this.minValue : this.getValue(0) - this.keyIncrement;
12865 this.setValue(0, val, undefined, true);
12868 e.preventDefault();
12874 * If using snapping, this takes a desired new value and returns the closest snapped
12876 * @param {Number} value The unsnapped value
12877 * @return {Number} The value of the nearest snap target
12879 doSnap : function(value){
12880 if (!(this.increment && value)) {
12883 var newValue = value,
12884 inc = this.increment,
12888 if (m * 2 >= inc) {
12890 } else if (m * 2 < -inc) {
12894 return newValue.constrain(this.minValue, this.maxValue);
12898 afterRender : function(){
12899 Ext.slider.MultiSlider.superclass.afterRender.apply(this, arguments);
12901 for (var i=0; i < this.thumbs.length; i++) {
12902 var thumb = this.thumbs[i];
12904 if (thumb.value !== undefined) {
12905 var v = this.normalizeValue(thumb.value);
12907 if (v !== thumb.value) {
12908 // delete this.value;
12909 this.setValue(i, v, false);
12911 this.moveThumb(i, this.translateValue(v), false);
12919 * Returns the ratio of pixels to mapped values. e.g. if the slider is 200px wide and maxValue - minValue is 100,
12921 * @return {Number} The ratio of pixels to mapped values
12923 getRatio : function(){
12924 var w = this.innerEl.getWidth(),
12925 v = this.maxValue - this.minValue;
12926 return v == 0 ? w : (w/v);
12931 * Returns a snapped, constrained value when given a desired value
12932 * @param {Number} value Raw number value
12933 * @return {Number} The raw value rounded to the correct d.p. and constrained within the set max and min values
12935 normalizeValue : function(v){
12936 v = this.doSnap(v);
12937 v = Ext.util.Format.round(v, this.decimalPrecision);
12938 v = v.constrain(this.minValue, this.maxValue);
12943 * Sets the minimum value for the slider instance. If the current value is less than the
12944 * minimum value, the current value will be changed.
12945 * @param {Number} val The new minimum value
12947 setMinValue : function(val){
12948 this.minValue = val;
12950 thumbs = this.thumbs,
12951 len = thumbs.length,
12954 for(; i < len; ++i){
12956 t.value = t.value < val ? val : t.value;
12962 * Sets the maximum value for the slider instance. If the current value is more than the
12963 * maximum value, the current value will be changed.
12964 * @param {Number} val The new maximum value
12966 setMaxValue : function(val){
12967 this.maxValue = val;
12969 thumbs = this.thumbs,
12970 len = thumbs.length,
12973 for(; i < len; ++i){
12975 t.value = t.value > val ? val : t.value;
12981 * Programmatically sets the value of the Slider. Ensures that the value is constrained within
12982 * the minValue and maxValue.
12983 * @param {Number} index Index of the thumb to move
12984 * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
12985 * @param {Boolean} animate Turn on or off animation, defaults to true
12987 setValue : function(index, v, animate, changeComplete) {
12988 var thumb = this.thumbs[index],
12991 v = this.normalizeValue(v);
12993 if (v !== thumb.value && this.fireEvent('beforechange', this, v, thumb.value, thumb) !== false) {
12996 this.moveThumb(index, this.translateValue(v), animate !== false);
12997 this.fireEvent('change', this, v, thumb);
12998 if(changeComplete){
12999 this.fireEvent('changecomplete', this, v, thumb);
13008 translateValue : function(v) {
13009 var ratio = this.getRatio();
13010 return (v * ratio) - (this.minValue * ratio) - this.halfThumb;
13015 * Given a pixel location along the slider, returns the mapped slider value for that pixel.
13016 * E.g. if we have a slider 200px wide with minValue = 100 and maxValue = 500, reverseValue(50)
13018 * @param {Number} pos The position along the slider to return a mapped value for
13019 * @return {Number} The mapped value for the given position
13021 reverseValue : function(pos){
13022 var ratio = this.getRatio();
13023 return (pos + (this.minValue * ratio)) / ratio;
13028 * @param {Number} index Index of the thumb to move
13030 moveThumb: function(index, v, animate){
13031 var thumb = this.thumbs[index].el;
13033 if(!animate || this.animate === false){
13036 thumb.shift({left: v, stopFx: true, duration:.35});
13041 focus : function(){
13042 this.focusEl.focus(10);
13046 onResize : function(w, h){
13047 var thumbs = this.thumbs,
13048 len = thumbs.length,
13052 * If we happen to be animating during a resize, the position of the thumb will likely be off
13053 * when the animation stops. As such, just stop any animations before syncing the thumbs.
13055 for(; i < len; ++i){
13056 thumbs[i].el.stopFx();
13058 this.innerEl.setWidth(w - (this.el.getPadding('l') + this.endEl.getPadding('r')));
13060 Ext.slider.MultiSlider.superclass.onResize.apply(this, arguments);
13064 onDisable: function(){
13065 Ext.slider.MultiSlider.superclass.onDisable.call(this);
13067 for (var i=0; i < this.thumbs.length; i++) {
13068 var thumb = this.thumbs[i],
13074 //IE breaks when using overflow visible and opacity other than 1.
13075 //Create a place holder for the thumb and display it.
13076 var xy = el.getXY();
13079 this.innerEl.addClass(this.disabledClass).dom.disabled = true;
13081 if (!this.thumbHolder) {
13082 this.thumbHolder = this.endEl.createChild({cls: 'x-slider-thumb ' + this.disabledClass});
13085 this.thumbHolder.show().setXY(xy);
13091 onEnable: function(){
13092 Ext.slider.MultiSlider.superclass.onEnable.call(this);
13094 for (var i=0; i < this.thumbs.length; i++) {
13095 var thumb = this.thumbs[i],
13101 this.innerEl.removeClass(this.disabledClass).dom.disabled = false;
13103 if (this.thumbHolder) this.thumbHolder.hide();
13112 * Synchronizes the thumb position to the proper proportion of the total component width based
13113 * on the current slider {@link #value}. This will be called automatically when the Slider
13114 * is resized by a layout, but if it is rendered auto width, this method can be called from
13115 * another resize handler to sync the Slider if necessary.
13117 syncThumb : function() {
13118 if (this.rendered) {
13119 for (var i=0; i < this.thumbs.length; i++) {
13120 this.moveThumb(i, this.translateValue(this.thumbs[i].value));
13126 * Returns the current value of the slider
13127 * @param {Number} index The index of the thumb to return a value for
13128 * @return {Number} The current value of the slider
13130 getValue : function(index) {
13131 return this.thumbs[index].value;
13135 * Returns an array of values - one for the location of each thumb
13136 * @return {Array} The set of thumb values
13138 getValues: function() {
13141 for (var i=0; i < this.thumbs.length; i++) {
13142 values.push(this.thumbs[i].value);
13149 beforeDestroy : function(){
13150 Ext.destroyMembers(this, 'endEl', 'innerEl', 'thumb', 'halfThumb', 'focusEl', 'tracker', 'thumbHolder');
13151 Ext.slider.MultiSlider.superclass.beforeDestroy.call(this);
13155 Ext.reg('multislider', Ext.slider.MultiSlider);
13158 * @class Ext.slider.SingleSlider
13159 * @extends Ext.slider.MultiSlider
13160 * Slider which supports vertical or horizontal orientation, keyboard adjustments,
13161 * configurable snapping, axis clicking and animation. Can be added as an item to
13162 * any container. Example usage:
13164 new Ext.slider.SingleSlider({
13165 renderTo: Ext.getBody(),
13173 * The class Ext.slider.SingleSlider is aliased to Ext.Slider for backwards compatibility.
13175 Ext.slider.SingleSlider = Ext.extend(Ext.slider.MultiSlider, {
13176 constructor: function(config) {
13177 config = config || {};
13179 Ext.applyIf(config, {
13180 values: [config.value || 0]
13183 Ext.slider.SingleSlider.superclass.constructor.call(this, config);
13187 * Returns the current value of the slider
13188 * @return {Number} The current value of the slider
13190 getValue: function() {
13191 //just returns the value of the first thumb, which should be the only one in a single slider
13192 return Ext.slider.SingleSlider.superclass.getValue.call(this, 0);
13196 * Programmatically sets the value of the Slider. Ensures that the value is constrained within
13197 * the minValue and maxValue.
13198 * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
13199 * @param {Boolean} animate Turn on or off animation, defaults to true
13201 setValue: function(value, animate) {
13202 var args = Ext.toArray(arguments),
13205 //this is to maintain backwards compatiblity for sliders with only one thunb. Usually you must pass the thumb
13206 //index to setValue, but if we only have one thumb we inject the index here first if given the multi-slider
13207 //signature without the required index. The index will always be 0 for a single slider
13208 if (len == 1 || (len <= 3 && typeof arguments[1] != 'number')) {
13212 return Ext.slider.SingleSlider.superclass.setValue.apply(this, args);
13216 * Synchronizes the thumb position to the proper proportion of the total component width based
13217 * on the current slider {@link #value}. This will be called automatically when the Slider
13218 * is resized by a layout, but if it is rendered auto width, this method can be called from
13219 * another resize handler to sync the Slider if necessary.
13221 syncThumb : function() {
13222 return Ext.slider.SingleSlider.superclass.syncThumb.apply(this, [0].concat(arguments));
13226 getNearest : function(){
13227 // Since there's only 1 thumb, it's always the nearest
13228 return this.thumbs[0];
13232 //backwards compatibility
13233 Ext.Slider = Ext.slider.SingleSlider;
13235 Ext.reg('slider', Ext.slider.SingleSlider);
13237 // private class to support vertical sliders
13238 Ext.slider.Vertical = {
13239 onResize : function(w, h){
13240 this.innerEl.setHeight(h - (this.el.getPadding('t') + this.endEl.getPadding('b')));
13244 getRatio : function(){
13245 var h = this.innerEl.getHeight(),
13246 v = this.maxValue - this.minValue;
13250 moveThumb: function(index, v, animate) {
13251 var thumb = this.thumbs[index],
13254 if (!animate || this.animate === false) {
13257 el.shift({bottom: v, stopFx: true, duration:.35});
13261 onClickChange : function(local) {
13262 if (local.left > this.clickRange[0] && local.left < this.clickRange[1]) {
13263 var thumb = this.getNearest(local, 'top'),
13264 index = thumb.index,
13265 value = this.minValue + this.reverseValue(this.innerEl.getHeight() - local.top);
13267 this.setValue(index, Ext.util.Format.round(value, this.decimalPrecision), undefined, true);
13272 //private class to support vertical dragging of thumbs within a slider
13273 Ext.slider.Thumb.Vertical = {
13274 getNewValue: function() {
13275 var slider = this.slider,
13276 innerEl = slider.innerEl,
13277 pos = innerEl.translatePoints(this.tracker.getXY()),
13278 bottom = innerEl.getHeight() - pos.top;
13280 return slider.minValue + Ext.util.Format.round(bottom / slider.getRatio(), slider.decimalPrecision);
13284 * @class Ext.ProgressBar
13285 * @extends Ext.BoxComponent
13286 * <p>An updateable progress bar component. The progress bar supports two different modes: manual and automatic.</p>
13287 * <p>In manual mode, you are responsible for showing, updating (via {@link #updateProgress}) and clearing the
13288 * progress bar as needed from your own code. This method is most appropriate when you want to show progress
13289 * throughout an operation that has predictable points of interest at which you can update the control.</p>
13290 * <p>In automatic mode, you simply call {@link #wait} and let the progress bar run indefinitely, only clearing it
13291 * once the operation is complete. You can optionally have the progress bar wait for a specific amount of time
13292 * and then clear itself. Automatic mode is most appropriate for timed operations or asynchronous operations in
13293 * which you have no need for indicating intermediate progress.</p>
13294 * @cfg {Float} value A floating point value between 0 and 1 (e.g., .5, defaults to 0)
13295 * @cfg {String} text The progress bar text (defaults to '')
13296 * @cfg {Mixed} textEl The element to render the progress text to (defaults to the progress
13297 * bar's internal text element)
13298 * @cfg {String} id The progress bar element's id (defaults to an auto-generated id)
13301 Ext.ProgressBar = Ext.extend(Ext.BoxComponent, {
13303 * @cfg {String} baseCls
13304 * The base CSS class to apply to the progress bar's wrapper element (defaults to 'x-progress')
13306 baseCls : 'x-progress',
13309 * @cfg {Boolean} animate
13310 * True to animate the progress bar during transitions (defaults to false)
13318 initComponent : function(){
13319 Ext.ProgressBar.superclass.initComponent.call(this);
13323 * Fires after each update interval
13324 * @param {Ext.ProgressBar} this
13325 * @param {Number} The current progress value
13326 * @param {String} The current progress text
13333 onRender : function(ct, position){
13334 var tpl = new Ext.Template(
13335 '<div class="{cls}-wrap">',
13336 '<div class="{cls}-inner">',
13337 '<div class="{cls}-bar">',
13338 '<div class="{cls}-text">',
13339 '<div> </div>',
13342 '<div class="{cls}-text {cls}-text-back">',
13343 '<div> </div>',
13349 this.el = position ? tpl.insertBefore(position, {cls: this.baseCls}, true)
13350 : tpl.append(ct, {cls: this.baseCls}, true);
13353 this.el.dom.id = this.id;
13355 var inner = this.el.dom.firstChild;
13356 this.progressBar = Ext.get(inner.firstChild);
13359 //use an external text el
13360 this.textEl = Ext.get(this.textEl);
13361 delete this.textTopEl;
13363 //setup our internal layered text els
13364 this.textTopEl = Ext.get(this.progressBar.dom.firstChild);
13365 var textBackEl = Ext.get(inner.childNodes[1]);
13366 this.textTopEl.setStyle("z-index", 99).addClass('x-hidden');
13367 this.textEl = new Ext.CompositeElement([this.textTopEl.dom.firstChild, textBackEl.dom.firstChild]);
13368 this.textEl.setWidth(inner.offsetWidth);
13370 this.progressBar.setHeight(inner.offsetHeight);
13374 afterRender : function(){
13375 Ext.ProgressBar.superclass.afterRender.call(this);
13377 this.updateProgress(this.value, this.text);
13379 this.updateText(this.text);
13384 * Updates the progress bar value, and optionally its text. If the text argument is not specified,
13385 * any existing text value will be unchanged. To blank out existing text, pass ''. Note that even
13386 * if the progress bar value exceeds 1, it will never automatically reset -- you are responsible for
13387 * determining when the progress is complete and calling {@link #reset} to clear and/or hide the control.
13388 * @param {Float} value (optional) A floating point value between 0 and 1 (e.g., .5, defaults to 0)
13389 * @param {String} text (optional) The string to display in the progress text element (defaults to '')
13390 * @param {Boolean} animate (optional) Whether to animate the transition of the progress bar. If this value is
13391 * not specified, the default for the class is used (default to false)
13392 * @return {Ext.ProgressBar} this
13394 updateProgress : function(value, text, animate){
13395 this.value = value || 0;
13397 this.updateText(text);
13399 if(this.rendered && !this.isDestroyed){
13400 var w = Math.floor(value*this.el.dom.firstChild.offsetWidth);
13401 this.progressBar.setWidth(w, animate === true || (animate !== false && this.animate));
13402 if(this.textTopEl){
13403 //textTopEl should be the same width as the bar so overflow will clip as the bar moves
13404 this.textTopEl.removeClass('x-hidden').setWidth(w);
13407 this.fireEvent('update', this, value, text);
13412 * Initiates an auto-updating progress bar. A duration can be specified, in which case the progress
13413 * bar will automatically reset after a fixed amount of time and optionally call a callback function
13414 * if specified. If no duration is passed in, then the progress bar will run indefinitely and must
13415 * be manually cleared by calling {@link #reset}. The wait method accepts a config object with
13416 * the following properties:
13418 Property Type Description
13419 ---------- ------------ ----------------------------------------------------------------------
13420 duration Number The length of time in milliseconds that the progress bar should
13421 run before resetting itself (defaults to undefined, in which case it
13422 will run indefinitely until reset is called)
13423 interval Number The length of time in milliseconds between each progress update
13424 (defaults to 1000 ms)
13425 animate Boolean Whether to animate the transition of the progress bar. If this value is
13426 not specified, the default for the class is used.
13427 increment Number The number of progress update segments to display within the progress
13428 bar (defaults to 10). If the bar reaches the end and is still
13429 updating, it will automatically wrap back to the beginning.
13430 text String Optional text to display in the progress bar element (defaults to '').
13431 fn Function A callback function to execute after the progress bar finishes auto-
13432 updating. The function will be called with no arguments. This function
13433 will be ignored if duration is not specified since in that case the
13434 progress bar can only be stopped programmatically, so any required function
13435 should be called by the same code after it resets the progress bar.
13436 scope Object The scope that is passed to the callback function (only applies when
13437 duration and fn are both passed).
13442 var p = new Ext.ProgressBar({
13446 //Wait for 5 seconds, then update the status el (progress bar will auto-reset)
13448 interval: 100, //bar will move fast!
13451 text: 'Updating...',
13454 Ext.fly('status').update('Done!');
13458 //Or update indefinitely until some async action completes, then reset manually
13460 myAction.on('complete', function(){
13462 Ext.fly('status').update('Done!');
13465 * @param {Object} config (optional) Configuration options
13466 * @return {Ext.ProgressBar} this
13468 wait : function(o){
13469 if(!this.waitTimer){
13472 this.updateText(o.text);
13473 this.waitTimer = Ext.TaskMgr.start({
13475 var inc = o.increment || 10;
13477 this.updateProgress(((((i+inc)%inc)+1)*(100/inc))*0.01, null, o.animate);
13479 interval: o.interval || 1000,
13480 duration: o.duration,
13481 onStop: function(){
13483 o.fn.apply(o.scope || this);
13494 * Returns true if the progress bar is currently in a {@link #wait} operation
13495 * @return {Boolean} True if waiting, else false
13497 isWaiting : function(){
13498 return this.waitTimer !== null;
13502 * Updates the progress bar text. If specified, textEl will be updated, otherwise the progress
13503 * bar itself will display the updated text.
13504 * @param {String} text (optional) The string to display in the progress text element (defaults to '')
13505 * @return {Ext.ProgressBar} this
13507 updateText : function(text){
13508 this.text = text || ' ';
13510 this.textEl.update(this.text);
13516 * Synchronizes the inner bar width to the proper proportion of the total componet width based
13517 * on the current progress {@link #value}. This will be called automatically when the ProgressBar
13518 * is resized by a layout, but if it is rendered auto width, this method can be called from
13519 * another resize handler to sync the ProgressBar if necessary.
13521 syncProgressBar : function(){
13523 this.updateProgress(this.value, this.text);
13529 * Sets the size of the progress bar.
13530 * @param {Number} width The new width in pixels
13531 * @param {Number} height The new height in pixels
13532 * @return {Ext.ProgressBar} this
13534 setSize : function(w, h){
13535 Ext.ProgressBar.superclass.setSize.call(this, w, h);
13536 if(this.textTopEl){
13537 var inner = this.el.dom.firstChild;
13538 this.textEl.setSize(inner.offsetWidth, inner.offsetHeight);
13540 this.syncProgressBar();
13545 * Resets the progress bar value to 0 and text to empty string. If hide = true, the progress
13546 * bar will also be hidden (using the {@link #hideMode} property internally).
13547 * @param {Boolean} hide (optional) True to hide the progress bar (defaults to false)
13548 * @return {Ext.ProgressBar} this
13550 reset : function(hide){
13551 this.updateProgress(0);
13552 if(this.textTopEl){
13553 this.textTopEl.addClass('x-hidden');
13563 clearTimer : function(){
13564 if(this.waitTimer){
13565 this.waitTimer.onStop = null; //prevent recursion
13566 Ext.TaskMgr.stop(this.waitTimer);
13567 this.waitTimer = null;
13571 onDestroy: function(){
13574 if(this.textEl.isComposite){
13575 this.textEl.clear();
13577 Ext.destroyMembers(this, 'textEl', 'progressBar', 'textTopEl');
13579 Ext.ProgressBar.superclass.onDestroy.call(this);
13582 Ext.reg('progress', Ext.ProgressBar);