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);
4328 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;
4632 * We can only lay out if there is a view area in which to layout.
4633 * display:none on the layout target, *or any of its parent elements* will mean it has no view area.
4637 canLayout : function() {
4638 var el = this.getVisibilityEl();
4639 return el && el.dom && !el.isStyle("display", "none");
4643 * Force this container's layout to be recalculated. A call to this function is required after adding a new component
4644 * to an already rendered container, or possibly after changing sizing/position properties of child components.
4645 * @param {Boolean} shallow (optional) True to only calc the layout of this component, and let child components auto
4646 * calc layouts as required (defaults to false, which calls doLayout recursively for each subcontainer)
4647 * @param {Boolean} force (optional) True to force a layout to occur, even if the item is hidden.
4648 * @return {Ext.Container} this
4651 doLayout : function(shallow, force){
4652 var rendered = this.rendered,
4653 forceLayout = force || this.forceLayout;
4655 if(this.collapsed || !this.canLayout()){
4656 this.deferLayout = this.deferLayout || !shallow;
4660 shallow = shallow && !this.deferLayout;
4662 delete this.deferLayout;
4664 if(rendered && this.layout){
4665 this.layout.layout();
4667 if(shallow !== true && this.items){
4668 var cs = this.items.items;
4669 for(var i = 0, len = cs.length; i < len; i++){
4672 c.doLayout(false, forceLayout);
4677 this.onLayout(shallow, forceLayout);
4679 // Initial layout completed
4680 this.hasLayout = true;
4681 delete this.forceLayout;
4684 onLayout : Ext.emptyFn,
4687 shouldBufferLayout: function(){
4689 * Returns true if the container should buffer a layout.
4690 * This is true only if the container has previously been laid out
4691 * and has a parent container that is pending a layout.
4693 var hl = this.hasLayout;
4695 // Only ever buffer if we've laid out the first time and we have one pending.
4696 return hl ? !this.hasLayoutPending() : false;
4698 // Never buffer initial layout
4703 hasLayoutPending: function(){
4704 // Traverse hierarchy to see if any parent container has a pending layout.
4705 var pending = false;
4706 this.ownerCt.bubble(function(c){
4707 if(c.layoutPending){
4715 onShow : function(){
4716 // removes css classes that were added to hide
4717 Ext.Container.superclass.onShow.call(this);
4718 // If we were sized during the time we were hidden, layout.
4719 if(Ext.isDefined(this.deferLayout)){
4720 delete this.deferLayout;
4721 this.doLayout(true);
4726 * Returns the layout currently in use by the container. If the container does not currently have a layout
4727 * set, a default {@link Ext.layout.ContainerLayout} will be created and set as the container's layout.
4728 * @return {ContainerLayout} layout The container's layout
4730 getLayout : function(){
4732 var layout = new Ext.layout.AutoLayout(this.layoutConfig);
4733 this.setLayout(layout);
4739 beforeDestroy : function(){
4742 while(c = this.items.first()){
4743 this.doRemove(c, true);
4746 if(this.monitorResize){
4747 Ext.EventManager.removeResizeListener(this.doLayout, this);
4749 Ext.destroy(this.layout);
4750 Ext.Container.superclass.beforeDestroy.call(this);
4754 * Bubbles up the component/container heirarchy, calling the specified function with each component. The scope (<i>this</i>) of
4755 * function call will be the scope provided or the current component. The arguments to the function
4756 * will be the args provided or the current component. If the function returns false at any point,
4757 * the bubble is stopped.
4758 * @param {Function} fn The function to call
4759 * @param {Object} scope (optional) The scope of the function (defaults to current node)
4760 * @param {Array} args (optional) The args to call the function with (default to passing the current component)
4761 * @return {Ext.Container} this
4763 bubble : function(fn, scope, args){
4766 if(fn.apply(scope || p, args || [p]) === false){
4775 * Cascades down the component/container heirarchy from this component (called first), calling the specified function with
4776 * each component. The scope (<i>this</i>) of
4777 * function call will be the scope provided or the current component. The arguments to the function
4778 * will be the args provided or the current component. If the function returns false at any point,
4779 * the cascade is stopped on that branch.
4780 * @param {Function} fn The function to call
4781 * @param {Object} scope (optional) The scope of the function (defaults to current component)
4782 * @param {Array} args (optional) The args to call the function with (defaults to passing the current component)
4783 * @return {Ext.Container} this
4785 cascade : function(fn, scope, args){
4786 if(fn.apply(scope || this, args || [this]) !== false){
4788 var cs = this.items.items;
4789 for(var i = 0, len = cs.length; i < len; i++){
4791 cs[i].cascade(fn, scope, args);
4793 fn.apply(scope || cs[i], args || [cs[i]]);
4802 * Find a component under this container at any level by id
4803 * @param {String} id
4804 * @return Ext.Component
4806 findById : function(id){
4808 this.cascade(function(c){
4809 if(ct != c && c.id === id){
4818 * Find a component under this container at any level by xtype or class
4819 * @param {String/Class} xtype The xtype string for a component, or the class of the component directly
4820 * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
4821 * the default), or true to check whether this Component is directly of the specified xtype.
4822 * @return {Array} Array of Ext.Components
4824 findByType : function(xtype, shallow){
4825 return this.findBy(function(c){
4826 return c.isXType(xtype, shallow);
4831 * Find a component under this container at any level by property
4832 * @param {String} prop
4833 * @param {String} value
4834 * @return {Array} Array of Ext.Components
4836 find : function(prop, value){
4837 return this.findBy(function(c){
4838 return c[prop] === value;
4843 * Find a component under this container at any level by a custom function. If the passed function returns
4844 * true, the component will be included in the results. The passed function is called with the arguments (component, this container).
4845 * @param {Function} fn The function to call
4846 * @param {Object} scope (optional)
4847 * @return {Array} Array of Ext.Components
4849 findBy : function(fn, scope){
4850 var m = [], ct = this;
4851 this.cascade(function(c){
4852 if(ct != c && fn.call(scope || c, c, ct) === true){
4860 * Get a component contained by this container (alias for items.get(key))
4861 * @param {String/Number} key The index or id of the component
4862 * @return {Ext.Component} Ext.Component
4864 get : function(key){
4865 return this.items.get(key);
4869 Ext.Container.LAYOUTS = {};
4870 Ext.reg('container', Ext.Container);
4872 * @class Ext.layout.ContainerLayout
4873 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
4874 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
4876 Ext.layout.ContainerLayout = Ext.extend(Object, {
4878 * @cfg {String} extraCls
4879 * <p>An optional extra CSS class that will be added to the container. This can be useful for adding
4880 * customized styles to the container or any of its children using standard CSS rules. See
4881 * {@link Ext.Component}.{@link Ext.Component#ctCls ctCls} also.</p>
4882 * <p><b>Note</b>: <tt>extraCls</tt> defaults to <tt>''</tt> except for the following classes
4883 * which assign a value by default:
4884 * <div class="mdetail-params"><ul>
4885 * <li>{@link Ext.layout.AbsoluteLayout Absolute Layout} : <tt>'x-abs-layout-item'</tt></li>
4886 * <li>{@link Ext.layout.Box Box Layout} : <tt>'x-box-item'</tt></li>
4887 * <li>{@link Ext.layout.ColumnLayout Column Layout} : <tt>'x-column'</tt></li>
4889 * To configure the above Classes with an extra CSS class append to the default. For example,
4890 * for ColumnLayout:<pre><code>
4891 * extraCls: 'x-column custom-class'
4896 * @cfg {Boolean} renderHidden
4897 * True to hide each contained item on render (defaults to false).
4901 * A reference to the {@link Ext.Component} that is active. For example, <pre><code>
4902 * if(myPanel.layout.activeItem.id == 'item-1') { ... }
4904 * <tt>activeItem</tt> only applies to layout styles that can display items one at a time
4905 * (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout}
4906 * and {@link Ext.layout.FitLayout}). Read-only. Related to {@link Ext.Container#activeItem}.
4907 * @type {Ext.Component}
4908 * @property activeItem
4912 monitorResize:false,
4916 constructor : function(config){
4917 this.id = Ext.id(null, 'ext-layout-');
4918 Ext.apply(this, config);
4923 /* Workaround for how IE measures autoWidth elements. It prefers bottom-up measurements
4924 whereas other browser prefer top-down. We will hide all target child elements before we measure and
4925 put them back to get an accurate measurement.
4927 IEMeasureHack : function(target, viewFlag) {
4928 var tChildren = target.dom.childNodes, tLen = tChildren.length, c, d = [], e, i, ret;
4929 for (i = 0 ; i < tLen ; i++) {
4933 d[i] = e.getStyle('display');
4934 e.setStyle({display: 'none'});
4937 ret = target ? target.getViewSize(viewFlag) : {};
4938 for (i = 0 ; i < tLen ; i++) {
4942 e.setStyle({display: d[i]});
4948 // Placeholder for the derived layouts
4949 getLayoutTargetSize : Ext.EmptyFn,
4952 layout : function(){
4953 var ct = this.container, target = ct.getLayoutTarget();
4954 if(!(this.hasLayout || Ext.isEmpty(this.targetCls))){
4955 target.addClass(this.targetCls);
4957 this.onLayout(ct, target);
4958 ct.fireEvent('afterlayout', ct, this);
4962 onLayout : function(ct, target){
4963 this.renderAll(ct, target);
4967 isValidParent : function(c, target){
4968 return target && c.getPositionEl().dom.parentNode == (target.dom || target);
4972 renderAll : function(ct, target){
4973 var items = ct.items.items, i, c, len = items.length;
4974 for(i = 0; i < len; i++) {
4976 if(c && (!c.rendered || !this.isValidParent(c, target))){
4977 this.renderItem(c, i, target);
4984 * Renders the given Component into the target Element. If the Component is already rendered,
4985 * it is moved to the provided target instead.
4986 * @param {Ext.Component} c The Component to render
4987 * @param {Number} position The position within the target to render the item to
4988 * @param {Ext.Element} target The target Element
4990 renderItem : function(c, position, target){
4993 c.render(target, position);
4994 this.configureItem(c, position);
4995 } else if (!this.isValidParent(c, target)) {
4996 if (Ext.isNumber(position)) {
4997 position = target.dom.childNodes[position];
5000 target.dom.insertBefore(c.getPositionEl().dom, position || null);
5001 c.container = target;
5002 this.configureItem(c, position);
5008 // Get all rendered items to lay out.
5009 getRenderedItems: function(ct){
5010 var t = ct.getLayoutTarget(), cti = ct.items.items, len = cti.length, i, c, items = [];
5011 for (i = 0; i < len; i++) {
5012 if((c = cti[i]).rendered && this.isValidParent(c, t)){
5021 * Applies extraCls and hides the item if renderHidden is true
5023 configureItem: function(c, position){
5024 if (this.extraCls) {
5025 var t = c.getPositionEl ? c.getPositionEl() : c;
5026 t.addClass(this.extraCls);
5029 // If we are forcing a layout, do so *before* we hide so elements have height/width
5030 if (c.doLayout && this.forceLayout) {
5033 if (this.renderHidden && c != this.activeItem) {
5038 onRemove: function(c){
5039 if(this.activeItem == c){
5040 delete this.activeItem;
5042 if(c.rendered && this.extraCls){
5043 var t = c.getPositionEl ? c.getPositionEl() : c;
5044 t.removeClass(this.extraCls);
5048 afterRemove: function(c){
5049 if(c.removeRestore){
5050 c.removeMode = 'container';
5051 delete c.removeRestore;
5056 onResize: function(){
5057 var ct = this.container,
5062 if(b = ct.bufferResize && ct.shouldBufferLayout()){
5063 if(!this.resizeTask){
5064 this.resizeTask = new Ext.util.DelayedTask(this.runLayout, this);
5065 this.resizeBuffer = Ext.isNumber(b) ? b : 50;
5067 ct.layoutPending = true;
5068 this.resizeTask.delay(this.resizeBuffer);
5074 runLayout: function(){
5075 var ct = this.container;
5078 delete ct.layoutPending;
5082 setContainer : function(ct){
5084 * This monitorResize flag will be renamed soon as to avoid confusion
5085 * with the Container version which hooks onWindowResize to doLayout
5087 * monitorResize flag in this context attaches the resize event between
5088 * a container and it's layout
5090 if(this.monitorResize && ct != this.container){
5091 var old = this.container;
5093 old.un(old.resizeEvent, this.onResize, this);
5096 ct.on(ct.resizeEvent, this.onResize, this);
5099 this.container = ct;
5103 * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
5104 * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
5105 * @param {Number|String} v The encoded margins
5106 * @return {Object} An object with margin sizes for top, right, bottom and left
5108 parseMargins : function(v){
5109 if (Ext.isNumber(v)) {
5112 var ms = v.split(' '),
5116 ms[1] = ms[2] = ms[3] = ms[0];
5117 } else if(len == 2) {
5120 } else if(len == 3) {
5125 top :parseInt(ms[0], 10) || 0,
5126 right :parseInt(ms[1], 10) || 0,
5127 bottom:parseInt(ms[2], 10) || 0,
5128 left :parseInt(ms[3], 10) || 0
5133 * The {@link Ext.Template Ext.Template} used by Field rendering layout classes (such as
5134 * {@link Ext.layout.FormLayout}) to create the DOM structure of a fully wrapped,
5135 * labeled and styled form Field. A default Template is supplied, but this may be
5136 * overriden to create custom field structures. The template processes values returned from
5137 * {@link Ext.layout.FormLayout#getTemplateArgs}.
5138 * @property fieldTpl
5139 * @type Ext.Template
5141 fieldTpl: (function() {
5142 var t = new Ext.Template(
5143 '<div class="x-form-item {itemCls}" tabIndex="-1">',
5144 '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{labelSeparator}</label>',
5145 '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
5146 '</div><div class="{clearCls}"></div>',
5149 t.disableFormats = true;
5154 * Destroys this layout. This is a template method that is empty by default, but should be implemented
5155 * by subclasses that require explicit destruction to purge event handlers or remove DOM nodes.
5158 destroy : function(){
5159 // Stop any buffered layout tasks
5160 if(this.resizeTask && this.resizeTask.cancel){
5161 this.resizeTask.cancel();
5163 if(!Ext.isEmpty(this.targetCls)){
5164 var target = this.container.getLayoutTarget();
5166 target.removeClass(this.targetCls);
5171 * @class Ext.layout.AutoLayout
5172 * <p>The AutoLayout is the default layout manager delegated by {@link Ext.Container} to
5173 * render any child Components when no <tt>{@link Ext.Container#layout layout}</tt> is configured into
5174 * a {@link Ext.Container Container}.</tt>. AutoLayout provides only a passthrough of any layout calls
5175 * to any child containers.</p>
5177 Ext.layout.AutoLayout = Ext.extend(Ext.layout.ContainerLayout, {
5180 monitorResize: true,
5182 onLayout : function(ct, target){
5183 Ext.layout.AutoLayout.superclass.onLayout.call(this, ct, target);
5184 var cs = this.getRenderedItems(ct), len = cs.length, i, c;
5185 for(i = 0; i < len; i++){
5188 // Shallow layout children
5195 Ext.Container.LAYOUTS['auto'] = Ext.layout.AutoLayout;
5197 * @class Ext.layout.FitLayout
5198 * @extends Ext.layout.ContainerLayout
5199 * <p>This is a base class for layouts that contain <b>a single item</b> that automatically expands to fill the layout's
5200 * container. This class is intended to be extended or created via the <tt>layout:'fit'</tt> {@link Ext.Container#layout}
5201 * config, and should generally not need to be created directly via the new keyword.</p>
5202 * <p>FitLayout does not have any direct config options (other than inherited ones). To fit a panel to a container
5203 * using FitLayout, simply set layout:'fit' on the container and add a single panel to it. If the container has
5204 * multiple panels, only the first one will be displayed. Example usage:</p>
5206 var p = new Ext.Panel({
5207 title: 'Fit Layout',
5210 title: 'Inner Panel',
5211 html: '<p>This is the inner panel content</p>',
5217 Ext.layout.FitLayout = Ext.extend(Ext.layout.ContainerLayout, {
5223 getLayoutTargetSize : function() {
5224 var target = this.container.getLayoutTarget();
5228 // Style Sized (scrollbars not included)
5229 return target.getStyleSize();
5233 onLayout : function(ct, target){
5234 Ext.layout.FitLayout.superclass.onLayout.call(this, ct, target);
5236 this.setItemSize(this.activeItem || ct.items.itemAt(0), this.getLayoutTargetSize());
5241 setItemSize : function(item, size){
5242 if(item && size.height > 0){ // display none?
5247 Ext.Container.LAYOUTS['fit'] = Ext.layout.FitLayout;/**
5248 * @class Ext.layout.CardLayout
5249 * @extends Ext.layout.FitLayout
5250 * <p>This layout manages multiple child Components, each fitted to the Container, where only a single child Component can be
5251 * visible at any given time. This layout style is most commonly used for wizards, tab implementations, etc.
5252 * This class is intended to be extended or created via the layout:'card' {@link Ext.Container#layout} config,
5253 * and should generally not need to be created directly via the new keyword.</p>
5254 * <p>The CardLayout's focal method is {@link #setActiveItem}. Since only one panel is displayed at a time,
5255 * the only way to move from one Component to the next is by calling setActiveItem, passing the id or index of
5256 * the next panel to display. The layout itself does not provide a user interface for handling this navigation,
5257 * so that functionality must be provided by the developer.</p>
5258 * <p>In the following example, a simplistic wizard setup is demonstrated. A button bar is added
5259 * to the footer of the containing panel to provide navigation buttons. The buttons will be handled by a
5260 * common navigation routine -- for this example, the implementation of that routine has been ommitted since
5261 * it can be any type of custom logic. Note that other uses of a CardLayout (like a tab control) would require a
5262 * completely different implementation. For serious implementations, a better approach would be to extend
5263 * CardLayout to provide the custom functionality needed. Example usage:</p>
5265 var navHandler = function(direction){
5266 // This routine could contain business logic required to manage the navigation steps.
5267 // It would call setActiveItem as needed, manage navigation button state, handle any
5268 // branching logic that might be required, handle alternate actions like cancellation
5269 // or finalization, etc. A complete wizard implementation could get pretty
5270 // sophisticated depending on the complexity required, and should probably be
5271 // done as a subclass of CardLayout in a real-world implementation.
5274 var card = new Ext.Panel({
5275 title: 'Example Wizard',
5277 activeItem: 0, // make sure the active item is set on the container config!
5278 bodyStyle: 'padding:15px',
5280 // applied to each contained panel
5283 // just an example of one possible navigation scheme, using buttons
5288 handler: navHandler.createDelegate(this, [-1]),
5291 '->', // greedy spacer so that the buttons are aligned to each side
5295 handler: navHandler.createDelegate(this, [1])
5298 // the panels (or "cards") within the layout
5301 html: '<h1>Welcome to the Wizard!</h1><p>Step 1 of 3</p>'
5304 html: '<p>Step 2 of 3</p>'
5307 html: '<h1>Congratulations!</h1><p>Step 3 of 3 - Complete</p>'
5312 Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, {
5314 * @cfg {Boolean} deferredRender
5315 * True to render each contained item at the time it becomes active, false to render all contained items
5316 * as soon as the layout is rendered (defaults to false). If there is a significant amount of content or
5317 * a lot of heavy controls being rendered into panels that are not displayed by default, setting this to
5318 * true might improve performance.
5320 deferredRender : false,
5323 * @cfg {Boolean} layoutOnCardChange
5324 * True to force a layout of the active item when the active card is changed. Defaults to false.
5326 layoutOnCardChange : false,
5329 * @cfg {Boolean} renderHidden @hide
5332 renderHidden : true,
5337 * Sets the active (visible) item in the layout.
5338 * @param {String/Number} item The string component id or numeric index of the item to activate
5340 setActiveItem : function(item){
5341 var ai = this.activeItem,
5342 ct = this.container;
5343 item = ct.getComponent(item);
5345 // Is this a valid, different card?
5346 if(item && ai != item){
5348 // Changing cards, hide the current one
5351 if (ai.hidden !== true) {
5354 ai.fireEvent('deactivate', ai);
5357 var layout = item.doLayout && (this.layoutOnCardChange || !item.rendered);
5359 // Change activeItem reference
5360 this.activeItem = item;
5362 // The container is about to get a recursive layout, remove any deferLayout reference
5363 // because it will trigger a redundant layout.
5364 delete item.deferLayout;
5366 // Show the new component
5374 item.fireEvent('activate', item);
5379 renderAll : function(ct, target){
5380 if(this.deferredRender){
5381 this.renderItem(this.activeItem, undefined, target);
5383 Ext.layout.CardLayout.superclass.renderAll.call(this, ct, target);
5387 Ext.Container.LAYOUTS['card'] = Ext.layout.CardLayout;
5389 * @class Ext.layout.AnchorLayout
5390 * @extends Ext.layout.ContainerLayout
5391 * <p>This is a layout that enables anchoring of contained elements relative to the container's dimensions.
5392 * If the container is resized, all anchored items are automatically rerendered according to their
5393 * <b><tt>{@link #anchor}</tt></b> rules.</p>
5394 * <p>This class is intended to be extended or created via the layout:'anchor' {@link Ext.Container#layout}
5395 * config, and should generally not need to be created directly via the new keyword.</p>
5396 * <p>AnchorLayout does not have any direct config options (other than inherited ones). By default,
5397 * AnchorLayout will calculate anchor measurements based on the size of the container itself. However, the
5398 * container using the AnchorLayout can supply an anchoring-specific config property of <b>anchorSize</b>.
5399 * If anchorSize is specifed, the layout will use it as a virtual container for the purposes of calculating
5400 * anchor measurements based on it instead, allowing the container to be sized independently of the anchoring
5401 * logic if necessary. For example:</p>
5403 var viewport = new Ext.Viewport({
5405 anchorSize: {width:800, height:600},
5425 Ext.layout.AnchorLayout = Ext.extend(Ext.layout.ContainerLayout, {
5427 * @cfg {String} anchor
5428 * <p>This configuation option is to be applied to <b>child <tt>items</tt></b> of a container managed by
5429 * this layout (ie. configured with <tt>layout:'anchor'</tt>).</p><br/>
5431 * <p>This value is what tells the layout how an item should be anchored to the container. <tt>items</tt>
5432 * added to an AnchorLayout accept an anchoring-specific config property of <b>anchor</b> which is a string
5433 * containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%').
5434 * The following types of anchor values are supported:<div class="mdetail-params"><ul>
5436 * <li><b>Percentage</b> : Any value between 1 and 100, expressed as a percentage.<div class="sub-desc">
5437 * The first anchor is the percentage width that the item should take up within the container, and the
5438 * second is the percentage height. For example:<pre><code>
5439 // two values specified
5440 anchor: '100% 50%' // render item complete width of the container and
5441 // 1/2 height of the container
5442 // one value specified
5443 anchor: '100%' // the width value; the height will default to auto
5444 * </code></pre></div></li>
5446 * <li><b>Offsets</b> : Any positive or negative integer value.<div class="sub-desc">
5447 * This is a raw adjustment where the first anchor is the offset from the right edge of the container,
5448 * and the second is the offset from the bottom edge. For example:<pre><code>
5449 // two values specified
5450 anchor: '-50 -100' // render item the complete width of the container
5451 // minus 50 pixels and
5452 // the complete height minus 100 pixels.
5453 // one value specified
5454 anchor: '-50' // anchor value is assumed to be the right offset value
5455 // bottom offset will default to 0
5456 * </code></pre></div></li>
5458 * <li><b>Sides</b> : Valid values are <tt>'right'</tt> (or <tt>'r'</tt>) and <tt>'bottom'</tt>
5459 * (or <tt>'b'</tt>).<div class="sub-desc">
5460 * Either the container must have a fixed size or an anchorSize config value defined at render time in
5461 * order for these to have any effect.</div></li>
5463 * <li><b>Mixed</b> : <div class="sub-desc">
5464 * Anchor values can also be mixed as needed. For example, to render the width offset from the container
5465 * right edge by 50 pixels and 75% of the container's height use:
5468 * </code></pre></div></li>
5475 monitorResize : true,
5480 * @cfg {String} defaultAnchor
5482 * default anchor for all child container items applied if no anchor or specific width is set on the child item. Defaults to '100%'.
5485 defaultAnchor : '100%',
5487 parseAnchorRE : /^(r|right|b|bottom)$/i,
5489 getLayoutTargetSize : function() {
5490 var target = this.container.getLayoutTarget();
5494 // Style Sized (scrollbars not included)
5495 return target.getStyleSize();
5499 onLayout : function(ct, target){
5500 Ext.layout.AnchorLayout.superclass.onLayout.call(this, ct, target);
5501 var size = this.getLayoutTargetSize();
5503 var w = size.width, h = size.height;
5505 if(w < 20 && h < 20){
5509 // find the container anchoring size
5512 if(typeof ct.anchorSize == 'number'){
5515 aw = ct.anchorSize.width;
5516 ah = ct.anchorSize.height;
5519 aw = ct.initialConfig.width;
5520 ah = ct.initialConfig.height;
5523 var cs = this.getRenderedItems(ct), len = cs.length, i, c, a, cw, ch, el, vs, boxes = [];
5524 for(i = 0; i < len; i++){
5526 el = c.getPositionEl();
5528 // If a child container item has no anchor and no specific width, set the child to the default anchor size
5529 if (!c.anchor && c.items && !Ext.isNumber(c.width) && !(Ext.isIE6 && Ext.isStrict)){
5530 c.anchor = this.defaultAnchor;
5535 if(!a){ // cache all anchor values
5536 vs = c.anchor.split(' ');
5537 c.anchorSpec = a = {
5538 right: this.parseAnchor(vs[0], c.initialConfig.width, aw),
5539 bottom: this.parseAnchor(vs[1], c.initialConfig.height, ah)
5542 cw = a.right ? this.adjustWidthAnchor(a.right(w) - el.getMargins('lr'), c) : undefined;
5543 ch = a.bottom ? this.adjustHeightAnchor(a.bottom(h) - el.getMargins('tb'), c) : undefined;
5548 width: cw || undefined,
5549 height: ch || undefined
5554 for (i = 0, len = boxes.length; i < len; i++) {
5556 c.comp.setSize(c.width, c.height);
5561 parseAnchor : function(a, start, cstart){
5562 if(a && a != 'none'){
5565 if(this.parseAnchorRE.test(a)){
5566 var diff = cstart - start;
5574 }else if(a.indexOf('%') != -1){
5575 var ratio = parseFloat(a.replace('%', ''))*.01;
5579 return Math.floor(v*ratio);
5582 // simple offset adjustment
5584 a = parseInt(a, 10);
5599 adjustWidthAnchor : function(value, comp){
5604 adjustHeightAnchor : function(value, comp){
5609 * @property activeItem
5613 Ext.Container.LAYOUTS['anchor'] = Ext.layout.AnchorLayout;
5615 * @class Ext.layout.ColumnLayout
5616 * @extends Ext.layout.ContainerLayout
5617 * <p>This is the layout style of choice for creating structural layouts in a multi-column format where the width of
5618 * each column can be specified as a percentage or fixed width, but the height is allowed to vary based on the content.
5619 * This class is intended to be extended or created via the layout:'column' {@link Ext.Container#layout} config,
5620 * and should generally not need to be created directly via the new keyword.</p>
5621 * <p>ColumnLayout does not have any direct config options (other than inherited ones), but it does support a
5622 * specific config property of <b><tt>columnWidth</tt></b> that can be included in the config of any panel added to it. The
5623 * layout will use the columnWidth (if present) or width of each panel during layout to determine how to size each panel.
5624 * If width or columnWidth is not specified for a given panel, its width will default to the panel's width (or auto).</p>
5625 * <p>The width property is always evaluated as pixels, and must be a number greater than or equal to 1.
5626 * The columnWidth property is always evaluated as a percentage, and must be a decimal value greater than 0 and
5627 * less than 1 (e.g., .25).</p>
5628 * <p>The basic rules for specifying column widths are pretty simple. The logic makes two passes through the
5629 * set of contained panels. During the first layout pass, all panels that either have a fixed width or none
5630 * specified (auto) are skipped, but their widths are subtracted from the overall container width. During the second
5631 * pass, all panels with columnWidths are assigned pixel widths in proportion to their percentages based on
5632 * the total <b>remaining</b> container width. In other words, percentage width panels are designed to fill the space
5633 * left over by all the fixed-width and/or auto-width panels. Because of this, while you can specify any number of columns
5634 * with different percentages, the columnWidths must always add up to 1 (or 100%) when added together, otherwise your
5635 * layout may not render as expected. Example usage:</p>
5637 // All columns are percentages -- they must add up to 1
5638 var p = new Ext.Panel({
5639 title: 'Column Layout - Percentage Only',
5653 // Mix of width and columnWidth -- all columnWidth values must add up
5654 // to 1. The first column will take up exactly 120px, and the last two
5655 // columns will fill the remaining container width.
5656 var p = new Ext.Panel({
5657 title: 'Column Layout - Mixed',
5672 Ext.layout.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, {
5678 extraCls: 'x-column',
5684 targetCls: 'x-column-layout-ct',
5686 isValidParent : function(c, target){
5687 return this.innerCt && c.getPositionEl().dom.parentNode == this.innerCt.dom;
5690 getLayoutTargetSize : function() {
5691 var target = this.container.getLayoutTarget(), ret;
5693 ret = target.getViewSize();
5695 // IE in strict mode will return a width of 0 on the 1st pass of getViewSize.
5696 // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly
5698 if (Ext.isIE && Ext.isStrict && ret.width == 0){
5699 ret = target.getStyleSize();
5702 ret.width -= target.getPadding('lr');
5703 ret.height -= target.getPadding('tb');
5708 renderAll : function(ct, target) {
5710 // the innerCt prevents wrapping and shuffling while
5711 // the container is resizing
5712 this.innerCt = target.createChild({cls:'x-column-inner'});
5713 this.innerCt.createChild({cls:'x-clear'});
5715 Ext.layout.ColumnLayout.superclass.renderAll.call(this, ct, this.innerCt);
5719 onLayout : function(ct, target){
5720 var cs = ct.items.items,
5727 this.renderAll(ct, target);
5729 var size = this.getLayoutTargetSize();
5731 if(size.width < 1 && size.height < 1){ // display none?
5735 var w = size.width - this.scrollOffset,
5739 this.innerCt.setWidth(w);
5741 // some columns can be percentages while others are fixed
5742 // so we need to make 2 passes
5744 for(i = 0; i < len; i++){
5746 m = c.getPositionEl().getMargins('lr');
5749 pw -= (c.getWidth() + m);
5753 pw = pw < 0 ? 0 : pw;
5755 for(i = 0; i < len; i++){
5759 c.setSize(Math.floor(c.columnWidth * pw) - m);
5763 // Browsers differ as to when they account for scrollbars. We need to re-measure to see if the scrollbar
5764 // spaces were accounted for properly. If not, re-layout.
5766 if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) {
5767 var ts = this.getLayoutTargetSize();
5768 if (ts.width != size.width){
5769 this.adjustmentPass = true;
5770 this.onLayout(ct, target);
5774 delete this.adjustmentPass;
5778 * @property activeItem
5783 Ext.Container.LAYOUTS['column'] = Ext.layout.ColumnLayout;
5785 * @class Ext.layout.BorderLayout
5786 * @extends Ext.layout.ContainerLayout
5787 * <p>This is a multi-pane, application-oriented UI layout style that supports multiple
5788 * nested panels, automatic {@link Ext.layout.BorderLayout.Region#split split} bars between
5789 * {@link Ext.layout.BorderLayout.Region#BorderLayout.Region regions} and built-in
5790 * {@link Ext.layout.BorderLayout.Region#collapsible expanding and collapsing} of regions.</p>
5791 * <p>This class is intended to be extended or created via the <tt>layout:'border'</tt>
5792 * {@link Ext.Container#layout} config, and should generally not need to be created directly
5793 * via the new keyword.</p>
5794 * <p>BorderLayout does not have any direct config options (other than inherited ones).
5795 * All configuration options available for customizing the BorderLayout are at the
5796 * {@link Ext.layout.BorderLayout.Region} and {@link Ext.layout.BorderLayout.SplitRegion}
5798 * <p>Example usage:</p>
5800 var myBorderPanel = new Ext.Panel({
5801 {@link Ext.Component#renderTo renderTo}: document.body,
5802 {@link Ext.BoxComponent#width width}: 700,
5803 {@link Ext.BoxComponent#height height}: 500,
5804 {@link Ext.Panel#title title}: 'Border Layout',
5805 {@link Ext.Container#layout layout}: 'border',
5806 {@link Ext.Container#items items}: [{
5807 {@link Ext.Panel#title title}: 'South Region is resizable',
5808 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'south', // position for region
5809 {@link Ext.BoxComponent#height height}: 100,
5810 {@link Ext.layout.BorderLayout.Region#split split}: true, // enable resizing
5811 {@link Ext.SplitBar#minSize minSize}: 75, // defaults to {@link Ext.layout.BorderLayout.Region#minHeight 50}
5812 {@link Ext.SplitBar#maxSize maxSize}: 150,
5813 {@link Ext.layout.BorderLayout.Region#margins margins}: '0 5 5 5'
5815 // xtype: 'panel' implied by default
5816 {@link Ext.Panel#title title}: 'West Region is collapsible',
5817 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}:'west',
5818 {@link Ext.layout.BorderLayout.Region#margins margins}: '5 0 0 5',
5819 {@link Ext.BoxComponent#width width}: 200,
5820 {@link Ext.layout.BorderLayout.Region#collapsible collapsible}: true, // make collapsible
5821 {@link Ext.layout.BorderLayout.Region#cmargins cmargins}: '5 5 0 5', // adjust top margin when collapsed
5822 {@link Ext.Component#id id}: 'west-region-container',
5823 {@link Ext.Container#layout layout}: 'fit',
5824 {@link Ext.Panel#unstyled unstyled}: true
5826 {@link Ext.Panel#title title}: 'Center Region',
5827 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'center', // center region is required, no width/height specified
5828 {@link Ext.Component#xtype xtype}: 'container',
5829 {@link Ext.Container#layout layout}: 'fit',
5830 {@link Ext.layout.BorderLayout.Region#margins margins}: '5 5 0 0'
5834 * <p><b><u>Notes</u></b>:</p><div class="mdetail-params"><ul>
5835 * <li>Any container using the BorderLayout <b>must</b> have a child item with <tt>region:'center'</tt>.
5836 * The child item in the center region will always be resized to fill the remaining space not used by
5837 * the other regions in the layout.</li>
5838 * <li>Any child items with a region of <tt>west</tt> or <tt>east</tt> must have <tt>width</tt> defined
5839 * (an integer representing the number of pixels that the region should take up).</li>
5840 * <li>Any child items with a region of <tt>north</tt> or <tt>south</tt> must have <tt>height</tt> defined.</li>
5841 * <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
5842 * Components within a BorderLayout, have them wrapped by an additional Container which is directly
5843 * managed by the BorderLayout. If the region is to be collapsible, the Container used directly
5844 * by the BorderLayout manager should be a Panel. In the following example a Container (an Ext.Panel)
5845 * is added to the west region:
5846 * <div style="margin-left:16px"><pre><code>
5847 wrc = {@link Ext#getCmp Ext.getCmp}('west-region-container');
5848 wrc.{@link Ext.Panel#removeAll removeAll}();
5849 wrc.{@link Ext.Container#add add}({
5850 title: 'Added Panel',
5851 html: 'Some content'
5853 wrc.{@link Ext.Container#doLayout doLayout}();
5854 * </code></pre></div>
5856 * <li> To reference a {@link Ext.layout.BorderLayout.Region Region}:
5857 * <div style="margin-left:16px"><pre><code>
5858 wr = myBorderPanel.layout.west;
5859 * </code></pre></div>
5863 Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {
5871 targetCls: 'x-border-layout-ct',
5873 getLayoutTargetSize : function() {
5874 var target = this.container.getLayoutTarget();
5875 return target ? target.getViewSize() : {};
5879 onLayout : function(ct, target){
5880 var collapsed, i, c, pos, items = ct.items.items, len = items.length;
5883 for(i = 0; i < len; i++) {
5889 c.collapsed = false;
5891 c.render(target, i);
5892 c.getPositionEl().addClass('x-border-panel');
5894 this[pos] = pos != 'center' && c.split ?
5895 new Ext.layout.BorderLayout.SplitRegion(this, c.initialConfig, pos) :
5896 new Ext.layout.BorderLayout.Region(this, c.initialConfig, pos);
5897 this[pos].render(target, c);
5899 this.rendered = true;
5902 var size = this.getLayoutTargetSize();
5903 if(size.width < 20 || size.height < 20){ // display none?
5905 this.restoreCollapsed = collapsed;
5908 }else if(this.restoreCollapsed){
5909 collapsed = this.restoreCollapsed;
5910 delete this.restoreCollapsed;
5913 var w = size.width, h = size.height,
5914 centerW = w, centerH = h, centerY = 0, centerX = 0,
5915 n = this.north, s = this.south, west = this.west, e = this.east, c = this.center,
5916 b, m, totalWidth, totalHeight;
5917 if(!c && Ext.layout.BorderLayout.WARN !== false){
5918 throw 'No center region defined in BorderLayout ' + ct.id;
5921 if(n && n.isVisible()){
5924 b.width = w - (m.left+m.right);
5927 centerY = b.height + b.y + m.bottom;
5931 if(s && s.isVisible()){
5934 b.width = w - (m.left+m.right);
5936 totalHeight = (b.height + m.top + m.bottom);
5937 b.y = h - totalHeight + m.top;
5938 centerH -= totalHeight;
5941 if(west && west.isVisible()){
5943 m = west.getMargins();
5944 b.height = centerH - (m.top+m.bottom);
5946 b.y = centerY + m.top;
5947 totalWidth = (b.width + m.left + m.right);
5948 centerX += totalWidth;
5949 centerW -= totalWidth;
5950 west.applyLayout(b);
5952 if(e && e.isVisible()){
5955 b.height = centerH - (m.top+m.bottom);
5956 totalWidth = (b.width + m.left + m.right);
5957 b.x = w - totalWidth + m.left;
5958 b.y = centerY + m.top;
5959 centerW -= totalWidth;
5965 x: centerX + m.left,
5967 width: centerW - (m.left+m.right),
5968 height: centerH - (m.top+m.bottom)
5970 c.applyLayout(centerBox);
5973 for(i = 0, len = collapsed.length; i < len; i++){
5974 collapsed[i].collapse(false);
5977 if(Ext.isIE && Ext.isStrict){ // workaround IE strict repainting issue
5980 // Putting a border layout into an overflowed container is NOT correct and will make a second layout pass necessary.
5981 if (i = target.getStyle('overflow') && i != 'hidden' && !this.adjustmentPass) {
5982 var ts = this.getLayoutTargetSize();
5983 if (ts.width != size.width || ts.height != size.height){
5984 this.adjustmentPass = true;
5985 this.onLayout(ct, target);
5988 delete this.adjustmentPass;
5991 destroy: function() {
5992 var r = ['north', 'south', 'east', 'west'], i, region;
5993 for (i = 0; i < r.length; i++) {
5994 region = this[r[i]];
5998 }else if (region.split){
5999 region.split.destroy(true);
6003 Ext.layout.BorderLayout.superclass.destroy.call(this);
6007 * @property activeItem
6013 * @class Ext.layout.BorderLayout.Region
6014 * <p>This is a region of a {@link Ext.layout.BorderLayout BorderLayout} that acts as a subcontainer
6015 * within the layout. Each region has its own {@link Ext.layout.ContainerLayout layout} that is
6016 * independent of other regions and the containing BorderLayout, and can be any of the
6017 * {@link Ext.layout.ContainerLayout valid Ext layout types}.</p>
6018 * <p>Region size is managed automatically and cannot be changed by the user -- for
6019 * {@link #split resizable regions}, see {@link Ext.layout.BorderLayout.SplitRegion}.</p>
6021 * Create a new Region.
6022 * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region.
6023 * @param {Object} config The configuration options
6024 * @param {String} position The region position. Valid values are: <tt>north</tt>, <tt>south</tt>,
6025 * <tt>east</tt>, <tt>west</tt> and <tt>center</tt>. Every {@link Ext.layout.BorderLayout BorderLayout}
6026 * <b>must have a center region</b> for the primary content -- all other regions are optional.
6028 Ext.layout.BorderLayout.Region = function(layout, config, pos){
6029 Ext.apply(this, config);
6030 this.layout = layout;
6031 this.position = pos;
6033 if(typeof this.margins == 'string'){
6034 this.margins = this.layout.parseMargins(this.margins);
6036 this.margins = Ext.applyIf(this.margins || {}, this.defaultMargins);
6037 if(this.collapsible){
6038 if(typeof this.cmargins == 'string'){
6039 this.cmargins = this.layout.parseMargins(this.cmargins);
6041 if(this.collapseMode == 'mini' && !this.cmargins){
6042 this.cmargins = {left:0,top:0,right:0,bottom:0};
6044 this.cmargins = Ext.applyIf(this.cmargins || {},
6045 pos == 'north' || pos == 'south' ? this.defaultNSCMargins : this.defaultEWCMargins);
6050 Ext.layout.BorderLayout.Region.prototype = {
6052 * @cfg {Boolean} animFloat
6053 * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated
6054 * panel that will close again once the user mouses out of that panel (or clicks out if
6055 * <tt>{@link #autoHide} = false</tt>). Setting <tt>{@link #animFloat} = false</tt> will
6056 * prevent the open and close of these floated panels from being animated (defaults to <tt>true</tt>).
6059 * @cfg {Boolean} autoHide
6060 * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated
6061 * panel. If <tt>autoHide = true</tt>, the panel will automatically hide after the user mouses
6062 * out of the panel. If <tt>autoHide = false</tt>, the panel will continue to display until the
6063 * user clicks outside of the panel (defaults to <tt>true</tt>).
6066 * @cfg {String} collapseMode
6067 * <tt>collapseMode</tt> supports two configuration values:<div class="mdetail-params"><ul>
6068 * <li><b><tt>undefined</tt></b> (default)<div class="sub-desc">By default, {@link #collapsible}
6069 * regions are collapsed by clicking the expand/collapse tool button that renders into the region's
6070 * title bar.</div></li>
6071 * <li><b><tt>'mini'</tt></b><div class="sub-desc">Optionally, when <tt>collapseMode</tt> is set to
6072 * <tt>'mini'</tt> the region's split bar will also display a small collapse button in the center of
6073 * the bar. In <tt>'mini'</tt> mode the region will collapse to a thinner bar than in normal mode.
6076 * <p><b>Note</b>: if a collapsible region does not have a title bar, then set <tt>collapseMode =
6077 * 'mini'</tt> and <tt>{@link #split} = true</tt> in order for the region to be {@link #collapsible}
6078 * by the user as the expand/collapse tool button (that would go in the title bar) will not be rendered.</p>
6079 * <p>See also <tt>{@link #cmargins}</tt>.</p>
6082 * @cfg {Object} margins
6083 * An object containing margins to apply to the region when in the expanded state in the
6084 * format:<pre><code>
6087 right: (right margin),
6088 bottom: (bottom margin),
6091 * <p>May also be a string containing space-separated, numeric margin values. The order of the
6092 * sides associated with each value matches the way CSS processes margin values:</p>
6093 * <p><div class="mdetail-params"><ul>
6094 * <li>If there is only one value, it applies to all sides.</li>
6095 * <li>If there are two values, the top and bottom borders are set to the first value and the
6096 * right and left are set to the second.</li>
6097 * <li>If there are three values, the top is set to the first value, the left and right are set
6098 * to the second, and the bottom is set to the third.</li>
6099 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
6101 * <p>Defaults to:</p><pre><code>
6102 * {top:0, right:0, bottom:0, left:0}
6106 * @cfg {Object} cmargins
6107 * An object containing margins to apply to the region when in the collapsed state in the
6108 * format:<pre><code>
6111 right: (right margin),
6112 bottom: (bottom margin),
6115 * <p>May also be a string containing space-separated, numeric margin values. The order of the
6116 * sides associated with each value matches the way CSS processes margin values.</p>
6118 * <li>If there is only one value, it applies to all sides.</li>
6119 * <li>If there are two values, the top and bottom borders are set to the first value and the
6120 * right and left are set to the second.</li>
6121 * <li>If there are three values, the top is set to the first value, the left and right are set
6122 * to the second, and the bottom is set to the third.</li>
6123 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
6127 * @cfg {Boolean} collapsible
6128 * <p><tt>true</tt> to allow the user to collapse this region (defaults to <tt>false</tt>). If
6129 * <tt>true</tt>, an expand/collapse tool button will automatically be rendered into the title
6130 * bar of the region, otherwise the button will not be shown.</p>
6131 * <p><b>Note</b>: that a title bar is required to display the collapse/expand toggle button -- if
6132 * no <tt>title</tt> is specified for the region's panel, the region will only be collapsible if
6133 * <tt>{@link #collapseMode} = 'mini'</tt> and <tt>{@link #split} = true</tt>.
6135 collapsible : false,
6137 * @cfg {Boolean} split
6138 * <p><tt>true</tt> to create a {@link Ext.layout.BorderLayout.SplitRegion SplitRegion} and
6139 * display a 5px wide {@link Ext.SplitBar} between this region and its neighbor, allowing the user to
6140 * resize the regions dynamically. Defaults to <tt>false</tt> creating a
6141 * {@link Ext.layout.BorderLayout.Region Region}.</p><br>
6142 * <p><b>Notes</b>:</p><div class="mdetail-params"><ul>
6143 * <li>this configuration option is ignored if <tt>region='center'</tt></li>
6144 * <li>when <tt>split == true</tt>, it is common to specify a
6145 * <tt>{@link Ext.SplitBar#minSize minSize}</tt> and <tt>{@link Ext.SplitBar#maxSize maxSize}</tt>
6146 * for the {@link Ext.BoxComponent BoxComponent} representing the region. These are not native
6147 * configs of {@link Ext.BoxComponent BoxComponent}, and are used only by this class.</li>
6148 * <li>if <tt>{@link #collapseMode} = 'mini'</tt> requires <tt>split = true</tt> to reserve space
6149 * for the collapse tool</tt></li>
6154 * @cfg {Boolean} floatable
6155 * <tt>true</tt> to allow clicking a collapsed region's bar to display the region's panel floated
6156 * above the layout, <tt>false</tt> to force the user to fully expand a collapsed region by
6157 * clicking the expand button to see it again (defaults to <tt>true</tt>).
6161 * @cfg {Number} minWidth
6162 * <p>The minimum allowable width in pixels for this region (defaults to <tt>50</tt>).
6163 * <tt>maxWidth</tt> may also be specified.</p><br>
6164 * <p><b>Note</b>: setting the <tt>{@link Ext.SplitBar#minSize minSize}</tt> /
6165 * <tt>{@link Ext.SplitBar#maxSize maxSize}</tt> supersedes any specified
6166 * <tt>minWidth</tt> / <tt>maxWidth</tt>.</p>
6170 * @cfg {Number} minHeight
6171 * The minimum allowable height in pixels for this region (defaults to <tt>50</tt>)
6172 * <tt>maxHeight</tt> may also be specified.</p><br>
6173 * <p><b>Note</b>: setting the <tt>{@link Ext.SplitBar#minSize minSize}</tt> /
6174 * <tt>{@link Ext.SplitBar#maxSize maxSize}</tt> supersedes any specified
6175 * <tt>minHeight</tt> / <tt>maxHeight</tt>.</p>
6180 defaultMargins : {left:0,top:0,right:0,bottom:0},
6182 defaultNSCMargins : {left:5,top:5,right:5,bottom:5},
6184 defaultEWCMargins : {left:5,top:0,right:5,bottom:0},
6185 floatingZIndex: 100,
6188 * True if this region is collapsed. Read-only.
6192 isCollapsed : false,
6195 * This region's panel. Read-only.
6200 * This region's layout. Read-only.
6205 * This region's layout position (north, south, east, west or center). Read-only.
6207 * @property position
6211 render : function(ct, p){
6213 p.el.enableDisplayMode();
6217 var gs = p.getState, ps = this.position;
6218 p.getState = function(){
6219 return Ext.apply(gs.call(p) || {}, this.state);
6220 }.createDelegate(this);
6223 p.allowQueuedExpand = false;
6225 beforecollapse: this.beforeCollapse,
6226 collapse: this.onCollapse,
6227 beforeexpand: this.beforeExpand,
6228 expand: this.onExpand,
6233 if(this.collapsible || this.floatable){
6234 p.collapseEl = 'el';
6235 p.slideAnchor = this.getSlideAnchor();
6237 if(p.tools && p.tools.toggle){
6238 p.tools.toggle.addClass('x-tool-collapse-'+ps);
6239 p.tools.toggle.addClassOnOver('x-tool-collapse-'+ps+'-over');
6245 getCollapsedEl : function(){
6246 if(!this.collapsedEl){
6247 if(!this.toolTemplate){
6248 var tt = new Ext.Template(
6249 '<div class="x-tool x-tool-{id}"> </div>'
6251 tt.disableFormats = true;
6253 Ext.layout.BorderLayout.Region.prototype.toolTemplate = tt;
6255 this.collapsedEl = this.targetEl.createChild({
6256 cls: "x-layout-collapsed x-layout-collapsed-"+this.position,
6257 id: this.panel.id + '-xcollapsed'
6259 this.collapsedEl.enableDisplayMode('block');
6261 if(this.collapseMode == 'mini'){
6262 this.collapsedEl.addClass('x-layout-cmini-'+this.position);
6263 this.miniCollapsedEl = this.collapsedEl.createChild({
6264 cls: "x-layout-mini x-layout-mini-"+this.position, html: " "
6266 this.miniCollapsedEl.addClassOnOver('x-layout-mini-over');
6267 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
6268 this.collapsedEl.on('click', this.onExpandClick, this, {stopEvent:true});
6270 if(this.collapsible !== false && !this.hideCollapseTool) {
6271 var t = this.toolTemplate.append(
6272 this.collapsedEl.dom,
6273 {id:'expand-'+this.position}, true);
6274 t.addClassOnOver('x-tool-expand-'+this.position+'-over');
6275 t.on('click', this.onExpandClick, this, {stopEvent:true});
6277 if(this.floatable !== false || this.titleCollapse){
6278 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
6279 this.collapsedEl.on("click", this[this.floatable ? 'collapseClick' : 'onExpandClick'], this);
6283 return this.collapsedEl;
6287 onExpandClick : function(e){
6289 this.panel.expand(false);
6291 this.panel.expand();
6296 onCollapseClick : function(e){
6297 this.panel.collapse();
6301 beforeCollapse : function(p, animate){
6302 this.lastAnim = animate;
6304 this.splitEl.hide();
6306 this.getCollapsedEl().show();
6307 var el = this.panel.getEl();
6308 this.originalZIndex = el.getStyle('z-index');
6309 el.setStyle('z-index', 100);
6310 this.isCollapsed = true;
6311 this.layout.layout();
6315 onCollapse : function(animate){
6316 this.panel.el.setStyle('z-index', 1);
6317 if(this.lastAnim === false || this.panel.animCollapse === false){
6318 this.getCollapsedEl().dom.style.visibility = 'visible';
6320 this.getCollapsedEl().slideIn(this.panel.slideAnchor, {duration:.2});
6322 this.state.collapsed = true;
6323 this.panel.saveState();
6327 beforeExpand : function(animate){
6329 this.afterSlideIn();
6331 var c = this.getCollapsedEl();
6333 if(this.position == 'east' || this.position == 'west'){
6334 this.panel.setSize(undefined, c.getHeight());
6336 this.panel.setSize(c.getWidth(), undefined);
6339 c.dom.style.visibility = 'hidden';
6340 this.panel.el.setStyle('z-index', this.floatingZIndex);
6344 onExpand : function(){
6345 this.isCollapsed = false;
6347 this.splitEl.show();
6349 this.layout.layout();
6350 this.panel.el.setStyle('z-index', this.originalZIndex);
6351 this.state.collapsed = false;
6352 this.panel.saveState();
6356 collapseClick : function(e){
6358 e.stopPropagation();
6361 e.stopPropagation();
6367 onHide : function(){
6368 if(this.isCollapsed){
6369 this.getCollapsedEl().hide();
6370 }else if(this.splitEl){
6371 this.splitEl.hide();
6376 onShow : function(){
6377 if(this.isCollapsed){
6378 this.getCollapsedEl().show();
6379 }else if(this.splitEl){
6380 this.splitEl.show();
6385 * True if this region is currently visible, else false.
6388 isVisible : function(){
6389 return !this.panel.hidden;
6393 * Returns the current margins for this region. If the region is collapsed, the
6394 * {@link #cmargins} (collapsed margins) value will be returned, otherwise the
6395 * {@link #margins} value will be returned.
6396 * @return {Object} An object containing the element's margins: <tt>{left: (left
6397 * margin), top: (top margin), right: (right margin), bottom: (bottom margin)}</tt>
6399 getMargins : function(){
6400 return this.isCollapsed && this.cmargins ? this.cmargins : this.margins;
6404 * Returns the current size of this region. If the region is collapsed, the size of the
6405 * collapsedEl will be returned, otherwise the size of the region's panel will be returned.
6406 * @return {Object} An object containing the element's size: <tt>{width: (element width),
6407 * height: (element height)}</tt>
6409 getSize : function(){
6410 return this.isCollapsed ? this.getCollapsedEl().getSize() : this.panel.getSize();
6414 * Sets the specified panel as the container element for this region.
6415 * @param {Ext.Panel} panel The new panel
6417 setPanel : function(panel){
6422 * Returns the minimum allowable width for this region.
6423 * @return {Number} The minimum width
6425 getMinWidth: function(){
6426 return this.minWidth;
6430 * Returns the minimum allowable height for this region.
6431 * @return {Number} The minimum height
6433 getMinHeight: function(){
6434 return this.minHeight;
6438 applyLayoutCollapsed : function(box){
6439 var ce = this.getCollapsedEl();
6440 ce.setLeftTop(box.x, box.y);
6441 ce.setSize(box.width, box.height);
6445 applyLayout : function(box){
6446 if(this.isCollapsed){
6447 this.applyLayoutCollapsed(box);
6449 this.panel.setPosition(box.x, box.y);
6450 this.panel.setSize(box.width, box.height);
6455 beforeSlide: function(){
6456 this.panel.beforeEffect();
6460 afterSlide : function(){
6461 this.panel.afterEffect();
6465 initAutoHide : function(){
6466 if(this.autoHide !== false){
6467 if(!this.autoHideHd){
6468 this.autoHideSlideTask = new Ext.util.DelayedTask(this.slideIn, this);
6470 "mouseout": function(e){
6471 if(!e.within(this.el, true)){
6472 this.autoHideSlideTask.delay(500);
6475 "mouseover" : function(e){
6476 this.autoHideSlideTask.cancel();
6481 this.el.on(this.autoHideHd);
6482 this.collapsedEl.on(this.autoHideHd);
6487 clearAutoHide : function(){
6488 if(this.autoHide !== false){
6489 this.el.un("mouseout", this.autoHideHd.mouseout);
6490 this.el.un("mouseover", this.autoHideHd.mouseover);
6491 this.collapsedEl.un("mouseout", this.autoHideHd.mouseout);
6492 this.collapsedEl.un("mouseover", this.autoHideHd.mouseover);
6497 clearMonitor : function(){
6498 Ext.getDoc().un("click", this.slideInIf, this);
6502 * If this Region is {@link #floatable}, this method slides this Region into full visibility <i>over the top
6503 * of the center Region</i> where it floats until either {@link #slideIn} is called, or other regions of the layout
6504 * are clicked, or the mouse exits the Region.
6506 slideOut : function(){
6507 if(this.isSlid || this.el.hasActiveFx()){
6511 var ts = this.panel.tools, dh, pc;
6512 if(ts && ts.toggle){
6517 // Temporarily clear the collapsed flag so we can onResize the panel on the slide
6518 pc = this.panel.collapsed;
6519 this.panel.collapsed = false;
6521 if(this.position == 'east' || this.position == 'west'){
6522 // Temporarily clear the deferHeight flag so we can size the height on the slide
6523 dh = this.panel.deferHeight;
6524 this.panel.deferHeight = false;
6526 this.panel.setSize(undefined, this.collapsedEl.getHeight());
6528 // Put the deferHeight flag back after setSize
6529 this.panel.deferHeight = dh;
6531 this.panel.setSize(this.collapsedEl.getWidth(), undefined);
6534 // Put the collapsed flag back after onResize
6535 this.panel.collapsed = pc;
6537 this.restoreLT = [this.el.dom.style.left, this.el.dom.style.top];
6538 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
6539 this.el.setStyle("z-index", this.floatingZIndex+2);
6540 this.panel.el.replaceClass('x-panel-collapsed', 'x-panel-floating');
6541 if(this.animFloat !== false){
6543 this.el.slideIn(this.getSlideAnchor(), {
6544 callback: function(){
6546 this.initAutoHide();
6547 Ext.getDoc().on("click", this.slideInIf, this);
6553 this.initAutoHide();
6554 Ext.getDoc().on("click", this.slideInIf, this);
6559 afterSlideIn : function(){
6560 this.clearAutoHide();
6561 this.isSlid = false;
6562 this.clearMonitor();
6563 this.el.setStyle("z-index", "");
6564 this.panel.el.replaceClass('x-panel-floating', 'x-panel-collapsed');
6565 this.el.dom.style.left = this.restoreLT[0];
6566 this.el.dom.style.top = this.restoreLT[1];
6568 var ts = this.panel.tools;
6569 if(ts && ts.toggle){
6575 * If this Region is {@link #floatable}, and this Region has been slid into floating visibility, then this method slides
6576 * this region back into its collapsed state.
6578 slideIn : function(cb){
6579 if(!this.isSlid || this.el.hasActiveFx()){
6583 this.isSlid = false;
6584 if(this.animFloat !== false){
6586 this.el.slideOut(this.getSlideAnchor(), {
6587 callback: function(){
6590 this.afterSlideIn();
6598 this.afterSlideIn();
6603 slideInIf : function(e){
6604 if(!e.within(this.el)){
6634 getAnchor : function(){
6635 return this.anchors[this.position];
6639 getCollapseAnchor : function(){
6640 return this.canchors[this.position];
6644 getSlideAnchor : function(){
6645 return this.sanchors[this.position];
6649 getAlignAdj : function(){
6650 var cm = this.cmargins;
6651 switch(this.position){
6668 getExpandAdj : function(){
6669 var c = this.collapsedEl, cm = this.cmargins;
6670 switch(this.position){
6672 return [-(cm.right+c.getWidth()+cm.left), 0];
6675 return [cm.right+c.getWidth()+cm.left, 0];
6678 return [0, -(cm.top+cm.bottom+c.getHeight())];
6681 return [0, cm.top+cm.bottom+c.getHeight()];
6686 destroy : function(){
6687 if (this.autoHideSlideTask && this.autoHideSlideTask.cancel){
6688 this.autoHideSlideTask.cancel();
6690 Ext.destroy(this.miniCollapsedEl, this.collapsedEl);
6695 * @class Ext.layout.BorderLayout.SplitRegion
6696 * @extends Ext.layout.BorderLayout.Region
6697 * <p>This is a specialized type of {@link Ext.layout.BorderLayout.Region BorderLayout region} that
6698 * has a built-in {@link Ext.SplitBar} for user resizing of regions. The movement of the split bar
6699 * is configurable to move either {@link #tickSize smooth or incrementally}.</p>
6701 * Create a new SplitRegion.
6702 * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region.
6703 * @param {Object} config The configuration options
6704 * @param {String} position The region position. Valid values are: north, south, east, west and center. Every
6705 * BorderLayout must have a center region for the primary content -- all other regions are optional.
6707 Ext.layout.BorderLayout.SplitRegion = function(layout, config, pos){
6708 Ext.layout.BorderLayout.SplitRegion.superclass.constructor.call(this, layout, config, pos);
6710 this.applyLayout = this.applyFns[pos];
6713 Ext.extend(Ext.layout.BorderLayout.SplitRegion, Ext.layout.BorderLayout.Region, {
6715 * @cfg {Number} tickSize
6716 * The increment, in pixels by which to move this Region's {@link Ext.SplitBar SplitBar}.
6717 * By default, the {@link Ext.SplitBar SplitBar} moves smoothly.
6720 * @cfg {String} splitTip
6721 * The tooltip to display when the user hovers over a
6722 * {@link Ext.layout.BorderLayout.Region#collapsible non-collapsible} region's split bar
6723 * (defaults to <tt>"Drag to resize."</tt>). Only applies if
6724 * <tt>{@link #useSplitTips} = true</tt>.
6726 splitTip : "Drag to resize.",
6728 * @cfg {String} collapsibleSplitTip
6729 * The tooltip to display when the user hovers over a
6730 * {@link Ext.layout.BorderLayout.Region#collapsible collapsible} region's split bar
6731 * (defaults to "Drag to resize. Double click to hide."). Only applies if
6732 * <tt>{@link #useSplitTips} = true</tt>.
6734 collapsibleSplitTip : "Drag to resize. Double click to hide.",
6736 * @cfg {Boolean} useSplitTips
6737 * <tt>true</tt> to display a tooltip when the user hovers over a region's split bar
6738 * (defaults to <tt>false</tt>). The tooltip text will be the value of either
6739 * <tt>{@link #splitTip}</tt> or <tt>{@link #collapsibleSplitTip}</tt> as appropriate.
6741 useSplitTips : false,
6746 orientation: Ext.SplitBar.VERTICAL,
6747 placement: Ext.SplitBar.TOP,
6748 maxFn : 'getVMaxSize',
6749 minProp: 'minHeight',
6750 maxProp: 'maxHeight'
6753 orientation: Ext.SplitBar.VERTICAL,
6754 placement: Ext.SplitBar.BOTTOM,
6755 maxFn : 'getVMaxSize',
6756 minProp: 'minHeight',
6757 maxProp: 'maxHeight'
6760 orientation: Ext.SplitBar.HORIZONTAL,
6761 placement: Ext.SplitBar.RIGHT,
6762 maxFn : 'getHMaxSize',
6763 minProp: 'minWidth',
6767 orientation: Ext.SplitBar.HORIZONTAL,
6768 placement: Ext.SplitBar.LEFT,
6769 maxFn : 'getHMaxSize',
6770 minProp: 'minWidth',
6777 west : function(box){
6778 if(this.isCollapsed){
6779 return this.applyLayoutCollapsed(box);
6781 var sd = this.splitEl.dom, s = sd.style;
6782 this.panel.setPosition(box.x, box.y);
6783 var sw = sd.offsetWidth;
6784 s.left = (box.x+box.width-sw)+'px';
6785 s.top = (box.y)+'px';
6786 s.height = Math.max(0, box.height)+'px';
6787 this.panel.setSize(box.width-sw, box.height);
6789 east : function(box){
6790 if(this.isCollapsed){
6791 return this.applyLayoutCollapsed(box);
6793 var sd = this.splitEl.dom, s = sd.style;
6794 var sw = sd.offsetWidth;
6795 this.panel.setPosition(box.x+sw, box.y);
6796 s.left = (box.x)+'px';
6797 s.top = (box.y)+'px';
6798 s.height = Math.max(0, box.height)+'px';
6799 this.panel.setSize(box.width-sw, box.height);
6801 north : function(box){
6802 if(this.isCollapsed){
6803 return this.applyLayoutCollapsed(box);
6805 var sd = this.splitEl.dom, s = sd.style;
6806 var sh = sd.offsetHeight;
6807 this.panel.setPosition(box.x, box.y);
6808 s.left = (box.x)+'px';
6809 s.top = (box.y+box.height-sh)+'px';
6810 s.width = Math.max(0, box.width)+'px';
6811 this.panel.setSize(box.width, box.height-sh);
6813 south : function(box){
6814 if(this.isCollapsed){
6815 return this.applyLayoutCollapsed(box);
6817 var sd = this.splitEl.dom, s = sd.style;
6818 var sh = sd.offsetHeight;
6819 this.panel.setPosition(box.x, box.y+sh);
6820 s.left = (box.x)+'px';
6821 s.top = (box.y)+'px';
6822 s.width = Math.max(0, box.width)+'px';
6823 this.panel.setSize(box.width, box.height-sh);
6828 render : function(ct, p){
6829 Ext.layout.BorderLayout.SplitRegion.superclass.render.call(this, ct, p);
6831 var ps = this.position;
6833 this.splitEl = ct.createChild({
6834 cls: "x-layout-split x-layout-split-"+ps, html: " ",
6835 id: this.panel.id + '-xsplit'
6838 if(this.collapseMode == 'mini'){
6839 this.miniSplitEl = this.splitEl.createChild({
6840 cls: "x-layout-mini x-layout-mini-"+ps, html: " "
6842 this.miniSplitEl.addClassOnOver('x-layout-mini-over');
6843 this.miniSplitEl.on('click', this.onCollapseClick, this, {stopEvent:true});
6846 var s = this.splitSettings[ps];
6848 this.split = new Ext.SplitBar(this.splitEl.dom, p.el, s.orientation);
6849 this.split.tickSize = this.tickSize;
6850 this.split.placement = s.placement;
6851 this.split.getMaximumSize = this[s.maxFn].createDelegate(this);
6852 this.split.minSize = this.minSize || this[s.minProp];
6853 this.split.on("beforeapply", this.onSplitMove, this);
6854 this.split.useShim = this.useShim === true;
6855 this.maxSize = this.maxSize || this[s.maxProp];
6858 this.splitEl.hide();
6861 if(this.useSplitTips){
6862 this.splitEl.dom.title = this.collapsible ? this.collapsibleSplitTip : this.splitTip;
6864 if(this.collapsible){
6865 this.splitEl.on("dblclick", this.onCollapseClick, this);
6869 //docs inherit from superclass
6870 getSize : function(){
6871 if(this.isCollapsed){
6872 return this.collapsedEl.getSize();
6874 var s = this.panel.getSize();
6875 if(this.position == 'north' || this.position == 'south'){
6876 s.height += this.splitEl.dom.offsetHeight;
6878 s.width += this.splitEl.dom.offsetWidth;
6884 getHMaxSize : function(){
6885 var cmax = this.maxSize || 10000;
6886 var center = this.layout.center;
6887 return Math.min(cmax, (this.el.getWidth()+center.el.getWidth())-center.getMinWidth());
6891 getVMaxSize : function(){
6892 var cmax = this.maxSize || 10000;
6893 var center = this.layout.center;
6894 return Math.min(cmax, (this.el.getHeight()+center.el.getHeight())-center.getMinHeight());
6898 onSplitMove : function(split, newSize){
6899 var s = this.panel.getSize();
6900 this.lastSplitSize = newSize;
6901 if(this.position == 'north' || this.position == 'south'){
6902 this.panel.setSize(s.width, newSize);
6903 this.state.height = newSize;
6905 this.panel.setSize(newSize, s.height);
6906 this.state.width = newSize;
6908 this.layout.layout();
6909 this.panel.saveState();
6914 * Returns a reference to the split bar in use by this region.
6915 * @return {Ext.SplitBar} The split bar
6917 getSplitBar : function(){
6922 destroy : function() {
6923 Ext.destroy(this.miniSplitEl, this.split, this.splitEl);
6924 Ext.layout.BorderLayout.SplitRegion.superclass.destroy.call(this);
6928 Ext.Container.LAYOUTS['border'] = Ext.layout.BorderLayout;/**
6929 * @class Ext.layout.FormLayout
6930 * @extends Ext.layout.AnchorLayout
6931 * <p>This layout manager is specifically designed for rendering and managing child Components of
6932 * {@link Ext.form.FormPanel forms}. It is responsible for rendering the labels of
6933 * {@link Ext.form.Field Field}s.</p>
6935 * <p>This layout manager is used when a Container is configured with the <tt>layout:'form'</tt>
6936 * {@link Ext.Container#layout layout} config option, and should generally not need to be created directly
6937 * via the new keyword. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
6939 * <p>In an application, it will usually be preferrable to use a {@link Ext.form.FormPanel FormPanel}
6940 * (which is configured with FormLayout as its layout class by default) since it also provides built-in
6941 * functionality for {@link Ext.form.BasicForm#doAction loading, validating and submitting} the form.</p>
6943 * <p>A {@link Ext.Container Container} <i>using</i> the FormLayout layout manager (e.g.
6944 * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>) can also accept the following
6945 * layout-specific config properties:<div class="mdetail-params"><ul>
6946 * <li><b><tt>{@link Ext.form.FormPanel#hideLabels hideLabels}</tt></b></li>
6947 * <li><b><tt>{@link Ext.form.FormPanel#labelAlign labelAlign}</tt></b></li>
6948 * <li><b><tt>{@link Ext.form.FormPanel#labelPad labelPad}</tt></b></li>
6949 * <li><b><tt>{@link Ext.form.FormPanel#labelSeparator labelSeparator}</tt></b></li>
6950 * <li><b><tt>{@link Ext.form.FormPanel#labelWidth labelWidth}</tt></b></li>
6953 * <p>Any Component (including Fields) managed by FormLayout accepts the following as a config option:
6954 * <div class="mdetail-params"><ul>
6955 * <li><b><tt>{@link Ext.Component#anchor anchor}</tt></b></li>
6958 * <p>Any Component managed by FormLayout may be rendered as a form field (with an associated label) by
6959 * configuring it with a non-null <b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b>. Components configured
6960 * in this way may be configured with the following options which affect the way the FormLayout renders them:
6961 * <div class="mdetail-params"><ul>
6962 * <li><b><tt>{@link Ext.Component#clearCls clearCls}</tt></b></li>
6963 * <li><b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b></li>
6964 * <li><b><tt>{@link Ext.Component#hideLabel hideLabel}</tt></b></li>
6965 * <li><b><tt>{@link Ext.Component#itemCls itemCls}</tt></b></li>
6966 * <li><b><tt>{@link Ext.Component#labelSeparator labelSeparator}</tt></b></li>
6967 * <li><b><tt>{@link Ext.Component#labelStyle labelStyle}</tt></b></li>
6970 * <p>Example usage:</p>
6972 // Required if showing validation messages
6973 Ext.QuickTips.init();
6975 // While you can create a basic Panel with layout:'form', practically
6976 // you should usually use a FormPanel to also get its form functionality
6977 // since it already creates a FormLayout internally.
6978 var form = new Ext.form.FormPanel({
6979 title: 'Form Layout',
6980 bodyStyle: 'padding:15px',
6982 defaultType: 'textfield',
6984 // applied to each contained item
6989 fieldLabel: 'First Name',
6992 {@link Ext.Component#labelSeparator labelSeparator}: ':' // override labelSeparator layout config
6994 fieldLabel: 'Last Name',
6997 fieldLabel: 'Email',
7002 hideLabel: true, // override hideLabels layout config
7012 {@link #labelSeparator}: '~' // superseded by assignment below
7014 // config options applicable to container when layout='form':
7016 labelAlign: 'left', // or 'right' or 'top'
7017 {@link Ext.form.FormPanel#labelSeparator labelSeparator}: '>>', // takes precedence over layoutConfig value
7018 labelWidth: 65, // defaults to 100
7019 labelPad: 8 // defaults to 5, must specify labelWidth to be honored
7023 Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, {
7026 * @cfg {String} labelSeparator
7027 * See {@link Ext.form.FormPanel}.{@link Ext.form.FormPanel#labelSeparator labelSeparator}. Configuration
7028 * of this property at the <b>container</b> level takes precedence.
7030 labelSeparator : ':',
7033 * Read only. The CSS style specification string added to field labels in this layout if not
7034 * otherwise {@link Ext.Component#labelStyle specified by each contained field}.
7036 * @property labelStyle
7040 * @cfg {Boolean} trackLabels
7041 * True to show/hide the field label when the field is hidden. Defaults to <tt>false</tt>.
7047 onRemove: function(c){
7048 Ext.layout.FormLayout.superclass.onRemove.call(this, c);
7049 if(this.trackLabels){
7050 c.un('show', this.onFieldShow, this);
7051 c.un('hide', this.onFieldHide, this);
7053 // check for itemCt, since we may be removing a fieldset or something similar
7054 var el = c.getPositionEl(),
7055 ct = c.getItemCt && c.getItemCt();
7056 if (c.rendered && ct) {
7061 Ext.destroyMembers(c, 'label', 'itemCt');
7062 if (c.customItemCt) {
7063 Ext.destroyMembers(c, 'getItemCt', 'customItemCt');
7069 setContainer : function(ct){
7070 Ext.layout.FormLayout.superclass.setContainer.call(this, ct);
7072 ct.addClass('x-form-label-'+ct.labelAlign);
7077 labelStyle: 'display:none',
7078 elementStyle: 'padding-left:0;',
7082 this.labelSeparator = ct.labelSeparator || this.labelSeparator;
7083 ct.labelWidth = ct.labelWidth || 100;
7084 if(Ext.isNumber(ct.labelWidth)){
7085 var pad = Ext.isNumber(ct.labelPad) ? ct.labelPad : 5;
7087 labelAdjust: ct.labelWidth + pad,
7088 labelStyle: 'width:' + ct.labelWidth + 'px;',
7089 elementStyle: 'padding-left:' + (ct.labelWidth + pad) + 'px'
7092 if(ct.labelAlign == 'top'){
7094 labelStyle: 'width:auto;',
7096 elementStyle: 'padding-left:0;'
7103 isHide: function(c){
7104 return c.hideLabel || this.container.hideLabels;
7107 onFieldShow: function(c){
7108 c.getItemCt().removeClass('x-hide-' + c.hideMode);
7111 onFieldHide: function(c){
7112 c.getItemCt().addClass('x-hide-' + c.hideMode);
7116 getLabelStyle: function(s){
7117 var ls = '', items = [this.labelStyle, s];
7118 for (var i = 0, len = items.length; i < len; ++i){
7121 if (ls.substr(-1, 1) != ';'){
7130 * @cfg {Ext.Template} fieldTpl
7131 * A {@link Ext.Template#compile compile}d {@link Ext.Template} for rendering
7132 * the fully wrapped, labeled and styled form Field. Defaults to:</p><pre><code>
7134 '<div class="x-form-item {itemCls}" tabIndex="-1">',
7135 '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{labelSeparator}</label>',
7136 '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
7137 '</div><div class="{clearCls}"></div>',
7141 * <p>This may be specified to produce a different DOM structure when rendering form Fields.</p>
7142 * <p>A description of the properties within the template follows:</p><div class="mdetail-params"><ul>
7143 * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper
7144 * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt>
7145 * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt>
7146 * supplied at the container level.</div></li>
7147 * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li>
7148 * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc">
7149 * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the
7150 * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li>
7151 * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this
7152 * field (defaults to <tt>''</tt>)</div></li>
7153 * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after
7154 * the text of the label for this field (defaults to a colon <tt>':'</tt> or the
7155 * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li>
7156 * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li>
7157 * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div
7158 * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li>
7160 * <p>Also see <tt>{@link #getTemplateArgs}</tt></p>
7167 renderItem : function(c, position, target){
7168 if(c && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){
7169 var args = this.getTemplateArgs(c);
7170 if(Ext.isNumber(position)){
7171 position = target.dom.childNodes[position] || null;
7174 c.itemCt = this.fieldTpl.insertBefore(position, args, true);
7176 c.itemCt = this.fieldTpl.append(target, args, true);
7179 // Non form fields don't have getItemCt, apply it here
7180 // This will get cleaned up in onRemove
7182 getItemCt: function(){
7188 c.label = c.getItemCt().child('label.x-form-item-label');
7190 c.render('x-form-el-' + c.id);
7191 }else if(!this.isValidParent(c, target)){
7192 Ext.fly('x-form-el-' + c.id).appendChild(c.getPositionEl());
7194 if(this.trackLabels){
7196 this.onFieldHide(c);
7200 show: this.onFieldShow,
7201 hide: this.onFieldHide
7204 this.configureItem(c);
7206 Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments);
7211 * <p>Provides template arguments for rendering the fully wrapped, labeled and styled form Field.</p>
7212 * <p>This method returns an object hash containing properties used by the layout's {@link #fieldTpl}
7213 * to create a correctly wrapped, labeled and styled form Field. This may be overriden to
7214 * create custom layouts. The properties which must be returned are:</p><div class="mdetail-params"><ul>
7215 * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper
7216 * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt>
7217 * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt>
7218 * supplied at the container level.</div></li>
7219 * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li>
7220 * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc">
7221 * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the
7222 * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li>
7223 * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this
7224 * field (defaults to the field's configured fieldLabel property)</div></li>
7225 * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after
7226 * the text of the label for this field (defaults to a colon <tt>':'</tt> or the
7227 * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li>
7228 * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li>
7229 * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div
7230 * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li>
7232 * @param (Ext.form.Field} field The {@link Ext.form.Field Field} being rendered.
7233 * @return {Object} An object hash containing the properties required to render the Field.
7235 getTemplateArgs: function(field) {
7236 var noLabelSep = !field.fieldLabel || field.hideLabel;
7240 label : field.fieldLabel,
7241 itemCls : (field.itemCls || this.container.itemCls || '') + (field.hideLabel ? ' x-hide-label' : ''),
7242 clearCls : field.clearCls || 'x-form-clear-left',
7243 labelStyle : this.getLabelStyle(field.labelStyle),
7244 elementStyle : this.elementStyle || '',
7245 labelSeparator: noLabelSep ? '' : (Ext.isDefined(field.labelSeparator) ? field.labelSeparator : this.labelSeparator)
7250 adjustWidthAnchor: function(value, c){
7251 if(c.label && !this.isHide(c) && (this.container.labelAlign != 'top')){
7252 var adjust = Ext.isIE6 || (Ext.isIE && !Ext.isStrict);
7253 return value - this.labelAdjust + (adjust ? -3 : 0);
7258 adjustHeightAnchor : function(value, c){
7259 if(c.label && !this.isHide(c) && (this.container.labelAlign == 'top')){
7260 return value - c.label.getHeight();
7266 isValidParent : function(c, target){
7267 return target && this.container.getEl().contains(c.getPositionEl());
7271 * @property activeItem
7276 Ext.Container.LAYOUTS['form'] = Ext.layout.FormLayout;
7278 * @class Ext.layout.AccordionLayout
7279 * @extends Ext.layout.FitLayout
7280 * <p>This is a layout that manages multiple Panels in an expandable accordion style such that only
7281 * <b>one Panel can be expanded at any given time</b>. Each Panel has built-in support for expanding and collapsing.</p>
7282 * <p>Note: Only Ext.Panels <b>and all subclasses of Ext.Panel</b> may be used in an accordion layout Container.</p>
7283 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
7284 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
7285 * <p>Example usage:</p>
7287 var accordion = new Ext.Panel({
7288 title: 'Accordion Layout',
7291 // applied to each contained panel
7292 bodyStyle: 'padding:15px'
7295 // layout-specific configs go here
7296 titleCollapse: false,
7302 html: '<p>Panel content!</p>'
7305 html: '<p>Panel content!</p>'
7308 html: '<p>Panel content!</p>'
7313 Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, {
7315 * @cfg {Boolean} fill
7316 * True to adjust the active item's height to fill the available space in the container, false to use the
7317 * item's current height, or auto height if not explicitly set (defaults to true).
7321 * @cfg {Boolean} autoWidth
7322 * True to set each contained item's width to 'auto', false to use the item's current width (defaults to true).
7323 * Note that some components, in particular the {@link Ext.grid.GridPanel grid}, will not function properly within
7324 * layouts if they have auto width, so in such cases this config should be set to false.
7328 * @cfg {Boolean} titleCollapse
7329 * True to allow expand/collapse of each contained panel by clicking anywhere on the title bar, false to allow
7330 * expand/collapse only when the toggle tool button is clicked (defaults to true). When set to false,
7331 * {@link #hideCollapseTool} should be false also.
7333 titleCollapse : true,
7335 * @cfg {Boolean} hideCollapseTool
7336 * True to hide the contained panels' collapse/expand toggle buttons, false to display them (defaults to false).
7337 * When set to true, {@link #titleCollapse} should be true also.
7339 hideCollapseTool : false,
7341 * @cfg {Boolean} collapseFirst
7342 * True to make sure the collapse/expand toggle button always renders first (to the left of) any other tools
7343 * in the contained panels' title bars, false to render it last (defaults to false).
7345 collapseFirst : false,
7347 * @cfg {Boolean} animate
7348 * True to slide the contained panels open and closed during expand/collapse using animation, false to open and
7349 * close directly with no animation (defaults to false). Note: to defer to the specific config setting of each
7350 * contained panel for this property, set this to undefined at the layout level.
7354 * @cfg {Boolean} sequence
7355 * <b>Experimental</b>. If animate is set to true, this will result in each animation running in sequence.
7359 * @cfg {Boolean} activeOnTop
7360 * True to swap the position of each panel as it is expanded so that it becomes the first item in the container,
7361 * false to keep the panels in the rendered order. <b>This is NOT compatible with "animate:true"</b> (defaults to false).
7363 activeOnTop : false,
7367 renderItem : function(c){
7368 if(this.animate === false){
7369 c.animCollapse = false;
7371 c.collapsible = true;
7375 if(this.titleCollapse){
7376 c.titleCollapse = true;
7378 if(this.hideCollapseTool){
7379 c.hideCollapseTool = true;
7381 if(this.collapseFirst !== undefined){
7382 c.collapseFirst = this.collapseFirst;
7384 if(!this.activeItem && !c.collapsed){
7385 this.setActiveItem(c, true);
7386 }else if(this.activeItem && this.activeItem != c){
7389 Ext.layout.AccordionLayout.superclass.renderItem.apply(this, arguments);
7390 c.header.addClass('x-accordion-hd');
7391 c.on('beforeexpand', this.beforeExpand, this);
7394 onRemove: function(c){
7395 Ext.layout.AccordionLayout.superclass.onRemove.call(this, c);
7397 c.header.removeClass('x-accordion-hd');
7399 c.un('beforeexpand', this.beforeExpand, this);
7403 beforeExpand : function(p, anim){
7404 var ai = this.activeItem;
7407 delete this.activeItem;
7409 ai.collapse({callback:function(){
7410 p.expand(anim || true);
7415 ai.collapse(this.animate);
7419 if(this.activeOnTop){
7420 p.el.dom.parentNode.insertBefore(p.el.dom, p.el.dom.parentNode.firstChild);
7422 // Items have been hidden an possibly rearranged, we need to get the container size again.
7427 setItemSize : function(item, size){
7428 if(this.fill && item){
7429 var hh = 0, i, ct = this.getRenderedItems(this.container), len = ct.length, p;
7430 // Add up all the header heights
7431 for (i = 0; i < len; i++) {
7432 if((p = ct[i]) != item){
7433 hh += p.header.getHeight();
7436 // Subtract the header heights from the container size
7438 // Call setSize on the container to set the correct height. For Panels, deferedHeight
7439 // will simply store this size for when the expansion is done.
7445 * Sets the active (expanded) item in the layout.
7446 * @param {String/Number} item The string component id or numeric index of the item to activate
7448 setActiveItem : function(item){
7449 this.setActive(item, true);
7453 setActive : function(item, expand){
7454 var ai = this.activeItem;
7455 item = this.container.getComponent(item);
7457 if(item.rendered && item.collapsed && expand){
7461 ai.fireEvent('deactivate', ai);
7463 this.activeItem = item;
7464 item.fireEvent('activate', item);
7469 Ext.Container.LAYOUTS.accordion = Ext.layout.AccordionLayout;
7472 Ext.layout.Accordion = Ext.layout.AccordionLayout;/**
7473 * @class Ext.layout.TableLayout
7474 * @extends Ext.layout.ContainerLayout
7475 * <p>This layout allows you to easily render content into an HTML table. The total number of columns can be
7476 * specified, and rowspan and colspan can be used to create complex layouts within the table.
7477 * This class is intended to be extended or created via the layout:'table' {@link Ext.Container#layout} config,
7478 * and should generally not need to be created directly via the new keyword.</p>
7479 * <p>Note that when creating a layout via config, the layout-specific config properties must be passed in via
7480 * the {@link Ext.Container#layoutConfig} object which will then be applied internally to the layout. In the
7481 * case of TableLayout, the only valid layout config property is {@link #columns}. However, the items added to a
7482 * TableLayout can supply the following table-specific config properties:</p>
7484 * <li><b>rowspan</b> Applied to the table cell containing the item.</li>
7485 * <li><b>colspan</b> Applied to the table cell containing the item.</li>
7486 * <li><b>cellId</b> An id applied to the table cell containing the item.</li>
7487 * <li><b>cellCls</b> A CSS class name added to the table cell containing the item.</li>
7489 * <p>The basic concept of building up a TableLayout is conceptually very similar to building up a standard
7490 * HTML table. You simply add each panel (or "cell") that you want to include along with any span attributes
7491 * specified as the special config properties of rowspan and colspan which work exactly like their HTML counterparts.
7492 * Rather than explicitly creating and nesting rows and columns as you would in HTML, you simply specify the
7493 * total column count in the layoutConfig and start adding panels in their natural order from left to right,
7494 * top to bottom. The layout will automatically figure out, based on the column count, rowspans and colspans,
7495 * how to position each panel within the table. Just like with HTML tables, your rowspans and colspans must add
7496 * up correctly in your overall layout or you'll end up with missing and/or extra cells! Example usage:</p>
7498 // This code will generate a layout table that is 3 columns by 2 rows
7499 // with some spanning included. The basic layout will be:
7500 // +--------+-----------------+
7502 // | |--------+--------|
7504 // +--------+--------+--------+
7505 var table = new Ext.Panel({
7506 title: 'Table Layout',
7509 // applied to each contained panel
7510 bodyStyle:'padding:20px'
7513 // The total column count must be specified here
7517 html: '<p>Cell A content</p>',
7520 html: '<p>Cell B content</p>',
7523 html: '<p>Cell C content</p>',
7524 cellCls: 'highlight'
7526 html: '<p>Cell D content</p>'
7531 Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, {
7533 * @cfg {Number} columns
7534 * The total number of columns to create in the table for this layout. If not specified, all Components added to
7535 * this layout will be rendered into a single row using one column per Component.
7539 monitorResize:false,
7543 targetCls: 'x-table-layout-ct',
7546 * @cfg {Object} tableAttrs
7547 * <p>An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification
7548 * used to create the layout's <tt><table></tt> element. Example:</p><pre><code>
7565 setContainer : function(ct){
7566 Ext.layout.TableLayout.superclass.setContainer.call(this, ct);
7568 this.currentRow = 0;
7569 this.currentColumn = 0;
7574 onLayout : function(ct, target){
7575 var cs = ct.items.items, len = cs.length, c, i;
7578 target.addClass('x-table-layout-ct');
7580 this.table = target.createChild(
7581 Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true);
7583 this.renderAll(ct, target);
7587 getRow : function(index){
7588 var row = this.table.tBodies[0].childNodes[index];
7590 row = document.createElement('tr');
7591 this.table.tBodies[0].appendChild(row);
7597 getNextCell : function(c){
7598 var cell = this.getNextNonSpan(this.currentColumn, this.currentRow);
7599 var curCol = this.currentColumn = cell[0], curRow = this.currentRow = cell[1];
7600 for(var rowIndex = curRow; rowIndex < curRow + (c.rowspan || 1); rowIndex++){
7601 if(!this.cells[rowIndex]){
7602 this.cells[rowIndex] = [];
7604 for(var colIndex = curCol; colIndex < curCol + (c.colspan || 1); colIndex++){
7605 this.cells[rowIndex][colIndex] = true;
7608 var td = document.createElement('td');
7612 var cls = 'x-table-layout-cell';
7614 cls += ' ' + c.cellCls;
7618 td.colSpan = c.colspan;
7621 td.rowSpan = c.rowspan;
7623 this.getRow(curRow).appendChild(td);
7628 getNextNonSpan: function(colIndex, rowIndex){
7629 var cols = this.columns;
7630 while((cols && colIndex >= cols) || (this.cells[rowIndex] && this.cells[rowIndex][colIndex])) {
7631 if(cols && colIndex >= cols){
7638 return [colIndex, rowIndex];
7642 renderItem : function(c, position, target){
7643 // Ensure we have our inner table to get cells to render into.
7645 this.table = target.createChild(
7646 Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true);
7648 if(c && !c.rendered){
7649 c.render(this.getNextCell(c));
7650 this.configureItem(c, position);
7651 }else if(c && !this.isValidParent(c, target)){
7652 var container = this.getNextCell(c);
7653 container.insertBefore(c.getPositionEl().dom, null);
7654 c.container = Ext.get(container);
7655 this.configureItem(c, position);
7660 isValidParent : function(c, target){
7661 return c.getPositionEl().up('table', 5).dom.parentNode === (target.dom || target);
7665 * @property activeItem
7670 Ext.Container.LAYOUTS['table'] = Ext.layout.TableLayout;/**
7671 * @class Ext.layout.AbsoluteLayout
7672 * @extends Ext.layout.AnchorLayout
7673 * <p>This is a layout that inherits the anchoring of <b>{@link Ext.layout.AnchorLayout}</b> and adds the
7674 * ability for x/y positioning using the standard x and y component config options.</p>
7675 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
7676 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
7677 * <p>Example usage:</p>
7679 var form = new Ext.form.FormPanel({
7680 title: 'Absolute Layout',
7683 // layout-specific configs go here
7684 extraCls: 'x-abs-layout-item',
7687 url:'save-form.php',
7688 defaultType: 'textfield',
7698 anchor:'100%' // anchor width by percentage
7708 anchor: '100%' // anchor width by percentage
7714 anchor: '100% 100%' // anchor width and height
7719 Ext.layout.AbsoluteLayout = Ext.extend(Ext.layout.AnchorLayout, {
7721 extraCls: 'x-abs-layout-item',
7725 onLayout : function(ct, target){
7727 this.paddingLeft = target.getPadding('l');
7728 this.paddingTop = target.getPadding('t');
7729 Ext.layout.AbsoluteLayout.superclass.onLayout.call(this, ct, target);
7733 adjustWidthAnchor : function(value, comp){
7734 return value ? value - comp.getPosition(true)[0] + this.paddingLeft : value;
7738 adjustHeightAnchor : function(value, comp){
7739 return value ? value - comp.getPosition(true)[1] + this.paddingTop : value;
7742 * @property activeItem
7746 Ext.Container.LAYOUTS['absolute'] = Ext.layout.AbsoluteLayout;
7748 * @class Ext.layout.BoxLayout
7749 * @extends Ext.layout.ContainerLayout
7750 * <p>Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.</p>
7752 Ext.layout.BoxLayout = Ext.extend(Ext.layout.ContainerLayout, {
7754 * @cfg {Object} defaultMargins
7755 * <p>If the individual contained items do not have a <tt>margins</tt>
7756 * property specified, the default margins from this property will be
7757 * applied to each item.</p>
7758 * <br><p>This property may be specified as an object containing margins
7759 * to apply in the format:</p><pre><code>
7762 right: (right margin),
7763 bottom: (bottom margin),
7766 * <p>This property may also be specified as a string containing
7767 * space-separated, numeric margin values. The order of the sides associated
7768 * with each value matches the way CSS processes margin values:</p>
7769 * <div class="mdetail-params"><ul>
7770 * <li>If there is only one value, it applies to all sides.</li>
7771 * <li>If there are two values, the top and bottom borders are set to the
7772 * first value and the right and left are set to the second.</li>
7773 * <li>If there are three values, the top is set to the first value, the left
7774 * and right are set to the second, and the bottom is set to the third.</li>
7775 * <li>If there are four values, they apply to the top, right, bottom, and
7776 * left, respectively.</li>
7778 * <p>Defaults to:</p><pre><code>
7779 * {top:0, right:0, bottom:0, left:0}
7782 defaultMargins : {left:0,top:0,right:0,bottom:0},
7784 * @cfg {String} padding
7785 * <p>Sets the padding to be applied to all child items managed by this layout.</p>
7786 * <p>This property must be specified as a string containing
7787 * space-separated, numeric padding values. The order of the sides associated
7788 * with each value matches the way CSS processes padding values:</p>
7789 * <div class="mdetail-params"><ul>
7790 * <li>If there is only one value, it applies to all sides.</li>
7791 * <li>If there are two values, the top and bottom borders are set to the
7792 * first value and the right and left are set to the second.</li>
7793 * <li>If there are three values, the top is set to the first value, the left
7794 * and right are set to the second, and the bottom is set to the third.</li>
7795 * <li>If there are four values, they apply to the top, right, bottom, and
7796 * left, respectively.</li>
7798 * <p>Defaults to: <code>"0"</code></p>
7801 // documented in subclasses
7805 monitorResize : true,
7808 extraCls : 'x-box-item',
7809 targetCls : 'x-box-layout-ct',
7810 innerCls : 'x-box-inner',
7812 constructor : function(config){
7813 Ext.layout.BoxLayout.superclass.constructor.call(this, config);
7815 if (Ext.isString(this.defaultMargins)) {
7816 this.defaultMargins = this.parseMargins(this.defaultMargins);
7822 * Runs the child box calculations and caches them in childBoxCache. Subclasses can used these cached values
7825 onLayout: function(container, target) {
7826 Ext.layout.BoxLayout.superclass.onLayout.call(this, container, target);
7828 var items = this.getVisibleItems(container),
7829 tSize = this.getLayoutTargetSize();
7833 * @property layoutTargetLastSize
7835 * Private cache of the last measured size of the layout target. This should never be used except by
7836 * BoxLayout subclasses during their onLayout run.
7838 this.layoutTargetLastSize = tSize;
7842 * @property childBoxCache
7844 * Array of the last calculated height, width, top and left positions of each visible rendered component
7845 * within the Box layout.
7847 this.childBoxCache = this.calculateChildBoxes(items, tSize);
7849 this.updateInnerCtSize(tSize, this.childBoxCache);
7850 this.updateChildBoxes(this.childBoxCache.boxes);
7852 // Putting a box layout into an overflowed container is NOT correct and will make a second layout pass necessary.
7853 this.handleTargetOverflow(tSize, container, target);
7857 * Resizes and repositions each child component
7858 * @param {Array} boxes The box measurements
7860 updateChildBoxes: function(boxes) {
7861 for (var i = 0, length = boxes.length; i < length; i++) {
7863 comp = box.component;
7865 if (box.dirtySize) {
7866 comp.setSize(box.width, box.height);
7868 // Don't set positions to NaN
7869 if (isNaN(box.left) || isNaN(box.top)) {
7872 comp.setPosition(box.left, box.top);
7878 * Called by onRender just before the child components are sized and positioned. This resizes the innerCt
7879 * to make sure all child items fit within it. We call this before sizing the children because if our child
7880 * items are larger than the previous innerCt size the browser will insert scrollbars and then remove them
7881 * again immediately afterwards, giving a performance hit.
7882 * Subclasses should provide an implementation.
7883 * @param {Object} currentSize The current height and width of the innerCt
7884 * @param {Array} calculations The new box calculations of all items to be laid out
7886 updateInnerCtSize: Ext.emptyFn,
7890 * This should be called after onLayout of any BoxLayout subclass. If the target's overflow is not set to 'hidden',
7891 * we need to lay out a second time because the scrollbars may have modified the height and width of the layout
7892 * target. Having a Box layout inside such a target is therefore not recommended.
7893 * @param {Object} previousTargetSize The size and height of the layout target before we just laid out
7894 * @param {Ext.Container} container The container
7895 * @param {Ext.Element} target The target element
7897 handleTargetOverflow: function(previousTargetSize, container, target) {
7898 var overflow = target.getStyle('overflow');
7900 if (overflow && overflow != 'hidden' &&!this.adjustmentPass) {
7901 var newTargetSize = this.getLayoutTargetSize();
7902 if (newTargetSize.width != previousTargetSize.width || newTargetSize.height != previousTargetSize.height){
7903 this.adjustmentPass = true;
7904 this.onLayout(container, target);
7908 delete this.adjustmentPass;
7912 isValidParent : function(c, target){
7913 return this.innerCt && c.getPositionEl().dom.parentNode == this.innerCt.dom;
7918 * Returns all items that are both rendered and visible
7919 * @return {Array} All matching items
7921 getVisibleItems: function(ct) {
7922 var ct = ct || this.container,
7923 t = ct.getLayoutTarget(),
7924 cti = ct.items.items,
7929 for (i = 0; i < len; i++) {
7930 if((c = cti[i]).rendered && this.isValidParent(c, t) && c.hidden !== true && c.collapsed !== true){
7939 renderAll : function(ct, target){
7941 // the innerCt prevents wrapping and shuffling while
7942 // the container is resizing
7943 this.innerCt = target.createChild({cls:this.innerCls});
7944 this.padding = this.parseMargins(this.padding);
7946 Ext.layout.BoxLayout.superclass.renderAll.call(this, ct, this.innerCt);
7949 getLayoutTargetSize : function(){
7950 var target = this.container.getLayoutTarget(), ret;
7952 ret = target.getViewSize();
7954 // IE in strict mode will return a width of 0 on the 1st pass of getViewSize.
7955 // Use getStyleSize to verify the 0 width, the adjustment pass will then work properly
7957 if (Ext.isIE && Ext.isStrict && ret.width == 0){
7958 ret = target.getStyleSize();
7961 ret.width -= target.getPadding('lr');
7962 ret.height -= target.getPadding('tb');
7968 renderItem : function(c){
7969 if(Ext.isString(c.margins)){
7970 c.margins = this.parseMargins(c.margins);
7971 }else if(!c.margins){
7972 c.margins = this.defaultMargins;
7974 Ext.layout.BoxLayout.superclass.renderItem.apply(this, arguments);
7979 * @class Ext.layout.VBoxLayout
7980 * @extends Ext.layout.BoxLayout
7981 * <p>A layout that arranges items vertically down a Container. This layout optionally divides available vertical
7982 * space between child items containing a numeric <code>flex</code> configuration.</p>
7983 * This layout may also be used to set the widths of child items by configuring it with the {@link #align} option.
7985 Ext.layout.VBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
7987 * @cfg {String} align
7988 * Controls how the child items of the container are aligned. Acceptable configuration values for this
7990 * <div class="mdetail-params"><ul>
7991 * <li><b><tt>left</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned horizontally
7992 * at the <b>left</b> side of the container</div></li>
7993 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are aligned horizontally at the
7994 * <b>mid-width</b> of the container</div></li>
7995 * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched horizontally to fill
7996 * the width of the container</div></li>
7997 * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched horizontally to
7998 * the size of the largest item.</div></li>
8001 align : 'left', // left, center, stretch, strechmax
8005 * @cfg {String} pack
8006 * Controls how the child items of the container are packed together. Acceptable configuration values
8007 * for this property are:
8008 * <div class="mdetail-params"><ul>
8009 * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
8010 * <b>top</b> side of container</div></li>
8011 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
8012 * <b>mid-height</b> of container</div></li>
8013 * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>bottom</b>
8014 * side of container</div></li>
8019 * @cfg {Number} flex
8020 * This configuation option is to be applied to <b>child <tt>items</tt></b> of the container managed
8021 * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>vertically</b>
8022 * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
8023 * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
8024 * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
8029 * See parent documentation
8031 updateInnerCtSize: function(tSize, calcs) {
8032 var innerCtHeight = tSize.height,
8033 innerCtWidth = calcs.meta.maxWidth + this.padding.left + this.padding.right;
8035 if (this.align == 'stretch') {
8036 innerCtWidth = tSize.width;
8037 } else if (this.align == 'center') {
8038 innerCtWidth = Math.max(tSize.width, innerCtWidth);
8041 //we set the innerCt size first because if our child items are larger than the previous innerCt size
8042 //the browser will insert scrollbars and then remove them again immediately afterwards
8043 this.innerCt.setSize(innerCtWidth || undefined, innerCtHeight || undefined);
8048 * Calculates the size and positioning of each item in the VBox. This iterates over all of the rendered,
8049 * visible items and returns a height, width, top and left for each, as well as a reference to each. Also
8050 * returns meta data such as maxHeight which are useful when resizing layout wrappers such as this.innerCt.
8051 * @param {Array} visibleItems The array of all rendered, visible items to be calculated for
8052 * @param {Object} targetSize Object containing target size and height
8053 * @return {Object} Object containing box measurements for each child, plus meta data
8055 calculateChildBoxes: function(visibleItems, targetSize) {
8056 var visibleCount = visibleItems.length,
8058 padding = this.padding,
8059 topOffset = padding.top,
8060 leftOffset = padding.left,
8061 paddingVert = topOffset + padding.bottom,
8062 paddingHoriz = leftOffset + padding.right,
8064 width = targetSize.width - this.scrollOffset,
8065 height = targetSize.height,
8066 availWidth = Math.max(0, width - paddingHoriz),
8068 isStart = this.pack == 'start',
8069 isCenter = this.pack == 'center',
8070 isEnd = this.pack == 'end',
8076 //used to cache the calculated size and position values for each child item
8079 //used in the for loops below, just declared here for brevity
8080 child, childWidth, childHeight, childSize, childMargins, canLayout, i, calcs, flexedHeight, horizMargins, stretchWidth;
8082 //gather the total flex of all flexed items and the width taken up by fixed width items
8083 for (i = 0; i < visibleCount; i++) {
8084 child = visibleItems[i];
8085 childHeight = child.height;
8086 childWidth = child.width;
8087 canLayout = !child.hasLayout && Ext.isFunction(child.doLayout);
8090 // Static height (numeric) requires no calcs
8091 if (!Ext.isNumber(childHeight)) {
8093 // flex and not 'auto' height
8094 if (child.flex && !childHeight) {
8095 totalFlex += child.flex;
8097 // Not flexed or 'auto' height or undefined height
8099 //Render and layout sub-containers without a flex or width defined, as otherwise we
8100 //don't know how wide the sub-container should be and cannot calculate flexed widths
8101 if (!childHeight && canLayout) {
8105 childSize = child.getSize();
8106 childWidth = childSize.width;
8107 childHeight = childSize.height;
8111 childMargins = child.margins;
8113 nonFlexHeight += (childHeight || 0) + childMargins.top + childMargins.bottom;
8115 // Max width for align - force layout of non-layed out subcontainers without a numeric width
8116 if (!Ext.isNumber(childWidth)) {
8120 childWidth = child.getWidth();
8123 maxWidth = Math.max(maxWidth, childWidth + childMargins.left + childMargins.right);
8125 //cache the size of each child component
8128 height : childHeight || undefined,
8129 width : childWidth || undefined
8133 //the height available to the flexed items
8134 var availableHeight = Math.max(0, (height - nonFlexHeight - paddingVert));
8137 topOffset += availableHeight / 2;
8139 topOffset += availableHeight;
8142 //temporary variables used in the flex height calculations below
8143 var remainingHeight = availableHeight,
8144 remainingFlex = totalFlex;
8146 //calculate the height of each flexed item, and the left + top positions of every item
8147 for (i = 0; i < visibleCount; i++) {
8148 child = visibleItems[i];
8151 childMargins = child.margins;
8152 horizMargins = childMargins.left + childMargins.right;
8154 topOffset += childMargins.top;
8156 if (isStart && child.flex && !child.height) {
8157 flexedHeight = Math.ceil((child.flex / remainingFlex) * remainingHeight);
8158 remainingHeight -= flexedHeight;
8159 remainingFlex -= child.flex;
8161 calcs.height = flexedHeight;
8162 calcs.dirtySize = true;
8165 calcs.left = leftOffset + childMargins.left;
8166 calcs.top = topOffset;
8168 switch (this.align) {
8170 stretchWidth = availWidth - horizMargins;
8171 calcs.width = stretchWidth.constrain(child.minHeight || 0, child.maxWidth || 1000000);
8172 calcs.dirtySize = true;
8175 stretchWidth = maxWidth - horizMargins;
8176 calcs.width = stretchWidth.constrain(child.minHeight || 0, child.maxWidth || 1000000);
8177 calcs.dirtySize = true;
8180 var diff = availWidth - calcs.width - horizMargins;
8182 calcs.left = leftOffset + horizMargins + (diff / 2);
8186 topOffset += calcs.height + childMargins.bottom;
8198 Ext.Container.LAYOUTS.vbox = Ext.layout.VBoxLayout;
8201 * @class Ext.layout.HBoxLayout
8202 * @extends Ext.layout.BoxLayout
8203 * <p>A layout that arranges items horizontally across a Container. This layout optionally divides available horizontal
8204 * space between child items containing a numeric <code>flex</code> configuration.</p>
8205 * This layout may also be used to set the heights of child items by configuring it with the {@link #align} option.
8207 Ext.layout.HBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
8209 * @cfg {String} align
8210 * Controls how the child items of the container are aligned. Acceptable configuration values for this
8212 * <div class="mdetail-params"><ul>
8213 * <li><b><tt>top</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned vertically
8214 * at the <b>top</b> of the container</div></li>
8215 * <li><b><tt>middle</tt></b> : <div class="sub-desc">child items are aligned vertically in the
8216 * <b>middle</b> of the container</div></li>
8217 * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched vertically to fill
8218 * the height of the container</div></li>
8219 * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched vertically to
8220 * the height of the largest item.</div></li>
8222 align: 'top', // top, middle, stretch, strechmax
8228 * See parent documentation
8230 updateInnerCtSize: function(tSize, calcs) {
8231 var innerCtWidth = tSize.width,
8232 innerCtHeight = calcs.meta.maxHeight + this.padding.top + this.padding.bottom;
8234 if (this.align == 'stretch') {
8235 innerCtHeight = tSize.height;
8236 } else if (this.align == 'middle') {
8237 innerCtHeight = Math.max(tSize.height, innerCtHeight);
8240 this.innerCt.setSize(innerCtWidth || undefined, innerCtHeight || undefined);
8244 * @cfg {String} pack
8245 * Controls how the child items of the container are packed together. Acceptable configuration values
8246 * for this property are:
8247 * <div class="mdetail-params"><ul>
8248 * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
8249 * <b>left</b> side of container</div></li>
8250 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
8251 * <b>mid-width</b> of container</div></li>
8252 * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>right</b>
8253 * side of container</div></li>
8257 * @cfg {Number} flex
8258 * This configuation option is to be applied to <b>child <tt>items</tt></b> of the container managed
8259 * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>horizontally</b>
8260 * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
8261 * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
8262 * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
8267 * Calculates the size and positioning of each item in the HBox. This iterates over all of the rendered,
8268 * visible items and returns a height, width, top and left for each, as well as a reference to each. Also
8269 * returns meta data such as maxHeight which are useful when resizing layout wrappers such as this.innerCt.
8270 * @param {Array} visibleItems The array of all rendered, visible items to be calculated for
8271 * @param {Object} targetSize Object containing target size and height
8272 * @return {Object} Object containing box measurements for each child, plus meta data
8274 calculateChildBoxes: function(visibleItems, targetSize) {
8275 var visibleCount = visibleItems.length,
8277 padding = this.padding,
8278 topOffset = padding.top,
8279 leftOffset = padding.left,
8280 paddingVert = topOffset + padding.bottom,
8281 paddingHoriz = leftOffset + padding.right,
8283 width = targetSize.width - this.scrollOffset,
8284 height = targetSize.height,
8285 availHeight = Math.max(0, height - paddingVert),
8287 isStart = this.pack == 'start',
8288 isCenter = this.pack == 'center',
8289 isEnd = this.pack == 'end',
8290 // isRestore = ['stretch', 'stretchmax'].indexOf(this.align) == -1,
8296 //used to cache the calculated size and position values for each child item
8299 //used in the for loops below, just declared here for brevity
8300 child, childWidth, childHeight, childSize, childMargins, canLayout, i, calcs, flexedWidth, vertMargins, stretchHeight;
8302 //gather the total flex of all flexed items and the width taken up by fixed width items
8303 for (i = 0; i < visibleCount; i++) {
8304 child = visibleItems[i];
8305 childHeight = child.height;
8306 childWidth = child.width;
8307 canLayout = !child.hasLayout && Ext.isFunction(child.doLayout);
8309 // Static width (numeric) requires no calcs
8310 if (!Ext.isNumber(childWidth)) {
8312 // flex and not 'auto' width
8313 if (child.flex && !childWidth) {
8314 totalFlex += child.flex;
8316 // Not flexed or 'auto' width or undefined width
8318 //Render and layout sub-containers without a flex or width defined, as otherwise we
8319 //don't know how wide the sub-container should be and cannot calculate flexed widths
8320 if (!childWidth && canLayout) {
8324 childSize = child.getSize();
8325 childWidth = childSize.width;
8326 childHeight = childSize.height;
8330 childMargins = child.margins;
8332 nonFlexWidth += (childWidth || 0) + childMargins.left + childMargins.right;
8334 // Max height for align - force layout of non-layed out subcontainers without a numeric height
8335 if (!Ext.isNumber(childHeight)) {
8339 childHeight = child.getHeight();
8342 maxHeight = Math.max(maxHeight, childHeight + childMargins.top + childMargins.bottom);
8344 //cache the size of each child component
8347 height : childHeight || undefined,
8348 width : childWidth || undefined
8352 //the width available to the flexed items
8353 var availableWidth = Math.max(0, (width - nonFlexWidth - paddingHoriz));
8356 leftOffset += availableWidth / 2;
8358 leftOffset += availableWidth;
8361 //temporary variables used in the flex width calculations below
8362 var remainingWidth = availableWidth,
8363 remainingFlex = totalFlex;
8365 //calculate the widths of each flexed item, and the left + top positions of every item
8366 for (i = 0; i < visibleCount; i++) {
8367 child = visibleItems[i];
8370 childMargins = child.margins;
8371 vertMargins = childMargins.top + childMargins.bottom;
8373 leftOffset += childMargins.left;
8375 if (isStart && child.flex && !child.width) {
8376 flexedWidth = Math.ceil((child.flex / remainingFlex) * remainingWidth);
8377 remainingWidth -= flexedWidth;
8378 remainingFlex -= child.flex;
8380 calcs.width = flexedWidth;
8381 calcs.dirtySize = true;
8384 calcs.left = leftOffset;
8385 calcs.top = topOffset + childMargins.top;
8387 switch (this.align) {
8389 stretchHeight = availHeight - vertMargins;
8390 calcs.height = stretchHeight.constrain(child.minHeight || 0, child.maxHeight || 1000000);
8391 calcs.dirtySize = true;
8394 stretchHeight = maxHeight - vertMargins;
8395 calcs.height = stretchHeight.constrain(child.minHeight || 0, child.maxHeight || 1000000);
8396 calcs.dirtySize = true;
8399 var diff = availHeight - calcs.height - vertMargins;
8401 calcs.top = topOffset + vertMargins + (diff / 2);
8404 leftOffset += calcs.width + childMargins.right;
8410 maxHeight: maxHeight
8416 Ext.Container.LAYOUTS.hbox = Ext.layout.HBoxLayout;
8418 * @class Ext.layout.ToolbarLayout
8419 * @extends Ext.layout.ContainerLayout
8420 * Layout manager used by Ext.Toolbar. This is highly specialised for use by Toolbars and would not
8421 * usually be used by any other class.
8423 Ext.layout.ToolbarLayout = Ext.extend(Ext.layout.ContainerLayout, {
8424 monitorResize : true,
8429 * @property triggerWidth
8431 * The width allocated for the menu trigger at the extreme right end of the Toolbar
8436 * @property noItemsMenuText
8438 * HTML fragment to render into the toolbar overflow menu if there are no items to display
8440 noItemsMenuText : '<div class="x-toolbar-no-items">(None)</div>',
8444 * @property lastOverflow
8446 * Used internally to record whether the last layout caused an overflow or not
8448 lastOverflow: false,
8452 * @property tableHTML
8454 * String used to build the HTML injected to support the Toolbar's layout. The align property is
8455 * injected into this string inside the td.x-toolbar-left element during onLayout.
8458 '<table cellspacing="0" class="x-toolbar-ct">',
8461 '<td class="x-toolbar-left" align="{0}">',
8462 '<table cellspacing="0">',
8464 '<tr class="x-toolbar-left-row"></tr>',
8468 '<td class="x-toolbar-right" align="right">',
8469 '<table cellspacing="0" class="x-toolbar-right-ct">',
8473 '<table cellspacing="0">',
8475 '<tr class="x-toolbar-right-row"></tr>',
8480 '<table cellspacing="0">',
8482 '<tr class="x-toolbar-extras-row"></tr>',
8497 * Create the wrapping Toolbar HTML and render/move all the items into the correct places
8499 onLayout : function(ct, target) {
8500 //render the Toolbar <table> HTML if it's not already present
8502 var align = ct.buttonAlign == 'center' ? 'center' : 'left';
8504 target.addClass('x-toolbar-layout-ct');
8505 target.insertHtml('beforeEnd', String.format(this.tableHTML, align));
8507 this.leftTr = target.child('tr.x-toolbar-left-row', true);
8508 this.rightTr = target.child('tr.x-toolbar-right-row', true);
8509 this.extrasTr = target.child('tr.x-toolbar-extras-row', true);
8511 if (this.hiddenItem == undefined) {
8513 * @property hiddenItems
8515 * Holds all items that are currently hidden due to there not being enough space to render them
8516 * These items will appear on the expand menu.
8518 this.hiddenItems = [];
8522 var side = ct.buttonAlign == 'right' ? this.rightTr : this.leftTr,
8523 items = ct.items.items,
8526 //render each item if not already rendered, place it into the correct (left or right) target
8527 for (var i = 0, len = items.length, c; i < len; i++, position++) {
8531 side = this.rightTr;
8533 } else if (!c.rendered) {
8534 c.render(this.insertCell(c, side, position));
8536 if (!c.xtbHidden && !this.isValidParent(c, side.childNodes[position])) {
8537 var td = this.insertCell(c, side, position);
8538 td.appendChild(c.getPositionEl().dom);
8539 c.container = Ext.get(td);
8544 //strip extra empty cells
8545 this.cleanup(this.leftTr);
8546 this.cleanup(this.rightTr);
8547 this.cleanup(this.extrasTr);
8548 this.fitToSize(target);
8553 * Removes any empty nodes from the given element
8554 * @param {Ext.Element} el The element to clean up
8556 cleanup : function(el) {
8557 var cn = el.childNodes, i, c;
8559 for (i = cn.length-1; i >= 0 && (c = cn[i]); i--) {
8560 if (!c.firstChild) {
8568 * Inserts the given Toolbar item into the given element
8569 * @param {Ext.Component} c The component to add
8570 * @param {Ext.Element} target The target to add the component to
8571 * @param {Number} position The position to add the component at
8573 insertCell : function(c, target, position) {
8574 var td = document.createElement('td');
8575 td.className = 'x-toolbar-cell';
8577 target.insertBefore(td, target.childNodes[position] || null);
8584 * Hides an item because it will not fit in the available width. The item will be unhidden again
8585 * if the Toolbar is resized to be large enough to show it
8586 * @param {Ext.Component} item The item to hide
8588 hideItem : function(item) {
8589 this.hiddenItems.push(item);
8591 item.xtbHidden = true;
8592 item.xtbWidth = item.getPositionEl().dom.parentNode.offsetWidth;
8598 * Unhides an item that was previously hidden due to there not being enough space left on the Toolbar
8599 * @param {Ext.Component} item The item to show
8601 unhideItem : function(item) {
8603 item.xtbHidden = false;
8604 this.hiddenItems.remove(item);
8609 * Returns the width of the given toolbar item. If the item is currently hidden because there
8610 * is not enough room to render it, its previous width is returned
8611 * @param {Ext.Component} c The component to measure
8612 * @return {Number} The width of the item
8614 getItemWidth : function(c) {
8615 return c.hidden ? (c.xtbWidth || 0) : c.getPositionEl().dom.parentNode.offsetWidth;
8620 * Called at the end of onLayout. At this point the Toolbar has already been resized, so we need
8621 * to fit the items into the available width. We add up the width required by all of the items in
8622 * the toolbar - if we don't have enough space we hide the extra items and render the expand menu
8624 * @param {Ext.Element} target The Element the Toolbar is currently laid out within
8626 fitToSize : function(target) {
8627 if (this.container.enableOverflow === false) {
8631 var width = target.dom.clientWidth,
8632 tableWidth = target.dom.firstChild.offsetWidth,
8633 clipWidth = width - this.triggerWidth,
8634 lastWidth = this.lastWidth || 0,
8636 hiddenItems = this.hiddenItems,
8637 hasHiddens = hiddenItems.length != 0,
8638 isLarger = width >= lastWidth;
8640 this.lastWidth = width;
8642 if (tableWidth > width || (hasHiddens && isLarger)) {
8643 var items = this.container.items.items,
8648 for (var i = 0; i < len; i++) {
8652 loopWidth += this.getItemWidth(item);
8653 if (loopWidth > clipWidth) {
8654 if (!(item.hidden || item.xtbHidden)) {
8655 this.hideItem(item);
8657 } else if (item.xtbHidden) {
8658 this.unhideItem(item);
8664 //test for number of hidden items again here because they may have changed above
8665 hasHiddens = hiddenItems.length != 0;
8670 if (!this.lastOverflow) {
8671 this.container.fireEvent('overflowchange', this.container, true);
8672 this.lastOverflow = true;
8674 } else if (this.more) {
8676 this.more.destroy();
8679 if (this.lastOverflow) {
8680 this.container.fireEvent('overflowchange', this.container, false);
8681 this.lastOverflow = false;
8688 * Returns a menu config for a given component. This config is used to create a menu item
8689 * to be added to the expander menu
8690 * @param {Ext.Component} component The component to create the config for
8691 * @param {Boolean} hideOnClick Passed through to the menu item
8693 createMenuConfig : function(component, hideOnClick){
8694 var config = Ext.apply({}, component.initialConfig),
8695 group = component.toggleGroup;
8697 Ext.copyTo(config, component, [
8698 'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu'
8702 text : component.overflowText || component.text,
8703 hideOnClick: hideOnClick
8706 if (group || component.enableToggle) {
8709 checked: component.pressed,
8711 checkchange: function(item, checked){
8712 component.toggle(checked);
8718 delete config.ownerCt;
8719 delete config.xtype;
8727 * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually.
8728 * @param {Ext.menu.Menu} menu The menu to add to
8729 * @param {Ext.Component} component The component to add
8731 addComponentToMenu : function(menu, component) {
8732 if (component instanceof Ext.Toolbar.Separator) {
8735 } else if (Ext.isFunction(component.isXType)) {
8736 if (component.isXType('splitbutton')) {
8737 menu.add(this.createMenuConfig(component, true));
8739 } else if (component.isXType('button')) {
8740 menu.add(this.createMenuConfig(component, !component.menu));
8742 } else if (component.isXType('buttongroup')) {
8743 component.items.each(function(item){
8744 this.addComponentToMenu(menu, item);
8752 * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as
8753 * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item
8755 clearMenu : function(){
8756 var menu = this.moreMenu;
8757 if (menu && menu.items) {
8758 menu.items.each(function(item){
8766 * Called before the expand menu is shown, this rebuilds the menu since it was last shown because
8767 * it is possible that the items hidden due to space limitations on the Toolbar have changed since.
8768 * @param {Ext.menu.Menu} m The menu
8770 beforeMoreShow : function(menu) {
8771 var items = this.container.items.items,
8776 var needsSep = function(group, item){
8777 return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator);
8782 for (var i = 0; i < len; i++) {
8784 if (item.xtbHidden) {
8785 if (prev && (needsSep(item, prev) || needsSep(prev, item))) {
8788 this.addComponentToMenu(menu, item);
8793 // put something so the menu isn't empty if no compatible items found
8794 if (menu.items.length < 1) {
8795 menu.add(this.noItemsMenuText);
8801 * Creates the expand trigger and menu, adding them to the <tr> at the extreme right of the
8804 initMore : function(){
8808 * @property moreMenu
8809 * @type Ext.menu.Menu
8810 * The expand menu - holds items for every Toolbar item that cannot be shown
8811 * because the Toolbar is currently not wide enough.
8813 this.moreMenu = new Ext.menu.Menu({
8814 ownerCt : this.container,
8816 beforeshow: this.beforeMoreShow,
8825 * The expand button which triggers the overflow menu to be shown
8827 this.more = new Ext.Button({
8828 iconCls: 'x-toolbar-more-icon',
8829 cls : 'x-toolbar-more',
8830 menu : this.moreMenu,
8831 ownerCt: this.container
8834 var td = this.insertCell(this.more, this.extrasTr, 100);
8835 this.more.render(td);
8839 destroy : function(){
8840 Ext.destroy(this.more, this.moreMenu);
8842 delete this.rightTr;
8843 delete this.extrasTr;
8844 Ext.layout.ToolbarLayout.superclass.destroy.call(this);
8848 Ext.Container.LAYOUTS.toolbar = Ext.layout.ToolbarLayout;
8850 * @class Ext.layout.MenuLayout
8851 * @extends Ext.layout.ContainerLayout
8852 * <p>Layout manager used by {@link Ext.menu.Menu}. Generally this class should not need to be used directly.</p>
8854 Ext.layout.MenuLayout = Ext.extend(Ext.layout.ContainerLayout, {
8855 monitorResize : true,
8859 setContainer : function(ct){
8860 this.monitorResize = !ct.floating;
8861 // This event is only fired by the menu in IE, used so we don't couple
8862 // the menu with the layout.
8863 ct.on('autosize', this.doAutoSize, this);
8864 Ext.layout.MenuLayout.superclass.setContainer.call(this, ct);
8867 renderItem : function(c, position, target){
8868 if (!this.itemTpl) {
8869 this.itemTpl = Ext.layout.MenuLayout.prototype.itemTpl = new Ext.XTemplate(
8870 '<li id="{itemId}" class="{itemCls}">',
8871 '<tpl if="needsIcon">',
8872 '<img src="{icon}" class="{iconCls}"/>',
8878 if(c && !c.rendered){
8879 if(Ext.isNumber(position)){
8880 position = target.dom.childNodes[position];
8882 var a = this.getItemArgs(c);
8884 // The Component's positionEl is the <li> it is rendered into
8885 c.render(c.positionEl = position ?
8886 this.itemTpl.insertBefore(position, a, true) :
8887 this.itemTpl.append(target, a, true));
8889 // Link the containing <li> to the item.
8890 c.positionEl.menuItemId = c.getItemId();
8892 // If rendering a regular Component, and it needs an icon,
8893 // move the Component rightwards.
8894 if (!a.isMenuItem && a.needsIcon) {
8895 c.positionEl.addClass('x-menu-list-item-indent');
8897 this.configureItem(c, position);
8898 }else if(c && !this.isValidParent(c, target)){
8899 if(Ext.isNumber(position)){
8900 position = target.dom.childNodes[position];
8902 target.dom.insertBefore(c.getActionEl().dom, position || null);
8906 getItemArgs : function(c) {
8907 var isMenuItem = c instanceof Ext.menu.Item;
8909 isMenuItem: isMenuItem,
8910 needsIcon: !isMenuItem && (c.icon || c.iconCls),
8911 icon: c.icon || Ext.BLANK_IMAGE_URL,
8912 iconCls: 'x-menu-item-icon ' + (c.iconCls || ''),
8913 itemId: 'x-menu-el-' + c.id,
8914 itemCls: 'x-menu-list-item '
8918 // Valid if the Component is in a <li> which is part of our target <ul>
8919 isValidParent : function(c, target) {
8920 return c.el.up('li.x-menu-list-item', 5).dom.parentNode === (target.dom || target);
8923 onLayout : function(ct, target){
8924 Ext.layout.MenuLayout.superclass.onLayout.call(this, ct, target);
8928 doAutoSize : function(){
8929 var ct = this.container, w = ct.width;
8934 ct.setWidth(Ext.isStrict && (Ext.isIE7 || Ext.isIE8) ? 'auto' : ct.minWidth);
8935 var el = ct.getEl(), t = el.dom.offsetWidth; // force recalc
8936 ct.setWidth(ct.getLayoutTarget().getWidth() + el.getFrameWidth('lr'));
8941 Ext.Container.LAYOUTS['menu'] = Ext.layout.MenuLayout;
8943 * @class Ext.Viewport
8944 * @extends Ext.Container
8945 * <p>A specialized container representing the viewable application area (the browser viewport).</p>
8946 * <p>The Viewport renders itself to the document body, and automatically sizes itself to the size of
8947 * the browser viewport and manages window resizing. There may only be one Viewport created
8948 * in a page. Inner layouts are available by virtue of the fact that all {@link Ext.Panel Panel}s
8949 * added to the Viewport, either through its {@link #items}, or through the items, or the {@link #add}
8950 * method of any of its child Panels may themselves have a layout.</p>
8951 * <p>The Viewport does not provide scrolling, so child Panels within the Viewport should provide
8952 * for scrolling if needed using the {@link #autoScroll} config.</p>
8953 * <p>An example showing a classic application border layout:</p><pre><code>
8958 html: '<h1 class="x-panel-header">Page Title</h1>',
8965 title: 'Navigation',
8967 // the west region might typically utilize a {@link Ext.tree.TreePanel TreePanel} or a Panel with {@link Ext.layout.AccordionLayout Accordion layout}
8970 title: 'Title for Panel',
8972 html: 'Information goes here',
8978 title: 'Title for the Grid Panel',
8983 // remaining grid configuration not shown ...
8984 // notice that the GridPanel is added directly as the region
8985 // it is not "overnested" inside another Panel
8988 xtype: 'tabpanel', // TabPanel itself has no title
8990 title: 'Default Tab',
8991 html: 'The first tab\'s content. Others may be added dynamically'
8997 * Create a new Viewport
8998 * @param {Object} config The config object
9001 Ext.Viewport = Ext.extend(Ext.Container, {
9003 * Privatize config options which, if used, would interfere with the
9004 * correct operation of the Viewport as the sole manager of the
9005 * layout of the document body.
9008 * @cfg {Mixed} applyTo @hide
9011 * @cfg {Boolean} allowDomMove @hide
9014 * @cfg {Boolean} hideParent @hide
9017 * @cfg {Mixed} renderTo @hide
9020 * @cfg {Boolean} hideParent @hide
9023 * @cfg {Number} height @hide
9026 * @cfg {Number} width @hide
9029 * @cfg {Boolean} autoHeight @hide
9032 * @cfg {Boolean} autoWidth @hide
9035 * @cfg {Boolean} deferHeight @hide
9038 * @cfg {Boolean} monitorResize @hide
9041 initComponent : function() {
9042 Ext.Viewport.superclass.initComponent.call(this);
9043 document.getElementsByTagName('html')[0].className += ' x-viewport';
9044 this.el = Ext.getBody();
9045 this.el.setHeight = Ext.emptyFn;
9046 this.el.setWidth = Ext.emptyFn;
9047 this.el.setSize = Ext.emptyFn;
9048 this.el.dom.scroll = 'no';
9049 this.allowDomMove = false;
9050 this.autoWidth = true;
9051 this.autoHeight = true;
9052 Ext.EventManager.onWindowResize(this.fireResize, this);
9053 this.renderTo = this.el;
9056 fireResize : function(w, h){
9057 this.fireEvent('resize', this, w, h, w, h);
9060 Ext.reg('viewport', Ext.Viewport);
9063 * @extends Ext.Container
9064 * <p>Panel is a container that has specific functionality and structural components that make
9065 * it the perfect building block for application-oriented user interfaces.</p>
9066 * <p>Panels are, by virtue of their inheritance from {@link Ext.Container}, capable
9067 * of being configured with a {@link Ext.Container#layout layout}, and containing child Components.</p>
9068 * <p>When either specifying child {@link Ext.Component#items items} of a Panel, or dynamically {@link Ext.Container#add adding} Components
9069 * to a Panel, remember to consider how you wish the Panel to arrange those child elements, and whether
9070 * 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
9071 * default, Panels use the {@link Ext.layout.ContainerLayout ContainerLayout} scheme. This simply renders
9072 * child components, appending them one after the other inside the Container, and <b>does not apply any sizing</b>
9074 * <p>A Panel may also contain {@link #bbar bottom} and {@link #tbar top} toolbars, along with separate
9075 * {@link #header}, {@link #footer} and {@link #body} sections (see {@link #frame} for additional
9077 * <p>Panel also provides built-in {@link #collapsible expandable and collapsible behavior}, along with
9078 * a variety of {@link #tools prebuilt tool buttons} that can be wired up to provide other customized
9079 * behavior. Panels can be easily dropped into any {@link Ext.Container Container} or layout, and the
9080 * layout and rendering pipeline is {@link Ext.Container#add completely managed by the framework}.</p>
9082 * @param {Object} config The config object
9085 Ext.Panel = Ext.extend(Ext.Container, {
9087 * The Panel's header {@link Ext.Element Element}. Read-only.
9088 * <p>This Element is used to house the {@link #title} and {@link #tools}</p>
9089 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
9094 * The Panel's body {@link Ext.Element Element} which may be used to contain HTML content.
9095 * The content may be specified in the {@link #html} config, or it may be loaded using the
9096 * {@link autoLoad} config, or through the Panel's {@link #getUpdater Updater}. Read-only.
9097 * <p>If this is used to load visible HTML elements in either way, then
9098 * the Panel may not be used as a Layout for hosting nested Panels.</p>
9099 * <p>If this Panel is intended to be used as the host of a Layout (See {@link #layout}
9100 * then the body Element must not be loaded or changed - it is under the control
9101 * of the Panel's Layout.
9102 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
9107 * The Panel's bwrap {@link Ext.Element Element} used to contain other Panel elements
9108 * (tbar, body, bbar, footer). See {@link #bodyCfg}. Read-only.
9113 * True if this panel is collapsed. Read-only.
9115 * @property collapsed
9118 * @cfg {Object} bodyCfg
9119 * <p>A {@link Ext.DomHelper DomHelper} element specification object may be specified for any
9120 * Panel Element.</p>
9121 * <p>By default, the Default element in the table below will be used for the html markup to
9122 * create a child element with the commensurate Default class name (<code>baseCls</code> will be
9123 * replaced by <code>{@link #baseCls}</code>):</p>
9125 * Panel Default Default Custom Additional Additional
9126 * Element element class element class style
9127 * ======== ========================== ========= ============== ===========
9128 * {@link #header} div {@link #baseCls}+'-header' {@link #headerCfg} headerCssClass headerStyle
9129 * {@link #bwrap} div {@link #baseCls}+'-bwrap' {@link #bwrapCfg} bwrapCssClass bwrapStyle
9130 * + tbar div {@link #baseCls}+'-tbar' {@link #tbarCfg} tbarCssClass tbarStyle
9131 * + {@link #body} div {@link #baseCls}+'-body' {@link #bodyCfg} {@link #bodyCssClass} {@link #bodyStyle}
9132 * + bbar div {@link #baseCls}+'-bbar' {@link #bbarCfg} bbarCssClass bbarStyle
9133 * + {@link #footer} div {@link #baseCls}+'-footer' {@link #footerCfg} footerCssClass footerStyle
9135 * <p>Configuring a Custom element may be used, for example, to force the {@link #body} Element
9136 * to use a different form of markup than is created by default. An example of this might be
9137 * to {@link Ext.Element#createChild create a child} Panel containing a custom content, such as
9138 * a header, or forcing centering of all Panel content by having the body be a <center>
9142 title: 'Message Title',
9143 renderTo: Ext.getBody(),
9144 width: 200, height: 130,
9147 cls: 'x-panel-body', // Default class not applied if Custom element specified
9152 cls: 'x-panel-footer' // same as the Default class
9155 footerCssClass: 'custom-footer', // additional css class, see {@link Ext.element#addClass addClass}
9156 footerStyle: 'background-color:red' // see {@link #bodyStyle}
9159 * <p>The example above also explicitly creates a <code>{@link #footer}</code> with custom markup and
9160 * styling applied.</p>
9163 * @cfg {Object} headerCfg
9164 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
9165 * of this Panel's {@link #header} Element. See <code>{@link #bodyCfg}</code> also.</p>
9168 * @cfg {Object} bwrapCfg
9169 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
9170 * of this Panel's {@link #bwrap} Element. See <code>{@link #bodyCfg}</code> also.</p>
9173 * @cfg {Object} tbarCfg
9174 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
9175 * of this Panel's {@link #tbar} Element. See <code>{@link #bodyCfg}</code> also.</p>
9178 * @cfg {Object} bbarCfg
9179 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
9180 * of this Panel's {@link #bbar} Element. See <code>{@link #bodyCfg}</code> also.</p>
9183 * @cfg {Object} footerCfg
9184 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
9185 * of this Panel's {@link #footer} Element. See <code>{@link #bodyCfg}</code> also.</p>
9188 * @cfg {Boolean} closable
9189 * Panels themselves do not directly support being closed, but some Panel subclasses do (like
9190 * {@link Ext.Window}) or a Panel Class within an {@link Ext.TabPanel}. Specify <code>true</code>
9191 * to enable closing in such situations. Defaults to <code>false</code>.
9194 * The Panel's footer {@link Ext.Element Element}. Read-only.
9195 * <p>This Element is used to house the Panel's <code>{@link #buttons}</code> or <code>{@link #fbar}</code>.</p>
9196 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
9201 * @cfg {Mixed} applyTo
9202 * <p>The id of the node, a DOM node or an existing Element corresponding to a DIV that is already present in
9203 * the document that specifies some panel-specific structural markup. When <code>applyTo</code> is used,
9204 * constituent parts of the panel can be specified by CSS class name within the main element, and the panel
9205 * will automatically create those components from that markup. Any required components not specified in the
9206 * markup will be autogenerated if necessary.</p>
9207 * <p>The following class names are supported (baseCls will be replaced by {@link #baseCls}):</p>
9208 * <ul><li>baseCls + '-header'</li>
9209 * <li>baseCls + '-header-text'</li>
9210 * <li>baseCls + '-bwrap'</li>
9211 * <li>baseCls + '-tbar'</li>
9212 * <li>baseCls + '-body'</li>
9213 * <li>baseCls + '-bbar'</li>
9214 * <li>baseCls + '-footer'</li></ul>
9215 * <p>Using this config, a call to render() is not required. If applyTo is specified, any value passed for
9216 * {@link #renderTo} will be ignored and the target element's parent node will automatically be used as the
9217 * panel's container.</p>
9220 * @cfg {Object/Array} tbar
9221 * <p>The top toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
9222 * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render.
9223 * To access the top toolbar after render, use {@link #getTopToolbar}.</p>
9224 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
9225 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
9226 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
9227 * submission parameters are collected from the DOM tree.</p>
9230 * @cfg {Object/Array} bbar
9231 * <p>The bottom toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
9232 * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render.
9233 * To access the bottom toolbar after render, use {@link #getBottomToolbar}.</p>
9234 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
9235 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
9236 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
9237 * submission parameters are collected from the DOM tree.</p>
9239 /** @cfg {Object/Array} fbar
9240 * <p>A {@link Ext.Toolbar Toolbar} object, a Toolbar config, or an array of
9241 * {@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>
9242 * <p>After render, the <code>fbar</code> property will be an {@link Ext.Toolbar Toolbar} instance.</p>
9243 * <p>If <code>{@link #buttons}</code> are specified, they will supersede the <code>fbar</code> configuration property.</p>
9244 * The Panel's <code>{@link #buttonAlign}</code> configuration affects the layout of these items, for example:
9246 var w = new Ext.Window({
9249 bbar: new Ext.Toolbar({
9256 {@link #buttonAlign}: 'left', // anything but 'center' or 'right' and you can use '-', and '->'
9257 // to control the alignment of fbar items
9265 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
9266 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
9267 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
9268 * submission parameters are collected from the DOM tree.</p>
9271 * @cfg {Boolean} header
9272 * <code>true</code> to create the Panel's header element explicitly, <code>false</code> to skip creating
9273 * it. If a <code>{@link #title}</code> is set the header will be created automatically, otherwise it will not.
9274 * If a <code>{@link #title}</code> is set but <code>header</code> is explicitly set to <code>false</code>, the header
9275 * will not be rendered.
9278 * @cfg {Boolean} footer
9279 * <code>true</code> to create the footer element explicitly, false to skip creating it. The footer
9280 * will be created automatically if <code>{@link #buttons}</code> or a <code>{@link #fbar}</code> have
9281 * been configured. See <code>{@link #bodyCfg}</code> for an example.
9284 * @cfg {String} title
9285 * The title text to be used as innerHTML (html tags are accepted) to display in the panel
9286 * <code>{@link #header}</code> (defaults to ''). When a <code>title</code> is specified the
9287 * <code>{@link #header}</code> element will automatically be created and displayed unless
9288 * {@link #header} is explicitly set to <code>false</code>. If you do not want to specify a
9289 * <code>title</code> at config time, but you may want one later, you must either specify a non-empty
9290 * <code>title</code> (a blank space ' ' will do) or <code>header:true</code> so that the container
9291 * element will get created.
9294 * @cfg {Array} buttons
9295 * <code>buttons</code> will be used as <code>{@link Ext.Container#items items}</code> for the toolbar in
9296 * the footer (<code>{@link #fbar}</code>). Typically the value of this configuration property will be
9297 * an array of {@link Ext.Button}s or {@link Ext.Button} configuration objects.
9298 * If an item is configured with <code>minWidth</code> or the Panel is configured with <code>minButtonWidth</code>,
9299 * that width will be applied to the item.
9302 * @cfg {Object/String/Function} autoLoad
9303 * A valid url spec according to the Updater {@link Ext.Updater#update} method.
9304 * If autoLoad is not null, the panel will attempt to load its contents
9305 * immediately upon render.<p>
9306 * The URL will become the default URL for this panel's {@link #body} element,
9307 * so it may be {@link Ext.Element#refresh refresh}ed at any time.</p>
9310 * @cfg {Boolean} frame
9311 * <code>false</code> by default to render with plain 1px square borders. <code>true</code> to render with
9312 * 9 elements, complete with custom rounded corners (also see {@link Ext.Element#boxWrap}).
9313 * <p>The template generated for each condition is depicted below:</p><pre><code>
9316 <div id="developer-specified-id-goes-here" class="x-panel">
9318 <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:false)</span></div>
9320 <div class="x-panel-bwrap">
9321 <div class="x-panel-body"><p>html value goes here</p></div>
9325 // frame = true (create 9 elements)
9326 <div id="developer-specified-id-goes-here" class="x-panel">
9327 <div class="x-panel-tl"><div class="x-panel-tr"><div class="x-panel-tc">
9328 <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:true)</span></div>
9329 </div></div></div>
9331 <div class="x-panel-bwrap">
9332 <div class="x-panel-ml"><div class="x-panel-mr"><div class="x-panel-mc">
9333 <div class="x-panel-body"><p>html value goes here</p></div>
9334 </div></div></div>
9336 <div class="x-panel-bl"><div class="x-panel-br"><div class="x-panel-bc"/>
9337 </div></div></div>
9342 * @cfg {Boolean} border
9343 * True to display the borders of the panel's body element, false to hide them (defaults to true). By default,
9344 * the border is a 2px wide inset border, but this can be further altered by setting {@link #bodyBorder} to false.
9347 * @cfg {Boolean} bodyBorder
9348 * True to display an interior border on the body element of the panel, false to hide it (defaults to true).
9349 * This only applies when {@link #border} == true. If border == true and bodyBorder == false, the border will display
9350 * as a 1px wide inset border, giving the entire body element an inset appearance.
9353 * @cfg {String/Object/Function} bodyCssClass
9354 * Additional css class selector to be applied to the {@link #body} element in the format expected by
9355 * {@link Ext.Element#addClass} (defaults to null). See {@link #bodyCfg}.
9358 * @cfg {String/Object/Function} bodyStyle
9359 * Custom CSS styles to be applied to the {@link #body} element in the format expected by
9360 * {@link Ext.Element#applyStyles} (defaults to null). See {@link #bodyCfg}.
9363 * @cfg {String} iconCls
9364 * The CSS class selector that specifies a background image to be used as the header icon (defaults to '').
9365 * <p>An example of specifying a custom icon class would be something like:
9367 // specify the property in the config for the class:
9371 // css class that specifies background image to be used as the icon image:
9372 .my-icon { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
9376 * @cfg {Boolean} collapsible
9377 * True to make the panel collapsible and have the expand/collapse toggle button automatically rendered into
9378 * the header tool button area, false to keep the panel statically sized with no button (defaults to false).
9381 * @cfg {Array} tools
9382 * An array of tool button configs to be added to the header tool area. When rendered, each tool is
9383 * stored as an {@link Ext.Element Element} referenced by a public property called <code><b></b>tools.<i><tool-type></i></code>
9384 * <p>Each tool config may contain the following properties:
9385 * <div class="mdetail-params"><ul>
9386 * <li><b>id</b> : String<div class="sub-desc"><b>Required.</b> The type
9387 * of tool to create. By default, this assigns a CSS class of the form <code>x-tool-<i><tool-type></i></code> to the
9388 * resulting tool Element. Ext provides CSS rules, and an icon sprite containing images for the tool types listed below.
9389 * The developer may implement custom tools by supplying alternate CSS rules and background images:
9391 * <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>
9392 * <div class="x-tool x-tool-close" style="float:left; margin-right:5;"> </div><div><code> close</code></div>
9393 * <div class="x-tool x-tool-minimize" style="float:left; margin-right:5;"> </div><div><code> minimize</code></div>
9394 * <div class="x-tool x-tool-maximize" style="float:left; margin-right:5;"> </div><div><code> maximize</code></div>
9395 * <div class="x-tool x-tool-restore" style="float:left; margin-right:5;"> </div><div><code> restore</code></div>
9396 * <div class="x-tool x-tool-gear" style="float:left; margin-right:5;"> </div><div><code> gear</code></div>
9397 * <div class="x-tool x-tool-pin" style="float:left; margin-right:5;"> </div><div><code> pin</code></div>
9398 * <div class="x-tool x-tool-unpin" style="float:left; margin-right:5;"> </div><div><code> unpin</code></div>
9399 * <div class="x-tool x-tool-right" style="float:left; margin-right:5;"> </div><div><code> right</code></div>
9400 * <div class="x-tool x-tool-left" style="float:left; margin-right:5;"> </div><div><code> left</code></div>
9401 * <div class="x-tool x-tool-up" style="float:left; margin-right:5;"> </div><div><code> up</code></div>
9402 * <div class="x-tool x-tool-down" style="float:left; margin-right:5;"> </div><div><code> down</code></div>
9403 * <div class="x-tool x-tool-refresh" style="float:left; margin-right:5;"> </div><div><code> refresh</code></div>
9404 * <div class="x-tool x-tool-minus" style="float:left; margin-right:5;"> </div><div><code> minus</code></div>
9405 * <div class="x-tool x-tool-plus" style="float:left; margin-right:5;"> </div><div><code> plus</code></div>
9406 * <div class="x-tool x-tool-help" style="float:left; margin-right:5;"> </div><div><code> help</code></div>
9407 * <div class="x-tool x-tool-search" style="float:left; margin-right:5;"> </div><div><code> search</code></div>
9408 * <div class="x-tool x-tool-save" style="float:left; margin-right:5;"> </div><div><code> save</code></div>
9409 * <div class="x-tool x-tool-print" style="float:left; margin-right:5;"> </div><div><code> print</code></div>
9411 * <li><b>handler</b> : Function<div class="sub-desc"><b>Required.</b> The function to
9412 * call when clicked. Arguments passed are:<ul>
9413 * <li><b>event</b> : Ext.EventObject<div class="sub-desc">The click event.</div></li>
9414 * <li><b>toolEl</b> : Ext.Element<div class="sub-desc">The tool Element.</div></li>
9415 * <li><b>panel</b> : Ext.Panel<div class="sub-desc">The host Panel</div></li>
9416 * <li><b>tc</b> : Object<div class="sub-desc">The tool configuration object</div></li>
9418 * <li><b>stopEvent</b> : Boolean<div class="sub-desc">Defaults to true. Specify as false to allow click event to propagate.</div></li>
9419 * <li><b>scope</b> : Object<div class="sub-desc">The scope in which to call the handler.</div></li>
9420 * <li><b>qtip</b> : String/Object<div class="sub-desc">A tip string, or
9421 * a config argument to {@link Ext.QuickTip#register}</div></li>
9422 * <li><b>hidden</b> : Boolean<div class="sub-desc">True to initially render hidden.</div></li>
9423 * <li><b>on</b> : Object<div class="sub-desc">A listener config object specifiying
9424 * event listeners in the format of an argument to {@link #addListener}</div></li>
9426 * <p>Note that, apart from the toggle tool which is provided when a panel is collapsible, these
9427 * tools only provide the visual button. Any required functionality must be provided by adding
9428 * handlers that implement the necessary behavior.</p>
9429 * <p>Example usage:</p>
9433 qtip: 'Refresh form Data',
9435 handler: function(event, toolEl, panel){
9442 handler: function(event, toolEl, panel){
9447 * <p>For the custom id of <code>'help'</code> define two relevant css classes with a link to
9448 * a 15x15 image:</p>
9450 .x-tool-help {background-image: url(images/help.png);}
9451 .x-tool-help-over {background-image: url(images/help_over.png);}
9452 // if using an image sprite:
9453 .x-tool-help {background-image: url(images/help.png) no-repeat 0 0;}
9454 .x-tool-help-over {background-position:-15px 0;}
9458 * @cfg {Ext.Template/Ext.XTemplate} toolTemplate
9459 * <p>A Template used to create {@link #tools} in the {@link #header} Element. Defaults to:</p><pre><code>
9460 new Ext.Template('<div class="x-tool x-tool-{id}">&#160;</div>')</code></pre>
9461 * <p>This may may be overridden to provide a custom DOM structure for tools based upon a more
9462 * complex XTemplate. The template's data is a single tool configuration object (Not the entire Array)
9463 * as specified in {@link #tools}. In the following example an <a> tag is used to provide a
9464 * visual indication when hovering over the tool:</p><pre><code>
9465 var win = new Ext.Window({
9468 href: '/MyPdfDoc.pdf'
9470 toolTemplate: new Ext.XTemplate(
9471 '<tpl if="id==\'download\'">',
9472 '<a class="x-tool x-tool-pdf" href="{href}"></a>',
9474 '<tpl if="id!=\'download\'">',
9475 '<div class="x-tool x-tool-{id}">&#160;</div>',
9482 * <p>Note that the CSS class 'x-tool-pdf' should have an associated style rule which provides an
9483 * appropriate background image, something like:</p>
9485 a.x-tool-pdf {background-image: url(../shared/extjs/images/pdf.gif)!important;}
9489 * @cfg {Boolean} hideCollapseTool
9490 * <code>true</code> to hide the expand/collapse toggle button when <code>{@link #collapsible} == true</code>,
9491 * <code>false</code> to display it (defaults to <code>false</code>).
9494 * @cfg {Boolean} titleCollapse
9495 * <code>true</code> to allow expanding and collapsing the panel (when <code>{@link #collapsible} = true</code>)
9496 * by clicking anywhere in the header bar, <code>false</code>) to allow it only by clicking to tool button
9497 * (defaults to <code>false</code>)). If this panel is a child item of a border layout also see the
9498 * {@link Ext.layout.BorderLayout.Region BorderLayout.Region}
9499 * <code>{@link Ext.layout.BorderLayout.Region#floatable floatable}</code> config option.
9503 * @cfg {Mixed} floating
9504 * <p>This property is used to configure the underlying {@link Ext.Layer}. Acceptable values for this
9505 * configuration property are:</p><div class="mdetail-params"><ul>
9506 * <li><b><code>false</code></b> : <b>Default.</b><div class="sub-desc">Display the panel inline where it is
9507 * rendered.</div></li>
9508 * <li><b><code>true</code></b> : <div class="sub-desc">Float the panel (absolute position it with automatic
9509 * shimming and shadow).<ul>
9510 * <div class="sub-desc">Setting floating to true will create an Ext.Layer for this panel and display the
9511 * panel at negative offsets so that it is hidden.</div>
9512 * <div class="sub-desc">Since the panel will be absolute positioned, the position must be set explicitly
9513 * <i>after</i> render (e.g., <code>myPanel.setPosition(100,100);</code>).</div>
9514 * <div class="sub-desc"><b>Note</b>: when floating a panel you should always assign a fixed width,
9515 * otherwise it will be auto width and will expand to fill to the right edge of the viewport.</div>
9517 * <li><b><code>{@link Ext.Layer object}</code></b> : <div class="sub-desc">The specified object will be used
9518 * as the configuration object for the {@link Ext.Layer} that will be created.</div></li>
9522 * @cfg {Boolean/String} shadow
9523 * <code>true</code> (or a valid Ext.Shadow {@link Ext.Shadow#mode} value) to display a shadow behind the
9524 * panel, <code>false</code> to display no shadow (defaults to <code>'sides'</code>). Note that this option
9525 * only applies when <code>{@link #floating} = true</code>.
9528 * @cfg {Number} shadowOffset
9529 * The number of pixels to offset the shadow if displayed (defaults to <code>4</code>). Note that this
9530 * option only applies when <code>{@link #floating} = true</code>.
9533 * @cfg {Boolean} shim
9534 * <code>false</code> to disable the iframe shim in browsers which need one (defaults to <code>true</code>).
9535 * Note that this option only applies when <code>{@link #floating} = true</code>.
9538 * @cfg {Object/Array} keys
9539 * A {@link Ext.KeyMap} config object (in the format expected by {@link Ext.KeyMap#addBinding}
9540 * used to assign custom key handling to this panel (defaults to <code>null</code>).
9543 * @cfg {Boolean/Object} draggable
9544 * <p><code>true</code> to enable dragging of this Panel (defaults to <code>false</code>).</p>
9545 * <p>For custom drag/drop implementations, an <b>Ext.Panel.DD</b> config could also be passed
9546 * in this config instead of <code>true</code>. Ext.Panel.DD is an internal, undocumented class which
9547 * moves a proxy Element around in place of the Panel's element, but provides no other behaviour
9548 * during dragging or on drop. It is a subclass of {@link Ext.dd.DragSource}, so behaviour may be
9549 * added by implementing the interface methods of {@link Ext.dd.DragDrop} e.g.:
9555 renderTo: Ext.getBody(),
9561 // Config option of Ext.Panel.DD class.
9562 // It's a floating Panel, so do not show a placeholder proxy in the original position.
9565 // Called for each mousemove event while dragging the DD object.
9566 onDrag : function(e){
9567 // Record the x,y position of the drag proxy so that we can
9568 // position the Panel at end of drag.
9569 var pel = this.proxy.getEl();
9570 this.x = pel.getLeft(true);
9571 this.y = pel.getTop(true);
9573 // Keep the Shadow aligned if there is one.
9574 var s = this.panel.getEl().shadow;
9576 s.realign(this.x, this.y, pel.getWidth(), pel.getHeight());
9580 // Called on the mouseup event.
9581 endDrag : function(e){
9582 this.panel.setPosition(this.x, this.y);
9589 * @cfg {Boolean} disabled
9590 * Render this panel disabled (default is <code>false</code>). An important note when using the disabled
9591 * config on panels is that IE will often fail to initialize the disabled mask element correectly if
9592 * the panel's layout has not yet completed by the time the Panel is disabled during the render process.
9593 * If you experience this issue, you may need to instead use the {@link #afterlayout} event to initialize
9594 * the disabled state:
9603 single: true // important, as many layouts can occur
9610 * @cfg {Boolean} autoHeight
9611 * <code>true</code> to use height:'auto', <code>false</code> to use fixed height (defaults to <code>false</code>).
9612 * <b>Note</b>: Setting <code>autoHeight: true</code> means that the browser will manage the panel's height
9613 * based on its contents, and that Ext will not manage it at all. If the panel is within a layout that
9614 * manages dimensions (<code>fit</code>, <code>border</code>, etc.) then setting <code>autoHeight: true</code>
9615 * can cause issues with scrolling and will not generally work as expected since the panel will take
9616 * on the height of its contents rather than the height required by the Ext layout.
9621 * @cfg {String} baseCls
9622 * The base CSS class to apply to this panel's element (defaults to <code>'x-panel'</code>).
9623 * <p>Another option available by default is to specify <code>'x-plain'</code> which strips all styling
9624 * except for required attributes for Ext layouts to function (e.g. overflow:hidden).
9625 * See <code>{@link #unstyled}</code> also.</p>
9627 baseCls : 'x-panel',
9629 * @cfg {String} collapsedCls
9630 * A CSS class to add to the panel's element after it has been collapsed (defaults to
9631 * <code>'x-panel-collapsed'</code>).
9633 collapsedCls : 'x-panel-collapsed',
9635 * @cfg {Boolean} maskDisabled
9636 * <code>true</code> to mask the panel when it is {@link #disabled}, <code>false</code> to not mask it (defaults
9637 * to <code>true</code>). Either way, the panel will always tell its contained elements to disable themselves
9638 * when it is disabled, but masking the panel can provide an additional visual cue that the panel is
9641 maskDisabled : true,
9643 * @cfg {Boolean} animCollapse
9644 * <code>true</code> to animate the transition when the panel is collapsed, <code>false</code> to skip the
9645 * animation (defaults to <code>true</code> if the {@link Ext.Fx} class is available, otherwise <code>false</code>).
9647 animCollapse : Ext.enableFx,
9649 * @cfg {Boolean} headerAsText
9650 * <code>true</code> to display the panel <code>{@link #title}</code> in the <code>{@link #header}</code>,
9651 * <code>false</code> to hide it (defaults to <code>true</code>).
9653 headerAsText : true,
9655 * @cfg {String} buttonAlign
9656 * The alignment of any {@link #buttons} added to this panel. Valid values are <code>'right'</code>,
9657 * <code>'left'</code> and <code>'center'</code> (defaults to <code>'right'</code>).
9659 buttonAlign : 'right',
9661 * @cfg {Boolean} collapsed
9662 * <code>true</code> to render the panel collapsed, <code>false</code> to render it expanded (defaults to
9663 * <code>false</code>).
9667 * @cfg {Boolean} collapseFirst
9668 * <code>true</code> to make sure the collapse/expand toggle button always renders first (to the left of)
9669 * any other tools in the panel's title bar, <code>false</code> to render it last (defaults to <code>true</code>).
9671 collapseFirst : true,
9673 * @cfg {Number} minButtonWidth
9674 * Minimum width in pixels of all {@link #buttons} in this panel (defaults to <code>75</code>)
9676 minButtonWidth : 75,
9678 * @cfg {Boolean} unstyled
9679 * Overrides the <code>{@link #baseCls}</code> setting to <code>{@link #baseCls} = 'x-plain'</code> which renders
9680 * the panel unstyled except for required attributes for Ext layouts to function (e.g. overflow:hidden).
9683 * @cfg {String} elements
9684 * A comma-delimited list of panel elements to initialize when the panel is rendered. Normally, this list will be
9685 * generated automatically based on the items added to the panel at config time, but sometimes it might be useful to
9686 * make sure a structural element is rendered even if not specified at config time (for example, you may want
9687 * to add a button or toolbar dynamically after the panel has been rendered). Adding those elements to this
9688 * list will allocate the required placeholders in the panel when it is rendered. Valid values are<div class="mdetail-params"><ul>
9689 * <li><code>header</code></li>
9690 * <li><code>tbar</code> (top bar)</li>
9691 * <li><code>body</code></li>
9692 * <li><code>bbar</code> (bottom bar)</li>
9693 * <li><code>footer</code></li>
9695 * Defaults to '<code>body</code>'.
9699 * @cfg {Boolean} preventBodyReset
9700 * Defaults to <code>false</code>. When set to <code>true</code>, an extra css class <code>'x-panel-normal'</code>
9701 * will be added to the panel's element, effectively applying css styles suggested by the W3C
9702 * (see http://www.w3.org/TR/CSS21/sample.html) to the Panel's <b>body</b> element (not the header,
9705 preventBodyReset : false,
9708 * @cfg {Number/String} padding
9709 * A shortcut for setting a padding style on the body element. The value can either be
9710 * a number to be applied to all sides, or a normal css string describing padding.
9711 * Defaults to <tt>undefined</tt>.
9716 /** @cfg {String} resizeEvent
9717 * The event to listen to for resizing in layouts. Defaults to <tt>'bodyresize'</tt>.
9719 resizeEvent: 'bodyresize',
9721 // protected - these could be used to customize the behavior of the window,
9722 // but changing them would not be useful without further mofifications and
9723 // could lead to unexpected or undesirable results.
9724 toolTarget : 'header',
9725 collapseEl : 'bwrap',
9729 // private, notify box this class will handle heights
9736 collapseDefaults : {
9741 initComponent : function(){
9742 Ext.Panel.superclass.initComponent.call(this);
9747 * Fires after the Panel has been resized.
9748 * @param {Ext.Panel} p the Panel which has been resized.
9749 * @param {Number} width The Panel body's new width.
9750 * @param {Number} height The Panel body's new height.
9754 * @event titlechange
9755 * Fires after the Panel title has been {@link #title set} or {@link #setTitle changed}.
9756 * @param {Ext.Panel} p the Panel which has had its title changed.
9757 * @param {String} The new title.
9762 * Fires after the Panel icon class has been {@link #iconCls set} or {@link #setIconClass changed}.
9763 * @param {Ext.Panel} p the Panel which has had its {@link #iconCls icon class} changed.
9764 * @param {String} The new icon class.
9765 * @param {String} The old icon class.
9770 * Fires after the Panel has been collapsed.
9771 * @param {Ext.Panel} p the Panel that has been collapsed.
9776 * Fires after the Panel has been expanded.
9777 * @param {Ext.Panel} p The Panel that has been expanded.
9781 * @event beforecollapse
9782 * Fires before the Panel is collapsed. A handler can return false to cancel the collapse.
9783 * @param {Ext.Panel} p the Panel being collapsed.
9784 * @param {Boolean} animate True if the collapse is animated, else false.
9788 * @event beforeexpand
9789 * Fires before the Panel is expanded. A handler can return false to cancel the expand.
9790 * @param {Ext.Panel} p The Panel being expanded.
9791 * @param {Boolean} animate True if the expand is animated, else false.
9795 * @event beforeclose
9796 * Fires before the Panel is closed. Note that Panels do not directly support being closed, but some
9797 * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel. This event only
9798 * applies to such subclasses.
9799 * A handler can return false to cancel the close.
9800 * @param {Ext.Panel} p The Panel being closed.
9805 * Fires after the Panel is closed. Note that Panels do not directly support being closed, but some
9806 * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel.
9807 * @param {Ext.Panel} p The Panel that has been closed.
9812 * Fires after the Panel has been visually activated.
9813 * Note that Panels do not directly support being activated, but some Panel subclasses
9814 * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
9815 * activate and deactivate events under the control of the TabPanel.
9816 * @param {Ext.Panel} p The Panel that has been activated.
9821 * Fires after the Panel has been visually deactivated.
9822 * Note that Panels do not directly support being deactivated, but some Panel subclasses
9823 * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
9824 * activate and deactivate events under the control of the TabPanel.
9825 * @param {Ext.Panel} p The Panel that has been deactivated.
9831 this.baseCls = 'x-plain';
9838 this.elements += ',tbar';
9839 this.topToolbar = this.createToolbar(this.tbar);
9844 this.elements += ',bbar';
9845 this.bottomToolbar = this.createToolbar(this.bbar);
9849 if(this.header === true){
9850 this.elements += ',header';
9852 }else if(this.headerCfg || (this.title && this.header !== false)){
9853 this.elements += ',header';
9856 if(this.footerCfg || this.footer === true){
9857 this.elements += ',footer';
9862 this.fbar = this.buttons;
9863 this.buttons = null;
9866 this.createFbar(this.fbar);
9869 this.on('render', this.doAutoLoad, this, {delay:10});
9874 createFbar : function(fbar){
9875 var min = this.minButtonWidth;
9876 this.elements += ',footer';
9877 this.fbar = this.createToolbar(fbar, {
9878 buttonAlign: this.buttonAlign,
9879 toolbarCls: 'x-panel-fbar',
9880 enableOverflow: false,
9881 defaults: function(c){
9883 minWidth: c.minWidth || min
9887 // @compat addButton and buttons could possibly be removed
9890 * This Panel's Array of buttons as created from the <code>{@link #buttons}</code>
9891 * config property. Read only.
9895 this.fbar.items.each(function(c){
9896 c.minWidth = c.minWidth || this.minButtonWidth;
9898 this.buttons = this.fbar.items.items;
9902 createToolbar: function(tb, options){
9904 // Convert array to proper toolbar config
9905 if(Ext.isArray(tb)){
9910 result = tb.events ? Ext.apply(tb, options) : this.createComponent(Ext.apply({}, tb, options), 'toolbar');
9911 this.toolbars.push(result);
9916 createElement : function(name, pnode){
9918 pnode.appendChild(this[name].dom);
9922 if(name === 'bwrap' || this.elements.indexOf(name) != -1){
9923 if(this[name+'Cfg']){
9924 this[name] = Ext.fly(pnode).createChild(this[name+'Cfg']);
9926 var el = document.createElement('div');
9927 el.className = this[name+'Cls'];
9928 this[name] = Ext.get(pnode.appendChild(el));
9930 if(this[name+'CssClass']){
9931 this[name].addClass(this[name+'CssClass']);
9933 if(this[name+'Style']){
9934 this[name].applyStyles(this[name+'Style']);
9940 onRender : function(ct, position){
9941 Ext.Panel.superclass.onRender.call(this, ct, position);
9942 this.createClasses();
9950 if(this.collapsible && !this.hideCollapseTool){
9951 this.tools = this.tools ? this.tools.slice(0) : [];
9952 this.tools[this.collapseFirst?'unshift':'push']({
9954 handler : this.toggleCollapse,
9961 this.elements += (this.header !== false) ? ',header' : '';
9965 el.addClass(this.baseCls);
9966 if(d.firstChild){ // existing markup
9967 this.header = el.down('.'+this.headerCls);
9968 this.bwrap = el.down('.'+this.bwrapCls);
9969 var cp = this.bwrap ? this.bwrap : el;
9970 this.tbar = cp.down('.'+this.tbarCls);
9971 this.body = cp.down('.'+this.bodyCls);
9972 this.bbar = cp.down('.'+this.bbarCls);
9973 this.footer = cp.down('.'+this.footerCls);
9974 this.fromMarkup = true;
9976 if (this.preventBodyReset === true) {
9977 el.addClass('x-panel-reset');
9980 el.addClass(this.cls);
9984 this.elements += ',footer';
9987 // This block allows for maximum flexibility and performance when using existing markup
9989 // framing requires special markup
9991 el.insertHtml('afterBegin', String.format(Ext.Element.boxMarkup, this.baseCls));
9993 this.createElement('header', d.firstChild.firstChild.firstChild);
9994 this.createElement('bwrap', d);
9996 // append the mid and bottom frame to the bwrap
9997 bw = this.bwrap.dom;
9998 var ml = d.childNodes[1], bl = d.childNodes[2];
10000 bw.appendChild(bl);
10002 var mc = bw.firstChild.firstChild.firstChild;
10003 this.createElement('tbar', mc);
10004 this.createElement('body', mc);
10005 this.createElement('bbar', mc);
10006 this.createElement('footer', bw.lastChild.firstChild.firstChild);
10009 this.bwrap.dom.lastChild.className += ' x-panel-nofooter';
10012 * Store a reference to this element so:
10013 * a) We aren't looking it up all the time
10014 * b) The last element is reported incorrectly when using a loadmask
10016 this.ft = Ext.get(this.bwrap.dom.lastChild);
10017 this.mc = Ext.get(mc);
10019 this.createElement('header', d);
10020 this.createElement('bwrap', d);
10022 // append the mid and bottom frame to the bwrap
10023 bw = this.bwrap.dom;
10024 this.createElement('tbar', bw);
10025 this.createElement('body', bw);
10026 this.createElement('bbar', bw);
10027 this.createElement('footer', bw);
10030 this.body.addClass(this.bodyCls + '-noheader');
10032 this.tbar.addClass(this.tbarCls + '-noheader');
10037 if(Ext.isDefined(this.padding)){
10038 this.body.setStyle('padding', this.body.addUnits(this.padding));
10041 if(this.border === false){
10042 this.el.addClass(this.baseCls + '-noborder');
10043 this.body.addClass(this.bodyCls + '-noborder');
10045 this.header.addClass(this.headerCls + '-noborder');
10048 this.footer.addClass(this.footerCls + '-noborder');
10051 this.tbar.addClass(this.tbarCls + '-noborder');
10054 this.bbar.addClass(this.bbarCls + '-noborder');
10058 if(this.bodyBorder === false){
10059 this.body.addClass(this.bodyCls + '-noborder');
10062 this.bwrap.enableDisplayMode('block');
10065 this.header.unselectable();
10067 // for tools, we need to wrap any existing header markup
10068 if(this.headerAsText){
10069 this.header.dom.innerHTML =
10070 '<span class="' + this.headerTextCls + '">'+this.header.dom.innerHTML+'</span>';
10073 this.setIconClass(this.iconCls);
10079 this.makeFloating(this.floating);
10082 if(this.collapsible && this.titleCollapse && this.header){
10083 this.mon(this.header, 'click', this.toggleCollapse, this);
10084 this.header.setStyle('cursor', 'pointer');
10087 this.addTool.apply(this, ts);
10090 // Render Toolbars.
10092 this.footer.addClass('x-panel-btns');
10093 this.fbar.ownerCt = this;
10094 this.fbar.render(this.footer);
10095 this.footer.createChild({cls:'x-clear'});
10097 if(this.tbar && this.topToolbar){
10098 this.topToolbar.ownerCt = this;
10099 this.topToolbar.render(this.tbar);
10101 if(this.bbar && this.bottomToolbar){
10102 this.bottomToolbar.ownerCt = this;
10103 this.bottomToolbar.render(this.bbar);
10108 * Sets the CSS class that provides the icon image for this panel. This method will replace any existing
10109 * icon class if one has already been set and fire the {@link #iconchange} event after completion.
10110 * @param {String} cls The new CSS class name
10112 setIconClass : function(cls){
10113 var old = this.iconCls;
10114 this.iconCls = cls;
10115 if(this.rendered && this.header){
10117 this.header.addClass('x-panel-icon');
10118 this.header.replaceClass(old, this.iconCls);
10120 var hd = this.header,
10121 img = hd.child('img.x-panel-inline-icon');
10123 Ext.fly(img).replaceClass(old, this.iconCls);
10125 var hdspan = hd.child('span.' + this.headerTextCls);
10127 Ext.DomHelper.insertBefore(hdspan.dom, {
10128 tag:'img', src: Ext.BLANK_IMAGE_URL, cls:'x-panel-inline-icon '+this.iconCls
10134 this.fireEvent('iconchange', this, cls, old);
10138 makeFloating : function(cfg){
10139 this.floating = true;
10140 this.el = new Ext.Layer(Ext.apply({}, cfg, {
10141 shadow: Ext.isDefined(this.shadow) ? this.shadow : 'sides',
10142 shadowOffset: this.shadowOffset,
10144 shim: this.shim === false ? false : undefined
10149 * Returns the {@link Ext.Toolbar toolbar} from the top (<code>{@link #tbar}</code>) section of the panel.
10150 * @return {Ext.Toolbar} The toolbar
10152 getTopToolbar : function(){
10153 return this.topToolbar;
10157 * Returns the {@link Ext.Toolbar toolbar} from the bottom (<code>{@link #bbar}</code>) section of the panel.
10158 * @return {Ext.Toolbar} The toolbar
10160 getBottomToolbar : function(){
10161 return this.bottomToolbar;
10165 * Returns the {@link Ext.Toolbar toolbar} from the footer (<code>{@link #fbar}</code>) section of the panel.
10166 * @return {Ext.Toolbar} The toolbar
10168 getFooterToolbar : function() {
10173 * Adds a button to this panel. Note that this method must be called prior to rendering. The preferred
10174 * approach is to add buttons via the {@link #buttons} config.
10175 * @param {String/Object} config A valid {@link Ext.Button} config. A string will become the text for a default
10176 * button config, an object will be treated as a button config object.
10177 * @param {Function} handler The function to be called on button {@link Ext.Button#click}
10178 * @param {Object} scope The scope (<code>this</code> reference) in which the button handler function is executed. Defaults to the Button.
10179 * @return {Ext.Button} The button that was added
10181 addButton : function(config, handler, scope){
10183 this.createFbar([]);
10186 if(Ext.isString(config)){
10187 config = {text: config};
10189 config = Ext.apply({
10194 return this.fbar.add(config);
10198 addTool : function(){
10199 if(!this.rendered){
10203 Ext.each(arguments, function(arg){
10204 this.tools.push(arg);
10208 // nowhere to render tools!
10209 if(!this[this.toolTarget]){
10212 if(!this.toolTemplate){
10213 // initialize the global tool template on first use
10214 var tt = new Ext.Template(
10215 '<div class="x-tool x-tool-{id}"> </div>'
10217 tt.disableFormats = true;
10219 Ext.Panel.prototype.toolTemplate = tt;
10221 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10223 if(!this.tools[tc.id]){
10224 var overCls = 'x-tool-'+tc.id+'-over';
10225 var t = this.toolTemplate.insertFirst(this[this.toolTarget], tc, true);
10226 this.tools[tc.id] = t;
10227 t.enableDisplayMode('block');
10228 this.mon(t, 'click', this.createToolHandler(t, tc, overCls, this));
10230 this.mon(t, tc.on);
10236 if(Ext.isObject(tc.qtip)){
10237 Ext.QuickTips.register(Ext.apply({
10241 t.dom.qtip = tc.qtip;
10244 t.addClassOnOver(overCls);
10249 onLayout : function(shallow, force){
10250 Ext.Panel.superclass.onLayout.apply(this, arguments);
10251 if(this.hasLayout && this.toolbars.length > 0){
10252 Ext.each(this.toolbars, function(tb){
10253 tb.doLayout(undefined, force);
10259 syncHeight : function(){
10260 var h = this.toolbarHeight,
10262 lsh = this.lastSize.height,
10265 if(this.autoHeight || !Ext.isDefined(lsh) || lsh == 'auto'){
10270 if(h != this.getToolbarHeight()){
10271 h = Math.max(0, lsh - this.getFrameHeight());
10274 this.toolbarHeight = this.getToolbarHeight();
10275 this.onBodyResize(sz.width, sz.height);
10280 onShow : function(){
10282 return this.el.show();
10284 Ext.Panel.superclass.onShow.call(this);
10288 onHide : function(){
10290 return this.el.hide();
10292 Ext.Panel.superclass.onHide.call(this);
10296 createToolHandler : function(t, tc, overCls, panel){
10297 return function(e){
10298 t.removeClass(overCls);
10299 if(tc.stopEvent !== false){
10303 tc.handler.call(tc.scope || t, e, t, panel, tc);
10309 afterRender : function(){
10310 if(this.floating && !this.hidden){
10314 this.setTitle(this.title);
10316 Ext.Panel.superclass.afterRender.call(this); // do sizing calcs last
10317 if (this.collapsed) {
10318 this.collapsed = false;
10319 this.collapse(false);
10325 getKeyMap : function(){
10327 this.keyMap = new Ext.KeyMap(this.el, this.keys);
10329 return this.keyMap;
10333 initEvents : function(){
10337 if(this.draggable){
10338 this.initDraggable();
10340 if(this.toolbars.length > 0){
10341 Ext.each(this.toolbars, function(tb){
10345 afterlayout: this.syncHeight,
10346 remove: this.syncHeight
10355 initDraggable : function(){
10357 * <p>If this Panel is configured {@link #draggable}, this property will contain
10358 * an instance of {@link Ext.dd.DragSource} which handles dragging the Panel.</p>
10359 * The developer must provide implementations of the abstract methods of {@link Ext.dd.DragSource}
10360 * in order to supply behaviour for each stage of the drag/drop process. See {@link #draggable}.
10361 * @type Ext.dd.DragSource.
10364 this.dd = new Ext.Panel.DD(this, Ext.isBoolean(this.draggable) ? null : this.draggable);
10368 beforeEffect : function(anim){
10370 this.el.beforeAction();
10372 if(anim !== false){
10373 this.el.addClass('x-panel-animated');
10378 afterEffect : function(anim){
10380 this.el.removeClass('x-panel-animated');
10383 // private - wraps up an animation param with internal callbacks
10384 createEffect : function(a, cb, scope){
10392 }else if(!a.callback){
10394 }else { // wrap it up
10395 o.callback = function(){
10397 Ext.callback(a.callback, a.scope);
10400 return Ext.applyIf(o, a);
10404 * Collapses the panel body so that it becomes hidden. Fires the {@link #beforecollapse} event which will
10405 * cancel the collapse action if it returns false.
10406 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
10407 * {@link #animCollapse} panel config)
10408 * @return {Ext.Panel} this
10410 collapse : function(animate){
10411 if(this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforecollapse', this, animate) === false){
10414 var doAnim = animate === true || (animate !== false && this.animCollapse);
10415 this.beforeEffect(doAnim);
10416 this.onCollapse(doAnim, animate);
10421 onCollapse : function(doAnim, animArg){
10423 this[this.collapseEl].slideOut(this.slideAnchor,
10424 Ext.apply(this.createEffect(animArg||true, this.afterCollapse, this),
10425 this.collapseDefaults));
10427 this[this.collapseEl].hide(this.hideMode);
10428 this.afterCollapse(false);
10433 afterCollapse : function(anim){
10434 this.collapsed = true;
10435 this.el.addClass(this.collapsedCls);
10436 if(anim !== false){
10437 this[this.collapseEl].hide(this.hideMode);
10439 this.afterEffect(anim);
10441 // Reset lastSize of all sub-components so they KNOW they are in a collapsed container
10442 this.cascade(function(c) {
10444 c.lastSize = { width: 0, height: 0 };
10447 this.fireEvent('collapse', this);
10451 * Expands the panel body so that it becomes visible. Fires the {@link #beforeexpand} event which will
10452 * cancel the expand action if it returns false.
10453 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
10454 * {@link #animCollapse} panel config)
10455 * @return {Ext.Panel} this
10457 expand : function(animate){
10458 if(!this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforeexpand', this, animate) === false){
10461 var doAnim = animate === true || (animate !== false && this.animCollapse);
10462 this.el.removeClass(this.collapsedCls);
10463 this.beforeEffect(doAnim);
10464 this.onExpand(doAnim, animate);
10469 onExpand : function(doAnim, animArg){
10471 this[this.collapseEl].slideIn(this.slideAnchor,
10472 Ext.apply(this.createEffect(animArg||true, this.afterExpand, this),
10473 this.expandDefaults));
10475 this[this.collapseEl].show(this.hideMode);
10476 this.afterExpand(false);
10481 afterExpand : function(anim){
10482 this.collapsed = false;
10483 if(anim !== false){
10484 this[this.collapseEl].show(this.hideMode);
10486 this.afterEffect(anim);
10487 if (this.deferLayout) {
10488 delete this.deferLayout;
10489 this.doLayout(true);
10491 this.fireEvent('expand', this);
10495 * Shortcut for performing an {@link #expand} or {@link #collapse} based on the current state of the panel.
10496 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
10497 * {@link #animCollapse} panel config)
10498 * @return {Ext.Panel} this
10500 toggleCollapse : function(animate){
10501 this[this.collapsed ? 'expand' : 'collapse'](animate);
10506 onDisable : function(){
10507 if(this.rendered && this.maskDisabled){
10510 Ext.Panel.superclass.onDisable.call(this);
10514 onEnable : function(){
10515 if(this.rendered && this.maskDisabled){
10518 Ext.Panel.superclass.onEnable.call(this);
10522 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
10526 if(Ext.isDefined(w) || Ext.isDefined(h)){
10527 if(!this.collapsed){
10528 // First, set the the Panel's body width.
10529 // If we have auto-widthed it, get the resulting full offset width so we can size the Toolbars to match
10530 // The Toolbars must not buffer this resize operation because we need to know their heights.
10532 if(Ext.isNumber(w)){
10533 this.body.setWidth(w = this.adjustBodyWidth(w - this.getFrameWidth()));
10534 } else if (w == 'auto') {
10535 w = this.body.setWidth('auto').dom.offsetWidth;
10537 w = this.body.dom.offsetWidth;
10541 this.tbar.setWidth(w);
10542 if(this.topToolbar){
10543 this.topToolbar.setSize(w);
10547 this.bbar.setWidth(w);
10548 if(this.bottomToolbar){
10549 this.bottomToolbar.setSize(w);
10550 // The bbar does not move on resize without this.
10552 this.bbar.setStyle('position', 'static');
10553 this.bbar.setStyle('position', '');
10558 this.footer.setWidth(w);
10560 this.fbar.setSize(Ext.isIE ? (w - this.footer.getFrameWidth('lr')) : 'auto');
10564 // At this point, the Toolbars must be layed out for getFrameHeight to find a result.
10565 if(Ext.isNumber(h)){
10566 h = Math.max(0, h - this.getFrameHeight());
10567 //h = Math.max(0, h - (this.getHeight() - this.body.getHeight()));
10568 this.body.setHeight(h);
10569 }else if(h == 'auto'){
10570 this.body.setHeight(h);
10573 if(this.disabled && this.el._mask){
10574 this.el._mask.setSize(this.el.dom.clientWidth, this.el.getHeight());
10577 // Adds an event to set the correct height afterExpand. This accounts for the deferHeight flag in panel
10578 this.queuedBodySize = {width: w, height: h};
10579 if(!this.queuedExpand && this.allowQueuedExpand !== false){
10580 this.queuedExpand = true;
10581 this.on('expand', function(){
10582 delete this.queuedExpand;
10583 this.onResize(this.queuedBodySize.width, this.queuedBodySize.height);
10584 }, this, {single:true});
10587 this.onBodyResize(w, h);
10590 Ext.Panel.superclass.onResize.call(this, adjWidth, adjHeight, rawWidth, rawHeight);
10595 onBodyResize: function(w, h){
10596 this.fireEvent('bodyresize', this, w, h);
10600 getToolbarHeight: function(){
10603 Ext.each(this.toolbars, function(tb){
10604 h += tb.getHeight();
10611 adjustBodyHeight : function(h){
10616 adjustBodyWidth : function(w){
10621 onPosition : function(){
10626 * Returns the width in pixels of the framing elements of this panel (not including the body width). To
10627 * retrieve the body width see {@link #getInnerWidth}.
10628 * @return {Number} The frame width
10630 getFrameWidth : function(){
10631 var w = this.el.getFrameWidth('lr') + this.bwrap.getFrameWidth('lr');
10634 var l = this.bwrap.dom.firstChild;
10635 w += (Ext.fly(l).getFrameWidth('l') + Ext.fly(l.firstChild).getFrameWidth('r'));
10636 w += this.mc.getFrameWidth('lr');
10642 * Returns the height in pixels of the framing elements of this panel (including any top and bottom bars and
10643 * header and footer elements, but not including the body height). To retrieve the body height see {@link #getInnerHeight}.
10644 * @return {Number} The frame height
10646 getFrameHeight : function() {
10647 var h = Math.max(0, this.getHeight() - this.body.getHeight());
10655 var h = this.el.getFrameWidth('tb') + this.bwrap.getFrameWidth('tb');
10656 h += (this.tbar ? this.tbar.getHeight() : 0) +
10657 (this.bbar ? this.bbar.getHeight() : 0);
10660 h += this.el.dom.firstChild.offsetHeight + this.ft.dom.offsetHeight + this.mc.getFrameWidth('tb');
10662 h += (this.header ? this.header.getHeight() : 0) +
10663 (this.footer ? this.footer.getHeight() : 0);
10670 * Returns the width in pixels of the body element (not including the width of any framing elements).
10671 * For the frame width see {@link #getFrameWidth}.
10672 * @return {Number} The body width
10674 getInnerWidth : function(){
10675 return this.getSize().width - this.getFrameWidth();
10679 * Returns the height in pixels of the body element (not including the height of any framing elements).
10680 * For the frame height see {@link #getFrameHeight}.
10681 * @return {Number} The body height
10683 getInnerHeight : function(){
10684 return this.body.getHeight();
10686 return this.getSize().height - this.getFrameHeight();
10691 syncShadow : function(){
10693 this.el.sync(true);
10698 getLayoutTarget : function(){
10703 getContentTarget : function(){
10708 * <p>Sets the title text for the panel and optionally the {@link #iconCls icon class}.</p>
10709 * <p>In order to be able to set the title, a header element must have been created
10710 * for the Panel. This is triggered either by configuring the Panel with a non-blank <code>{@link #title}</code>,
10711 * or configuring it with <code><b>{@link #header}: true</b></code>.</p>
10712 * @param {String} title The title text to set
10713 * @param {String} iconCls (optional) {@link #iconCls iconCls} A user-defined CSS class that provides the icon image for this panel
10715 setTitle : function(title, iconCls){
10716 this.title = title;
10717 if(this.header && this.headerAsText){
10718 this.header.child('span').update(title);
10721 this.setIconClass(iconCls);
10723 this.fireEvent('titlechange', this, title);
10728 * Get the {@link Ext.Updater} for this panel. Enables you to perform Ajax updates of this panel's body.
10729 * @return {Ext.Updater} The Updater
10731 getUpdater : function(){
10732 return this.body.getUpdater();
10736 * Loads this content panel immediately with content returned from an XHR call.
10737 * @param {Object/String/Function} config A config object containing any of the following options:
10740 url: 'your-url.php',
10741 params: {param1: 'foo', param2: 'bar'}, // or a URL encoded string
10742 callback: yourFunction,
10743 scope: yourObject, // optional scope for the callback
10746 text: 'Loading...',
10751 * The only required property is url. The optional properties nocache, text and scripts
10752 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their
10753 * associated property on this panel Updater instance.
10754 * @return {Ext.Panel} this
10757 var um = this.body.getUpdater();
10758 um.update.apply(um, arguments);
10763 beforeDestroy : function(){
10764 Ext.Panel.superclass.beforeDestroy.call(this);
10766 this.header.removeAllListeners();
10769 for(var k in this.tools){
10770 Ext.destroy(this.tools[k]);
10773 if(this.toolbars.length > 0){
10774 Ext.each(this.toolbars, function(tb){
10775 tb.un('afterlayout', this.syncHeight, this);
10776 tb.un('remove', this.syncHeight, this);
10779 if(Ext.isArray(this.buttons)){
10780 while(this.buttons.length) {
10781 Ext.destroy(this.buttons[0]);
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;
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)
11406 select : function(color){
11407 color = color.replace('#', '');
11408 if(color != this.value || this.allowReselect){
11411 el.child('a.color-'+this.value).removeClass('x-color-palette-sel');
11413 el.child('a.color-'+color).addClass('x-color-palette-sel');
11414 this.value = color;
11415 this.fireEvent('select', this, color);
11420 * @cfg {String} autoEl @hide
11423 Ext.reg('colorpalette', Ext.ColorPalette);
11425 * @class Ext.DatePicker
11426 * @extends Ext.Component
11427 * <p>A popup date picker. This class is used by the {@link Ext.form.DateField DateField} class
11428 * to allow browsing and selection of valid dates.</p>
11429 * <p>All the string values documented below may be overridden by including an Ext locale file in
11432 * Create a new DatePicker
11433 * @param {Object} config The config object
11434 * @xtype datepicker
11436 Ext.DatePicker = Ext.extend(Ext.BoxComponent, {
11438 * @cfg {String} todayText
11439 * The text to display on the button that selects the current date (defaults to <code>'Today'</code>)
11441 todayText : 'Today',
11443 * @cfg {String} okText
11444 * The text to display on the ok button (defaults to <code>' OK '</code> to give the user extra clicking room)
11446 okText : ' OK ',
11448 * @cfg {String} cancelText
11449 * The text to display on the cancel button (defaults to <code>'Cancel'</code>)
11451 cancelText : 'Cancel',
11453 * @cfg {Function} handler
11454 * Optional. A function that will handle the select event of this picker.
11455 * The handler is passed the following parameters:<div class="mdetail-params"><ul>
11456 * <li><code>picker</code> : DatePicker<div class="sub-desc">This DatePicker.</div></li>
11457 * <li><code>date</code> : Date<div class="sub-desc">The selected date.</div></li>
11461 * @cfg {Object} scope
11462 * The scope (<code><b>this</b></code> reference) in which the <code>{@link #handler}</code>
11463 * function will be called. Defaults to this DatePicker instance.
11466 * @cfg {String} todayTip
11467 * A string used to format the message for displaying in a tooltip over the button that
11468 * selects the current date. Defaults to <code>'{0} (Spacebar)'</code> where
11469 * the <code>{0}</code> token is replaced by today's date.
11471 todayTip : '{0} (Spacebar)',
11473 * @cfg {String} minText
11474 * The error text to display if the minDate validation fails (defaults to <code>'This date is before the minimum date'</code>)
11476 minText : 'This date is before the minimum date',
11478 * @cfg {String} maxText
11479 * The error text to display if the maxDate validation fails (defaults to <code>'This date is after the maximum date'</code>)
11481 maxText : 'This date is after the maximum date',
11483 * @cfg {String} format
11484 * The default date format string which can be overriden for localization support. The format must be
11485 * valid according to {@link Date#parseDate} (defaults to <code>'m/d/y'</code>).
11489 * @cfg {String} disabledDaysText
11490 * The tooltip to display when the date falls on a disabled day (defaults to <code>'Disabled'</code>)
11492 disabledDaysText : 'Disabled',
11494 * @cfg {String} disabledDatesText
11495 * The tooltip text to display when the date falls on a disabled date (defaults to <code>'Disabled'</code>)
11497 disabledDatesText : 'Disabled',
11499 * @cfg {Array} monthNames
11500 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
11502 monthNames : Date.monthNames,
11504 * @cfg {Array} dayNames
11505 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
11507 dayNames : Date.dayNames,
11509 * @cfg {String} nextText
11510 * The next month navigation button tooltip (defaults to <code>'Next Month (Control+Right)'</code>)
11512 nextText : 'Next Month (Control+Right)',
11514 * @cfg {String} prevText
11515 * The previous month navigation button tooltip (defaults to <code>'Previous Month (Control+Left)'</code>)
11517 prevText : 'Previous Month (Control+Left)',
11519 * @cfg {String} monthYearText
11520 * The header month selector tooltip (defaults to <code>'Choose a month (Control+Up/Down to move years)'</code>)
11522 monthYearText : 'Choose a month (Control+Up/Down to move years)',
11524 * @cfg {Number} startDay
11525 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
11529 * @cfg {Boolean} showToday
11530 * False to hide the footer area containing the Today button and disable the keyboard handler for spacebar
11531 * that selects the current date (defaults to <code>true</code>).
11535 * @cfg {Date} minDate
11536 * Minimum allowable date (JavaScript date object, defaults to null)
11539 * @cfg {Date} maxDate
11540 * Maximum allowable date (JavaScript date object, defaults to null)
11543 * @cfg {Array} disabledDays
11544 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
11547 * @cfg {RegExp} disabledDatesRE
11548 * JavaScript regular expression used to disable a pattern of dates (defaults to null). The {@link #disabledDates}
11549 * config will generate this regex internally, but if you specify disabledDatesRE it will take precedence over the
11550 * disabledDates value.
11553 * @cfg {Array} disabledDates
11554 * An array of 'dates' to disable, as strings. These strings will be used to build a dynamic regular
11555 * expression so they are very powerful. Some examples:
11557 * <li>['03/08/2003', '09/16/2003'] would disable those exact dates</li>
11558 * <li>['03/08', '09/16'] would disable those days for every year</li>
11559 * <li>['^03/08'] would only match the beginning (useful if you are using short years)</li>
11560 * <li>['03/../2006'] would disable every day in March 2006</li>
11561 * <li>['^03'] would disable every day in every March</li>
11563 * Note that the format of the dates included in the array should exactly match the {@link #format} config.
11564 * In order to support regular expressions, if you are using a date format that has '.' in it, you will have to
11565 * escape the dot when restricting dates. For example: ['03\\.08\\.03'].
11569 // Set by other components to stop the picker focus being updated when the value changes.
11570 focusOnSelect: true,
11572 // default value used to initialise each date in the DatePicker
11573 // (note: 12 noon was chosen because it steers well clear of all DST timezone changes)
11574 initHour: 12, // 24-hour format
11577 initComponent : function(){
11578 Ext.DatePicker.superclass.initComponent.call(this);
11580 this.value = this.value ?
11581 this.value.clearTime(true) : new Date().clearTime();
11586 * Fires when a date is selected
11587 * @param {DatePicker} this DatePicker
11588 * @param {Date} date The selected date
11594 this.on('select', this.handler, this.scope || this);
11597 this.initDisabledDays();
11601 initDisabledDays : function(){
11602 if(!this.disabledDatesRE && this.disabledDates){
11603 var dd = this.disabledDates,
11604 len = dd.length - 1,
11607 Ext.each(dd, function(d, i){
11608 re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i];
11613 this.disabledDatesRE = new RegExp(re + ')');
11618 * Replaces any existing disabled dates with new values and refreshes the DatePicker.
11619 * @param {Array/RegExp} disabledDates An array of date strings (see the {@link #disabledDates} config
11620 * for details on supported values), or a JavaScript regular expression used to disable a pattern of dates.
11622 setDisabledDates : function(dd){
11623 if(Ext.isArray(dd)){
11624 this.disabledDates = dd;
11625 this.disabledDatesRE = null;
11627 this.disabledDatesRE = dd;
11629 this.initDisabledDays();
11630 this.update(this.value, true);
11634 * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.
11635 * @param {Array} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config
11636 * for details on supported values.
11638 setDisabledDays : function(dd){
11639 this.disabledDays = dd;
11640 this.update(this.value, true);
11644 * Replaces any existing {@link #minDate} with the new value and refreshes the DatePicker.
11645 * @param {Date} value The minimum date that can be selected
11647 setMinDate : function(dt){
11649 this.update(this.value, true);
11653 * Replaces any existing {@link #maxDate} with the new value and refreshes the DatePicker.
11654 * @param {Date} value The maximum date that can be selected
11656 setMaxDate : function(dt){
11658 this.update(this.value, true);
11662 * Sets the value of the date field
11663 * @param {Date} value The date to set
11665 setValue : function(value){
11666 this.value = value.clearTime(true);
11667 this.update(this.value);
11671 * Gets the current selected value of the date field
11672 * @return {Date} The selected date
11674 getValue : function(){
11679 focus : function(){
11680 this.update(this.activeDate);
11684 onEnable: function(initial){
11685 Ext.DatePicker.superclass.onEnable.call(this);
11686 this.doDisabled(false);
11687 this.update(initial ? this.value : this.activeDate);
11695 onDisable : function(){
11696 Ext.DatePicker.superclass.onDisable.call(this);
11697 this.doDisabled(true);
11698 if(Ext.isIE && !Ext.isIE8){
11699 /* Really strange problem in IE6/7, when disabled, have to explicitly
11700 * repaint each of the nodes to get them to display correctly, simply
11701 * calling repaint on the main element doesn't appear to be enough.
11703 Ext.each([].concat(this.textNodes, this.el.query('th span')), function(el){
11704 Ext.fly(el).repaint();
11710 doDisabled : function(disabled){
11711 this.keyNav.setDisabled(disabled);
11712 this.prevRepeater.setDisabled(disabled);
11713 this.nextRepeater.setDisabled(disabled);
11714 if(this.showToday){
11715 this.todayKeyListener.setDisabled(disabled);
11716 this.todayBtn.setDisabled(disabled);
11721 onRender : function(container, position){
11723 '<table cellspacing="0">',
11724 '<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>',
11725 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'],
11726 dn = this.dayNames,
11728 for(i = 0; i < 7; i++){
11729 var d = this.startDay+i;
11733 m.push('<th><span>', dn[d].substr(0,1), '</span></th>');
11735 m[m.length] = '</tr></thead><tbody><tr>';
11736 for(i = 0; i < 42; i++) {
11737 if(i % 7 === 0 && i !== 0){
11738 m[m.length] = '</tr><tr>';
11740 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
11742 m.push('</tr></tbody></table></td></tr>',
11743 this.showToday ? '<tr><td colspan="3" class="x-date-bottom" align="center"></td></tr>' : '',
11744 '</table><div class="x-date-mp"></div>');
11746 var el = document.createElement('div');
11747 el.className = 'x-date-picker';
11748 el.innerHTML = m.join('');
11750 container.dom.insertBefore(el, position);
11752 this.el = Ext.get(el);
11753 this.eventEl = Ext.get(el.firstChild);
11755 this.prevRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-left a'), {
11756 handler: this.showPrevMonth,
11758 preventDefault:true,
11762 this.nextRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-right a'), {
11763 handler: this.showNextMonth,
11765 preventDefault:true,
11769 this.monthPicker = this.el.down('div.x-date-mp');
11770 this.monthPicker.enableDisplayMode('block');
11772 this.keyNav = new Ext.KeyNav(this.eventEl, {
11773 'left' : function(e){
11775 this.showPrevMonth();
11777 this.update(this.activeDate.add('d', -1));
11781 'right' : function(e){
11783 this.showNextMonth();
11785 this.update(this.activeDate.add('d', 1));
11789 'up' : function(e){
11791 this.showNextYear();
11793 this.update(this.activeDate.add('d', -7));
11797 'down' : function(e){
11799 this.showPrevYear();
11801 this.update(this.activeDate.add('d', 7));
11805 'pageUp' : function(e){
11806 this.showNextMonth();
11809 'pageDown' : function(e){
11810 this.showPrevMonth();
11813 'enter' : function(e){
11814 e.stopPropagation();
11821 this.el.unselectable();
11823 this.cells = this.el.select('table.x-date-inner tbody td');
11824 this.textNodes = this.el.query('table.x-date-inner tbody span');
11826 this.mbtn = new Ext.Button({
11828 tooltip: this.monthYearText,
11829 renderTo: this.el.child('td.x-date-middle', true)
11831 this.mbtn.el.child('em').addClass('x-btn-arrow');
11833 if(this.showToday){
11834 this.todayKeyListener = this.eventEl.addKeyListener(Ext.EventObject.SPACE, this.selectToday, this);
11835 var today = (new Date()).dateFormat(this.format);
11836 this.todayBtn = new Ext.Button({
11837 renderTo: this.el.child('td.x-date-bottom', true),
11838 text: String.format(this.todayText, today),
11839 tooltip: String.format(this.todayTip, today),
11840 handler: this.selectToday,
11844 this.mon(this.eventEl, 'mousewheel', this.handleMouseWheel, this);
11845 this.mon(this.eventEl, 'click', this.handleDateClick, this, {delegate: 'a.x-date-date'});
11846 this.mon(this.mbtn, 'click', this.showMonthPicker, this);
11847 this.onEnable(true);
11851 createMonthPicker : function(){
11852 if(!this.monthPicker.dom.firstChild){
11853 var buf = ['<table border="0" cellspacing="0">'];
11854 for(var i = 0; i < 6; i++){
11856 '<tr><td class="x-date-mp-month"><a href="#">', Date.getShortMonthName(i), '</a></td>',
11857 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', Date.getShortMonthName(i + 6), '</a></td>',
11859 '<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>' :
11860 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
11864 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
11866 '</button><button type="button" class="x-date-mp-cancel">',
11868 '</button></td></tr>',
11871 this.monthPicker.update(buf.join(''));
11873 this.mon(this.monthPicker, 'click', this.onMonthClick, this);
11874 this.mon(this.monthPicker, 'dblclick', this.onMonthDblClick, this);
11876 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
11877 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
11879 this.mpMonths.each(function(m, a, i){
11882 m.dom.xmonth = 5 + Math.round(i * 0.5);
11884 m.dom.xmonth = Math.round((i-1) * 0.5);
11891 showMonthPicker : function(){
11892 if(!this.disabled){
11893 this.createMonthPicker();
11894 var size = this.el.getSize();
11895 this.monthPicker.setSize(size);
11896 this.monthPicker.child('table').setSize(size);
11898 this.mpSelMonth = (this.activeDate || this.value).getMonth();
11899 this.updateMPMonth(this.mpSelMonth);
11900 this.mpSelYear = (this.activeDate || this.value).getFullYear();
11901 this.updateMPYear(this.mpSelYear);
11903 this.monthPicker.slideIn('t', {duration:0.2});
11908 updateMPYear : function(y){
11910 var ys = this.mpYears.elements;
11911 for(var i = 1; i <= 10; i++){
11912 var td = ys[i-1], y2;
11914 y2 = y + Math.round(i * 0.5);
11915 td.firstChild.innerHTML = y2;
11918 y2 = y - (5-Math.round(i * 0.5));
11919 td.firstChild.innerHTML = y2;
11922 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
11927 updateMPMonth : function(sm){
11928 this.mpMonths.each(function(m, a, i){
11929 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
11934 selectMPMonth : function(m){
11939 onMonthClick : function(e, t){
11941 var el = new Ext.Element(t), pn;
11942 if(el.is('button.x-date-mp-cancel')){
11943 this.hideMonthPicker();
11945 else if(el.is('button.x-date-mp-ok')){
11946 var d = new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate());
11947 if(d.getMonth() != this.mpSelMonth){
11948 // 'fix' the JS rolling date conversion if needed
11949 d = new Date(this.mpSelYear, this.mpSelMonth, 1).getLastDateOfMonth();
11952 this.hideMonthPicker();
11954 else if((pn = el.up('td.x-date-mp-month', 2))){
11955 this.mpMonths.removeClass('x-date-mp-sel');
11956 pn.addClass('x-date-mp-sel');
11957 this.mpSelMonth = pn.dom.xmonth;
11959 else if((pn = el.up('td.x-date-mp-year', 2))){
11960 this.mpYears.removeClass('x-date-mp-sel');
11961 pn.addClass('x-date-mp-sel');
11962 this.mpSelYear = pn.dom.xyear;
11964 else if(el.is('a.x-date-mp-prev')){
11965 this.updateMPYear(this.mpyear-10);
11967 else if(el.is('a.x-date-mp-next')){
11968 this.updateMPYear(this.mpyear+10);
11973 onMonthDblClick : function(e, t){
11975 var el = new Ext.Element(t), pn;
11976 if((pn = el.up('td.x-date-mp-month', 2))){
11977 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
11978 this.hideMonthPicker();
11980 else if((pn = el.up('td.x-date-mp-year', 2))){
11981 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
11982 this.hideMonthPicker();
11987 hideMonthPicker : function(disableAnim){
11988 if(this.monthPicker){
11989 if(disableAnim === true){
11990 this.monthPicker.hide();
11992 this.monthPicker.slideOut('t', {duration:0.2});
11998 showPrevMonth : function(e){
11999 this.update(this.activeDate.add('mo', -1));
12003 showNextMonth : function(e){
12004 this.update(this.activeDate.add('mo', 1));
12008 showPrevYear : function(){
12009 this.update(this.activeDate.add('y', -1));
12013 showNextYear : function(){
12014 this.update(this.activeDate.add('y', 1));
12018 handleMouseWheel : function(e){
12020 if(!this.disabled){
12021 var delta = e.getWheelDelta();
12023 this.showPrevMonth();
12024 } else if(delta < 0){
12025 this.showNextMonth();
12031 handleDateClick : function(e, t){
12033 if(!this.disabled && t.dateValue && !Ext.fly(t.parentNode).hasClass('x-date-disabled')){
12034 this.cancelFocus = this.focusOnSelect === false;
12035 this.setValue(new Date(t.dateValue));
12036 delete this.cancelFocus;
12037 this.fireEvent('select', this, this.value);
12042 selectToday : function(){
12043 if(this.todayBtn && !this.todayBtn.disabled){
12044 this.setValue(new Date().clearTime());
12045 this.fireEvent('select', this, this.value);
12050 update : function(date, forceRefresh){
12052 var vd = this.activeDate, vis = this.isVisible();
12053 this.activeDate = date;
12054 if(!forceRefresh && vd && this.el){
12055 var t = date.getTime();
12056 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12057 this.cells.removeClass('x-date-selected');
12058 this.cells.each(function(c){
12059 if(c.dom.firstChild.dateValue == t){
12060 c.addClass('x-date-selected');
12061 if(vis && !this.cancelFocus){
12062 Ext.fly(c.dom.firstChild).focus(50);
12070 var days = date.getDaysInMonth(),
12071 firstOfMonth = date.getFirstDateOfMonth(),
12072 startingPos = firstOfMonth.getDay()-this.startDay;
12074 if(startingPos < 0){
12077 days += startingPos;
12079 var pm = date.add('mo', -1),
12080 prevStart = pm.getDaysInMonth()-startingPos,
12081 cells = this.cells.elements,
12082 textEls = this.textNodes,
12083 // convert everything to numbers so it's fast
12084 d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart, this.initHour)),
12085 today = new Date().clearTime().getTime(),
12086 sel = date.clearTime(true).getTime(),
12087 min = this.minDate ? this.minDate.clearTime(true) : Number.NEGATIVE_INFINITY,
12088 max = this.maxDate ? this.maxDate.clearTime(true) : Number.POSITIVE_INFINITY,
12089 ddMatch = this.disabledDatesRE,
12090 ddText = this.disabledDatesText,
12091 ddays = this.disabledDays ? this.disabledDays.join('') : false,
12092 ddaysText = this.disabledDaysText,
12093 format = this.format;
12095 if(this.showToday){
12096 var td = new Date().clearTime(),
12097 disable = (td < min || td > max ||
12098 (ddMatch && format && ddMatch.test(td.dateFormat(format))) ||
12099 (ddays && ddays.indexOf(td.getDay()) != -1));
12101 if(!this.disabled){
12102 this.todayBtn.setDisabled(disable);
12103 this.todayKeyListener[disable ? 'disable' : 'enable']();
12107 var setCellClass = function(cal, cell){
12109 var t = d.clearTime(true).getTime();
12110 cell.firstChild.dateValue = t;
12112 cell.className += ' x-date-today';
12113 cell.title = cal.todayText;
12116 cell.className += ' x-date-selected';
12118 Ext.fly(cell.firstChild).focus(50);
12123 cell.className = ' x-date-disabled';
12124 cell.title = cal.minText;
12128 cell.className = ' x-date-disabled';
12129 cell.title = cal.maxText;
12133 if(ddays.indexOf(d.getDay()) != -1){
12134 cell.title = ddaysText;
12135 cell.className = ' x-date-disabled';
12138 if(ddMatch && format){
12139 var fvalue = d.dateFormat(format);
12140 if(ddMatch.test(fvalue)){
12141 cell.title = ddText.replace('%0', fvalue);
12142 cell.className = ' x-date-disabled';
12148 for(; i < startingPos; i++) {
12149 textEls[i].innerHTML = (++prevStart);
12150 d.setDate(d.getDate()+1);
12151 cells[i].className = 'x-date-prevday';
12152 setCellClass(this, cells[i]);
12154 for(; i < days; i++){
12155 var intDay = i - startingPos + 1;
12156 textEls[i].innerHTML = (intDay);
12157 d.setDate(d.getDate()+1);
12158 cells[i].className = 'x-date-active';
12159 setCellClass(this, cells[i]);
12162 for(; i < 42; i++) {
12163 textEls[i].innerHTML = (++extraDays);
12164 d.setDate(d.getDate()+1);
12165 cells[i].className = 'x-date-nextday';
12166 setCellClass(this, cells[i]);
12169 this.mbtn.setText(this.monthNames[date.getMonth()] + ' ' + date.getFullYear());
12171 if(!this.internalRender){
12172 var main = this.el.dom.firstChild,
12173 w = main.offsetWidth;
12174 this.el.setWidth(w + this.el.getBorderWidth('lr'));
12175 Ext.fly(main).setWidth(w);
12176 this.internalRender = true;
12177 // opera does not respect the auto grow header center column
12178 // then, after it gets a width opera refuses to recalculate
12179 // without a second pass
12180 if(Ext.isOpera && !this.secondPass){
12181 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + 'px';
12182 this.secondPass = true;
12183 this.update.defer(10, this, [date]);
12190 beforeDestroy : function() {
12202 delete this.textNodes;
12203 delete this.cells.elements;
12208 * @cfg {String} autoEl @hide
12212 Ext.reg('datepicker', Ext.DatePicker);
12214 * @class Ext.LoadMask
12215 * A simple utility class for generically masking elements while loading data. If the {@link #store}
12216 * config option is specified, the masking will be automatically synchronized with the store's loading
12217 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
12218 * element's Updater load indicator and will be destroyed after the initial load.
12219 * <p>Example usage:</p>
12222 var myMask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait..."});
12226 * Create a new LoadMask
12227 * @param {Mixed} el The element or DOM node, or its id
12228 * @param {Object} config The config object
12230 Ext.LoadMask = function(el, config){
12231 this.el = Ext.get(el);
12232 Ext.apply(this, config);
12236 beforeload: this.onBeforeLoad,
12238 exception: this.onLoad
12240 this.removeMask = Ext.value(this.removeMask, false);
12242 var um = this.el.getUpdater();
12243 um.showLoadIndicator = false; // disable the default indicator
12246 beforeupdate: this.onBeforeLoad,
12247 update: this.onLoad,
12248 failure: this.onLoad
12250 this.removeMask = Ext.value(this.removeMask, true);
12254 Ext.LoadMask.prototype = {
12256 * @cfg {Ext.data.Store} store
12257 * Optional Store to which the mask is bound. The mask is displayed when a load request is issued, and
12258 * hidden on either load sucess, or load fail.
12261 * @cfg {Boolean} removeMask
12262 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
12263 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
12266 * @cfg {String} msg
12267 * The text to display in a centered loading message box (defaults to 'Loading...')
12269 msg : 'Loading...',
12271 * @cfg {String} msgCls
12272 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
12274 msgCls : 'x-mask-loading',
12277 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
12283 * Disables the mask to prevent it from being displayed
12285 disable : function(){
12286 this.disabled = true;
12290 * Enables the mask so that it can be displayed
12292 enable : function(){
12293 this.disabled = false;
12297 onLoad : function(){
12298 this.el.unmask(this.removeMask);
12302 onBeforeLoad : function(){
12303 if(!this.disabled){
12304 this.el.mask(this.msg, this.msgCls);
12309 * Show this LoadMask over the configured Element.
12312 this.onBeforeLoad();
12316 * Hide this LoadMask.
12323 destroy : function(){
12325 this.store.un('beforeload', this.onBeforeLoad, this);
12326 this.store.un('load', this.onLoad, this);
12327 this.store.un('exception', this.onLoad, this);
12329 var um = this.el.getUpdater();
12330 um.un('beforeupdate', this.onBeforeLoad, this);
12331 um.un('update', this.onLoad, this);
12332 um.un('failure', this.onLoad, this);
12335 };Ext.ns('Ext.slider');
12338 * @class Ext.slider.Thumb
12340 * Represents a single thumb element on a Slider. This would not usually be created manually and would instead
12341 * be created internally by an {@link Ext.slider.MultiSlider Ext.Slider}.
12343 Ext.slider.Thumb = Ext.extend(Object, {
12347 * @cfg {Ext.slider.MultiSlider} slider The Slider to render to (required)
12349 constructor: function(config) {
12352 * @type Ext.slider.MultiSlider
12353 * The slider this thumb is contained within
12355 Ext.apply(this, config || {}, {
12356 cls: 'x-slider-thumb',
12359 * @cfg {Boolean} constrain True to constrain the thumb so that it cannot overlap its siblings
12364 Ext.slider.Thumb.superclass.constructor.call(this, config);
12366 if (this.slider.vertical) {
12367 Ext.apply(this, Ext.slider.Thumb.Vertical);
12372 * Renders the thumb into a slider
12374 render: function() {
12375 this.el = this.slider.innerEl.insertFirst({cls: this.cls});
12381 * Enables the thumb if it is currently disabled
12383 enable: function() {
12384 this.disabled = false;
12385 this.el.removeClass(this.slider.disabledClass);
12389 * Disables the thumb if it is currently enabled
12391 disable: function() {
12392 this.disabled = true;
12393 this.el.addClass(this.slider.disabledClass);
12397 * Sets up an Ext.dd.DragTracker for this thumb
12399 initEvents: function() {
12402 el.addClassOnOver('x-slider-thumb-over');
12404 this.tracker = new Ext.dd.DragTracker({
12405 onBeforeStart: this.onBeforeDragStart.createDelegate(this),
12406 onStart : this.onDragStart.createDelegate(this),
12407 onDrag : this.onDrag.createDelegate(this),
12408 onEnd : this.onDragEnd.createDelegate(this),
12413 this.tracker.initEl(el);
12418 * This is tied into the internal Ext.dd.DragTracker. If the slider is currently disabled,
12419 * this returns false to disable the DragTracker too.
12420 * @return {Boolean} False if the slider is currently disabled
12422 onBeforeDragStart : function(e) {
12423 if (this.disabled) {
12426 this.slider.promoteThumb(this);
12433 * This is tied into the internal Ext.dd.DragTracker's onStart template method. Adds the drag CSS class
12434 * to the thumb and fires the 'dragstart' event
12436 onDragStart: function(e){
12437 this.el.addClass('x-slider-thumb-drag');
12438 this.dragging = true;
12439 this.dragStartValue = this.value;
12441 this.slider.fireEvent('dragstart', this.slider, e, this);
12446 * This is tied into the internal Ext.dd.DragTracker's onDrag template method. This is called every time
12447 * the DragTracker detects a drag movement. It updates the Slider's value using the position of the drag
12449 onDrag: function(e) {
12450 var slider = this.slider,
12451 index = this.index,
12452 newValue = this.getNewValue();
12454 if (this.constrain) {
12455 var above = slider.thumbs[index + 1],
12456 below = slider.thumbs[index - 1];
12458 if (below != undefined && newValue <= below.value) newValue = below.value;
12459 if (above != undefined && newValue >= above.value) newValue = above.value;
12462 slider.setValue(index, newValue, false);
12463 slider.fireEvent('drag', slider, e, this);
12466 getNewValue: function() {
12467 var slider = this.slider,
12468 pos = slider.innerEl.translatePoints(this.tracker.getXY());
12470 return Ext.util.Format.round(slider.reverseValue(pos.left), slider.decimalPrecision);
12475 * This is tied to the internal Ext.dd.DragTracker's onEnd template method. Removes the drag CSS class and
12476 * fires the 'changecomplete' event with the new value
12478 onDragEnd: function(e) {
12479 var slider = this.slider,
12480 value = this.value;
12482 this.el.removeClass('x-slider-thumb-drag');
12484 this.dragging = false;
12485 slider.fireEvent('dragend', slider, e);
12487 if (this.dragStartValue != value) {
12488 slider.fireEvent('changecomplete', slider, value, this);
12494 * @class Ext.slider.MultiSlider
12495 * @extends Ext.BoxComponent
12496 * 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:
12499 renderTo: Ext.getBody(),
12507 * Sliders can be created with more than one thumb handle by passing an array of values instead of a single one:
12510 renderTo: Ext.getBody(),
12512 values: [25, 50, 75],
12516 //this defaults to true, setting to false allows the thumbs to pass each other
12517 {@link #constrainThumbs}: false
12521 Ext.slider.MultiSlider = Ext.extend(Ext.BoxComponent, {
12523 * @cfg {Number} value The value to initialize the slider with. Defaults to minValue.
12526 * @cfg {Boolean} vertical Orient the Slider vertically rather than horizontally, defaults to false.
12530 * @cfg {Number} minValue The minimum value for the Slider. Defaults to 0.
12534 * @cfg {Number} maxValue The maximum value for the Slider. Defaults to 100.
12538 * @cfg {Number/Boolean} decimalPrecision.
12539 * <p>The number of decimal places to which to round the Slider's value. Defaults to 0.</p>
12540 * <p>To disable rounding, configure as <tt><b>false</b></tt>.</p>
12542 decimalPrecision: 0,
12544 * @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.
12548 * @cfg {Number} increment How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'.
12554 * @property clickRange
12556 * 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],
12557 * 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'
12558 * 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
12560 clickRange: [5,15],
12563 * @cfg {Boolean} clickToChange Determines whether or not clicking on the Slider axis will change the slider. Defaults to true
12565 clickToChange : true,
12567 * @cfg {Boolean} animate Turn on or off animation. Defaults to true
12572 * True while the thumb is in a drag operation
12578 * @cfg {Boolean} constrainThumbs True to disallow thumbs from overlapping one another. Defaults to true
12580 constrainThumbs: true,
12584 * @property topThumbZIndex
12586 * The number used internally to set the z index of the top thumb (see promoteThumb for details)
12588 topThumbZIndex: 10000,
12590 // private override
12591 initComponent : function(){
12592 if(!Ext.isDefined(this.value)){
12593 this.value = this.minValue;
12599 * Array containing references to each thumb
12603 Ext.slider.MultiSlider.superclass.initComponent.call(this);
12605 this.keyIncrement = Math.max(this.increment, this.keyIncrement);
12608 * @event beforechange
12609 * Fires before the slider value is changed. By returning false from an event handler,
12610 * you can cancel the event and prevent the slider from changing.
12611 * @param {Ext.Slider} slider The slider
12612 * @param {Number} newValue The new value which the slider is being changed to.
12613 * @param {Number} oldValue The old value which the slider was previously.
12619 * Fires when the slider value is changed.
12620 * @param {Ext.Slider} slider The slider
12621 * @param {Number} newValue The new value which the slider has been changed to.
12622 * @param {Ext.slider.Thumb} thumb The thumb that was changed
12627 * @event changecomplete
12628 * Fires when the slider value is changed by the user and any drag operations have completed.
12629 * @param {Ext.Slider} slider The slider
12630 * @param {Number} newValue The new value which the slider has been changed to.
12631 * @param {Ext.slider.Thumb} thumb The thumb that was changed
12637 * Fires after a drag operation has started.
12638 * @param {Ext.Slider} slider The slider
12639 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
12645 * Fires continuously during the drag operation while the mouse is moving.
12646 * @param {Ext.Slider} slider The slider
12647 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
12653 * Fires after the drag operation has completed.
12654 * @param {Ext.Slider} slider The slider
12655 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
12663 * Array of values to initalize the thumbs with
12665 if (this.values == undefined || Ext.isEmpty(this.values)) this.values = [0];
12667 var values = this.values;
12669 for (var i=0; i < values.length; i++) {
12670 this.addThumb(values[i]);
12674 Ext.apply(this, Ext.slider.Vertical);
12679 * Creates a new thumb and adds it to the slider
12680 * @param {Number} value The initial value to set on the thumb. Defaults to 0
12682 addThumb: function(value) {
12683 var thumb = new Ext.slider.Thumb({
12686 index : this.thumbs.length,
12687 constrain: this.constrainThumbs
12689 this.thumbs.push(thumb);
12691 //render the thumb now if needed
12692 if (this.rendered) thumb.render();
12697 * Moves the given thumb above all other by increasing its z-index. This is called when as drag
12698 * any thumb, so that the thumb that was just dragged is always at the highest z-index. This is
12699 * required when the thumbs are stacked on top of each other at one of the ends of the slider's
12700 * range, which can result in the user not being able to move any of them.
12701 * @param {Ext.slider.Thumb} topThumb The thumb to move to the top
12703 promoteThumb: function(topThumb) {
12704 var thumbs = this.thumbs,
12707 for (var i = 0, j = thumbs.length; i < j; i++) {
12710 if (thumb == topThumb) {
12711 zIndex = this.topThumbZIndex;
12716 thumb.el.setStyle('zIndex', zIndex);
12720 // private override
12721 onRender : function() {
12723 cls: 'x-slider ' + (this.vertical ? 'x-slider-vert' : 'x-slider-horz'),
12725 cls: 'x-slider-end',
12727 cls:'x-slider-inner',
12728 cn : [{tag:'a', cls:'x-slider-focus', href:"#", tabIndex: '-1', hidefocus:'on'}]
12733 Ext.slider.MultiSlider.superclass.onRender.apply(this, arguments);
12735 this.endEl = this.el.first();
12736 this.innerEl = this.endEl.first();
12737 this.focusEl = this.innerEl.child('.x-slider-focus');
12739 //render each thumb
12740 for (var i=0; i < this.thumbs.length; i++) {
12741 this.thumbs[i].render();
12744 //calculate the size of half a thumb
12745 var thumb = this.innerEl.child('.x-slider-thumb');
12746 this.halfThumb = (this.vertical ? thumb.getHeight() : thumb.getWidth()) / 2;
12753 * Adds keyboard and mouse listeners on this.el. Ignores click events on the internal focus element.
12754 * Creates a new DragTracker which is used to control what happens when the user drags the thumb around.
12756 initEvents : function(){
12757 this.mon(this.el, {
12759 mousedown: this.onMouseDown,
12760 keydown : this.onKeyDown
12763 this.focusEl.swallowEvent("click", true);
12768 * Mousedown handler for the slider. If the clickToChange is enabled and the click was not on the draggable 'thumb',
12769 * this calculates the new value of the slider and tells the implementation (Horizontal or Vertical) to move the thumb
12770 * @param {Ext.EventObject} e The click event
12772 onMouseDown : function(e){
12777 //see if the click was on any of the thumbs
12778 var thumbClicked = false;
12779 for (var i=0; i < this.thumbs.length; i++) {
12780 thumbClicked = thumbClicked || e.target == this.thumbs[i].el.dom;
12783 if (this.clickToChange && !thumbClicked) {
12784 var local = this.innerEl.translatePoints(e.getXY());
12785 this.onClickChange(local);
12792 * Moves the thumb to the indicated position. Note that a Vertical implementation is provided in Ext.slider.Vertical.
12793 * Only changes the value if the click was within this.clickRange.
12794 * @param {Object} local Object containing top and left values for the click event.
12796 onClickChange : function(local) {
12797 if (local.top > this.clickRange[0] && local.top < this.clickRange[1]) {
12798 //find the nearest thumb to the click event
12799 var thumb = this.getNearest(local, 'left'),
12800 index = thumb.index;
12802 this.setValue(index, Ext.util.Format.round(this.reverseValue(local.left), this.decimalPrecision), undefined, true);
12808 * Returns the nearest thumb to a click event, along with its distance
12809 * @param {Object} local Object containing top and left values from a click event
12810 * @param {String} prop The property of local to compare on. Use 'left' for horizontal sliders, 'top' for vertical ones
12811 * @return {Object} The closest thumb object and its distance from the click event
12813 getNearest: function(local, prop) {
12814 var localValue = prop == 'top' ? this.innerEl.getHeight() - local[prop] : local[prop],
12815 clickValue = this.reverseValue(localValue),
12816 nearestDistance = (this.maxValue - this.minValue) + 5, //add a small fudge for the end of the slider
12820 for (var i=0; i < this.thumbs.length; i++) {
12821 var thumb = this.thumbs[i],
12822 value = thumb.value,
12823 dist = Math.abs(value - clickValue);
12825 if (Math.abs(dist <= nearestDistance)) {
12828 nearestDistance = dist;
12836 * Handler for any keypresses captured by the slider. If the key is UP or RIGHT, the thumb is moved along to the right
12837 * by this.keyIncrement. If DOWN or LEFT it is moved left. Pressing CTRL moves the slider to the end in either direction
12838 * @param {Ext.EventObject} e The Event object
12840 onKeyDown : function(e){
12841 if(this.disabled){e.preventDefault();return;}
12842 var k = e.getKey();
12848 this.setValue(this.maxValue, undefined, true);
12850 this.setValue(this.value+this.keyIncrement, undefined, true);
12857 this.setValue(this.minValue, undefined, true);
12859 this.setValue(this.value-this.keyIncrement, undefined, true);
12863 e.preventDefault();
12869 * If using snapping, this takes a desired new value and returns the closest snapped
12871 * @param {Number} value The unsnapped value
12872 * @return {Number} The value of the nearest snap target
12874 doSnap : function(value){
12875 if (!(this.increment && value)) {
12878 var newValue = value,
12879 inc = this.increment,
12883 if (m * 2 >= inc) {
12885 } else if (m * 2 < -inc) {
12889 return newValue.constrain(this.minValue, this.maxValue);
12893 afterRender : function(){
12894 Ext.slider.MultiSlider.superclass.afterRender.apply(this, arguments);
12896 for (var i=0; i < this.thumbs.length; i++) {
12897 var thumb = this.thumbs[i];
12899 if (thumb.value !== undefined) {
12900 var v = this.normalizeValue(thumb.value);
12902 if (v !== thumb.value) {
12903 // delete this.value;
12904 this.setValue(i, v, false);
12906 this.moveThumb(i, this.translateValue(v), false);
12914 * Returns the ratio of pixels to mapped values. e.g. if the slider is 200px wide and maxValue - minValue is 100,
12916 * @return {Number} The ratio of pixels to mapped values
12918 getRatio : function(){
12919 var w = this.innerEl.getWidth(),
12920 v = this.maxValue - this.minValue;
12921 return v == 0 ? w : (w/v);
12926 * Returns a snapped, constrained value when given a desired value
12927 * @param {Number} value Raw number value
12928 * @return {Number} The raw value rounded to the correct d.p. and constrained within the set max and min values
12930 normalizeValue : function(v){
12931 v = this.doSnap(v);
12932 v = Ext.util.Format.round(v, this.decimalPrecision);
12933 v = v.constrain(this.minValue, this.maxValue);
12938 * Sets the minimum value for the slider instance. If the current value is less than the
12939 * minimum value, the current value will be changed.
12940 * @param {Number} val The new minimum value
12942 setMinValue : function(val){
12943 this.minValue = val;
12946 for (var i=0, j = this.thumbs.length; i < j; i++) {
12947 if (this.thumbs[i].value < val) this.thumbs[i].value = val;
12952 * Sets the maximum value for the slider instance. If the current value is more than the
12953 * maximum value, the current value will be changed.
12954 * @param {Number} val The new maximum value
12956 setMaxValue : function(val){
12957 this.maxValue = val;
12960 for (var i=0; i < this.thumbs.length; i++) {
12961 if (this.thumbs[i].value > val) this.thumbs[i].value = val;
12966 * Programmatically sets the value of the Slider. Ensures that the value is constrained within
12967 * the minValue and maxValue.
12968 * @param {Number} index Index of the thumb to move
12969 * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
12970 * @param {Boolean} animate Turn on or off animation, defaults to true
12972 setValue : function(index, v, animate, changeComplete) {
12973 var thumb = this.thumbs[index],
12976 v = this.normalizeValue(v);
12978 if (v !== thumb.value && this.fireEvent('beforechange', this, v, thumb.value) !== false) {
12980 this.moveThumb(index, this.translateValue(v), animate !== false);
12981 this.fireEvent('change', this, v, thumb);
12982 if(changeComplete){
12983 this.fireEvent('changecomplete', this, v, thumb);
12991 translateValue : function(v) {
12992 var ratio = this.getRatio();
12993 return (v * ratio) - (this.minValue * ratio) - this.halfThumb;
12998 * Given a pixel location along the slider, returns the mapped slider value for that pixel.
12999 * E.g. if we have a slider 200px wide with minValue = 100 and maxValue = 500, reverseValue(50)
13001 * @param {Number} pos The position along the slider to return a mapped value for
13002 * @return {Number} The mapped value for the given position
13004 reverseValue : function(pos){
13005 var ratio = this.getRatio();
13006 return (pos + (this.minValue * ratio)) / ratio;
13011 * @param {Number} index Index of the thumb to move
13013 moveThumb: function(index, v, animate){
13014 var thumb = this.thumbs[index].el;
13016 if(!animate || this.animate === false){
13019 thumb.shift({left: v, stopFx: true, duration:.35});
13024 focus : function(){
13025 this.focusEl.focus(10);
13029 onResize : function(w, h){
13030 var thumbs = this.thumbs,
13031 len = thumbs.length,
13035 * If we happen to be animating during a resize, the position of the thumb will likely be off
13036 * when the animation stops. As such, just stop any animations before syncing the thumbs.
13038 for(; i < len; ++i){
13039 thumbs[i].el.stopFx();
13041 this.innerEl.setWidth(w - (this.el.getPadding('l') + this.endEl.getPadding('r')));
13043 Ext.slider.MultiSlider.superclass.onResize.apply(this, arguments);
13047 onDisable: function(){
13048 Ext.slider.MultiSlider.superclass.onDisable.call(this);
13050 for (var i=0; i < this.thumbs.length; i++) {
13051 var thumb = this.thumbs[i],
13057 //IE breaks when using overflow visible and opacity other than 1.
13058 //Create a place holder for the thumb and display it.
13059 var xy = el.getXY();
13062 this.innerEl.addClass(this.disabledClass).dom.disabled = true;
13064 if (!this.thumbHolder) {
13065 this.thumbHolder = this.endEl.createChild({cls: 'x-slider-thumb ' + this.disabledClass});
13068 this.thumbHolder.show().setXY(xy);
13074 onEnable: function(){
13075 Ext.slider.MultiSlider.superclass.onEnable.call(this);
13077 for (var i=0; i < this.thumbs.length; i++) {
13078 var thumb = this.thumbs[i],
13084 this.innerEl.removeClass(this.disabledClass).dom.disabled = false;
13086 if (this.thumbHolder) this.thumbHolder.hide();
13095 * Synchronizes the thumb position to the proper proportion of the total component width based
13096 * on the current slider {@link #value}. This will be called automatically when the Slider
13097 * is resized by a layout, but if it is rendered auto width, this method can be called from
13098 * another resize handler to sync the Slider if necessary.
13100 syncThumb : function() {
13101 if (this.rendered) {
13102 for (var i=0; i < this.thumbs.length; i++) {
13103 this.moveThumb(i, this.translateValue(this.thumbs[i].value));
13109 * Returns the current value of the slider
13110 * @param {Number} index The index of the thumb to return a value for
13111 * @return {Number} The current value of the slider
13113 getValue : function(index) {
13114 return this.thumbs[index].value;
13118 * Returns an array of values - one for the location of each thumb
13119 * @return {Array} The set of thumb values
13121 getValues: function() {
13124 for (var i=0; i < this.thumbs.length; i++) {
13125 values.push(this.thumbs[i].value);
13132 beforeDestroy : function(){
13133 Ext.destroyMembers(this, 'endEl', 'innerEl', 'thumb', 'halfThumb', 'focusEl', 'tracker', 'thumbHolder');
13134 Ext.slider.MultiSlider.superclass.beforeDestroy.call(this);
13138 Ext.reg('multislider', Ext.slider.MultiSlider);
13141 * @class Ext.slider.SingleSlider
13142 * @extends Ext.slider.MultiSlider
13143 * Slider which supports vertical or horizontal orientation, keyboard adjustments,
13144 * configurable snapping, axis clicking and animation. Can be added as an item to
13145 * any container. Example usage:
13147 new Ext.slider.SingleSlider({
13148 renderTo: Ext.getBody(),
13156 * The class Ext.slider.SingleSlider is aliased to Ext.Slider for backwards compatibility.
13158 Ext.slider.SingleSlider = Ext.extend(Ext.slider.MultiSlider, {
13159 constructor: function(config) {
13160 config = config || {};
13162 Ext.applyIf(config, {
13163 values: [config.value || 0]
13166 Ext.slider.SingleSlider.superclass.constructor.call(this, config);
13170 * Returns the current value of the slider
13171 * @return {Number} The current value of the slider
13173 getValue: function() {
13174 //just returns the value of the first thumb, which should be the only one in a single slider
13175 return Ext.slider.SingleSlider.superclass.getValue.call(this, 0);
13179 * Programmatically sets the value of the Slider. Ensures that the value is constrained within
13180 * the minValue and maxValue.
13181 * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
13182 * @param {Boolean} animate Turn on or off animation, defaults to true
13184 setValue: function(value, animate) {
13185 var args = Ext.toArray(arguments),
13188 //this is to maintain backwards compatiblity for sliders with only one thunb. Usually you must pass the thumb
13189 //index to setValue, but if we only have one thumb we inject the index here first if given the multi-slider
13190 //signature without the required index. The index will always be 0 for a single slider
13191 if (len == 1 || (len <= 3 && typeof arguments[1] != 'number')) {
13195 return Ext.slider.SingleSlider.superclass.setValue.apply(this, args);
13199 * Synchronizes the thumb position to the proper proportion of the total component width based
13200 * on the current slider {@link #value}. This will be called automatically when the Slider
13201 * is resized by a layout, but if it is rendered auto width, this method can be called from
13202 * another resize handler to sync the Slider if necessary.
13204 syncThumb : function() {
13205 return Ext.slider.SingleSlider.superclass.syncThumb.apply(this, [0].concat(arguments));
13209 getNearest : function(){
13210 // Since there's only 1 thumb, it's always the nearest
13211 return this.thumbs[0];
13215 //backwards compatibility
13216 Ext.Slider = Ext.slider.SingleSlider;
13218 Ext.reg('slider', Ext.slider.SingleSlider);
13220 // private class to support vertical sliders
13221 Ext.slider.Vertical = {
13222 onResize : function(w, h){
13223 this.innerEl.setHeight(h - (this.el.getPadding('t') + this.endEl.getPadding('b')));
13227 getRatio : function(){
13228 var h = this.innerEl.getHeight(),
13229 v = this.maxValue - this.minValue;
13233 moveThumb: function(index, v, animate) {
13234 var thumb = this.thumbs[index],
13237 if (!animate || this.animate === false) {
13240 el.shift({bottom: v, stopFx: true, duration:.35});
13244 onClickChange : function(local) {
13245 if (local.left > this.clickRange[0] && local.left < this.clickRange[1]) {
13246 var thumb = this.getNearest(local, 'top'),
13247 index = thumb.index,
13248 value = this.minValue + this.reverseValue(this.innerEl.getHeight() - local.top);
13250 this.setValue(index, Ext.util.Format.round(value, this.decimalPrecision), undefined, true);
13255 //private class to support vertical dragging of thumbs within a slider
13256 Ext.slider.Thumb.Vertical = {
13257 getNewValue: function() {
13258 var slider = this.slider,
13259 innerEl = slider.innerEl,
13260 pos = innerEl.translatePoints(this.tracker.getXY()),
13261 bottom = innerEl.getHeight() - pos.top;
13263 return slider.minValue + Ext.util.Format.round(bottom / slider.getRatio(), slider.decimalPrecision);
13267 * @class Ext.ProgressBar
13268 * @extends Ext.BoxComponent
13269 * <p>An updateable progress bar component. The progress bar supports two different modes: manual and automatic.</p>
13270 * <p>In manual mode, you are responsible for showing, updating (via {@link #updateProgress}) and clearing the
13271 * progress bar as needed from your own code. This method is most appropriate when you want to show progress
13272 * throughout an operation that has predictable points of interest at which you can update the control.</p>
13273 * <p>In automatic mode, you simply call {@link #wait} and let the progress bar run indefinitely, only clearing it
13274 * once the operation is complete. You can optionally have the progress bar wait for a specific amount of time
13275 * and then clear itself. Automatic mode is most appropriate for timed operations or asynchronous operations in
13276 * which you have no need for indicating intermediate progress.</p>
13277 * @cfg {Float} value A floating point value between 0 and 1 (e.g., .5, defaults to 0)
13278 * @cfg {String} text The progress bar text (defaults to '')
13279 * @cfg {Mixed} textEl The element to render the progress text to (defaults to the progress
13280 * bar's internal text element)
13281 * @cfg {String} id The progress bar element's id (defaults to an auto-generated id)
13284 Ext.ProgressBar = Ext.extend(Ext.BoxComponent, {
13286 * @cfg {String} baseCls
13287 * The base CSS class to apply to the progress bar's wrapper element (defaults to 'x-progress')
13289 baseCls : 'x-progress',
13292 * @cfg {Boolean} animate
13293 * True to animate the progress bar during transitions (defaults to false)
13301 initComponent : function(){
13302 Ext.ProgressBar.superclass.initComponent.call(this);
13306 * Fires after each update interval
13307 * @param {Ext.ProgressBar} this
13308 * @param {Number} The current progress value
13309 * @param {String} The current progress text
13316 onRender : function(ct, position){
13317 var tpl = new Ext.Template(
13318 '<div class="{cls}-wrap">',
13319 '<div class="{cls}-inner">',
13320 '<div class="{cls}-bar">',
13321 '<div class="{cls}-text">',
13322 '<div> </div>',
13325 '<div class="{cls}-text {cls}-text-back">',
13326 '<div> </div>',
13332 this.el = position ? tpl.insertBefore(position, {cls: this.baseCls}, true)
13333 : tpl.append(ct, {cls: this.baseCls}, true);
13336 this.el.dom.id = this.id;
13338 var inner = this.el.dom.firstChild;
13339 this.progressBar = Ext.get(inner.firstChild);
13342 //use an external text el
13343 this.textEl = Ext.get(this.textEl);
13344 delete this.textTopEl;
13346 //setup our internal layered text els
13347 this.textTopEl = Ext.get(this.progressBar.dom.firstChild);
13348 var textBackEl = Ext.get(inner.childNodes[1]);
13349 this.textTopEl.setStyle("z-index", 99).addClass('x-hidden');
13350 this.textEl = new Ext.CompositeElement([this.textTopEl.dom.firstChild, textBackEl.dom.firstChild]);
13351 this.textEl.setWidth(inner.offsetWidth);
13353 this.progressBar.setHeight(inner.offsetHeight);
13357 afterRender : function(){
13358 Ext.ProgressBar.superclass.afterRender.call(this);
13360 this.updateProgress(this.value, this.text);
13362 this.updateText(this.text);
13367 * Updates the progress bar value, and optionally its text. If the text argument is not specified,
13368 * any existing text value will be unchanged. To blank out existing text, pass ''. Note that even
13369 * if the progress bar value exceeds 1, it will never automatically reset -- you are responsible for
13370 * determining when the progress is complete and calling {@link #reset} to clear and/or hide the control.
13371 * @param {Float} value (optional) A floating point value between 0 and 1 (e.g., .5, defaults to 0)
13372 * @param {String} text (optional) The string to display in the progress text element (defaults to '')
13373 * @param {Boolean} animate (optional) Whether to animate the transition of the progress bar. If this value is
13374 * not specified, the default for the class is used (default to false)
13375 * @return {Ext.ProgressBar} this
13377 updateProgress : function(value, text, animate){
13378 this.value = value || 0;
13380 this.updateText(text);
13382 if(this.rendered && !this.isDestroyed){
13383 var w = Math.floor(value*this.el.dom.firstChild.offsetWidth);
13384 this.progressBar.setWidth(w, animate === true || (animate !== false && this.animate));
13385 if(this.textTopEl){
13386 //textTopEl should be the same width as the bar so overflow will clip as the bar moves
13387 this.textTopEl.removeClass('x-hidden').setWidth(w);
13390 this.fireEvent('update', this, value, text);
13395 * Initiates an auto-updating progress bar. A duration can be specified, in which case the progress
13396 * bar will automatically reset after a fixed amount of time and optionally call a callback function
13397 * if specified. If no duration is passed in, then the progress bar will run indefinitely and must
13398 * be manually cleared by calling {@link #reset}. The wait method accepts a config object with
13399 * the following properties:
13401 Property Type Description
13402 ---------- ------------ ----------------------------------------------------------------------
13403 duration Number The length of time in milliseconds that the progress bar should
13404 run before resetting itself (defaults to undefined, in which case it
13405 will run indefinitely until reset is called)
13406 interval Number The length of time in milliseconds between each progress update
13407 (defaults to 1000 ms)
13408 animate Boolean Whether to animate the transition of the progress bar. If this value is
13409 not specified, the default for the class is used.
13410 increment Number The number of progress update segments to display within the progress
13411 bar (defaults to 10). If the bar reaches the end and is still
13412 updating, it will automatically wrap back to the beginning.
13413 text String Optional text to display in the progress bar element (defaults to '').
13414 fn Function A callback function to execute after the progress bar finishes auto-
13415 updating. The function will be called with no arguments. This function
13416 will be ignored if duration is not specified since in that case the
13417 progress bar can only be stopped programmatically, so any required function
13418 should be called by the same code after it resets the progress bar.
13419 scope Object The scope that is passed to the callback function (only applies when
13420 duration and fn are both passed).
13425 var p = new Ext.ProgressBar({
13429 //Wait for 5 seconds, then update the status el (progress bar will auto-reset)
13431 interval: 100, //bar will move fast!
13434 text: 'Updating...',
13437 Ext.fly('status').update('Done!');
13441 //Or update indefinitely until some async action completes, then reset manually
13443 myAction.on('complete', function(){
13445 Ext.fly('status').update('Done!');
13448 * @param {Object} config (optional) Configuration options
13449 * @return {Ext.ProgressBar} this
13451 wait : function(o){
13452 if(!this.waitTimer){
13455 this.updateText(o.text);
13456 this.waitTimer = Ext.TaskMgr.start({
13458 var inc = o.increment || 10;
13460 this.updateProgress(((((i+inc)%inc)+1)*(100/inc))*0.01, null, o.animate);
13462 interval: o.interval || 1000,
13463 duration: o.duration,
13464 onStop: function(){
13466 o.fn.apply(o.scope || this);
13477 * Returns true if the progress bar is currently in a {@link #wait} operation
13478 * @return {Boolean} True if waiting, else false
13480 isWaiting : function(){
13481 return this.waitTimer !== null;
13485 * Updates the progress bar text. If specified, textEl will be updated, otherwise the progress
13486 * bar itself will display the updated text.
13487 * @param {String} text (optional) The string to display in the progress text element (defaults to '')
13488 * @return {Ext.ProgressBar} this
13490 updateText : function(text){
13491 this.text = text || ' ';
13493 this.textEl.update(this.text);
13499 * Synchronizes the inner bar width to the proper proportion of the total componet width based
13500 * on the current progress {@link #value}. This will be called automatically when the ProgressBar
13501 * is resized by a layout, but if it is rendered auto width, this method can be called from
13502 * another resize handler to sync the ProgressBar if necessary.
13504 syncProgressBar : function(){
13506 this.updateProgress(this.value, this.text);
13512 * Sets the size of the progress bar.
13513 * @param {Number} width The new width in pixels
13514 * @param {Number} height The new height in pixels
13515 * @return {Ext.ProgressBar} this
13517 setSize : function(w, h){
13518 Ext.ProgressBar.superclass.setSize.call(this, w, h);
13519 if(this.textTopEl){
13520 var inner = this.el.dom.firstChild;
13521 this.textEl.setSize(inner.offsetWidth, inner.offsetHeight);
13523 this.syncProgressBar();
13528 * Resets the progress bar value to 0 and text to empty string. If hide = true, the progress
13529 * bar will also be hidden (using the {@link #hideMode} property internally).
13530 * @param {Boolean} hide (optional) True to hide the progress bar (defaults to false)
13531 * @return {Ext.ProgressBar} this
13533 reset : function(hide){
13534 this.updateProgress(0);
13535 if(this.textTopEl){
13536 this.textTopEl.addClass('x-hidden');
13546 clearTimer : function(){
13547 if(this.waitTimer){
13548 this.waitTimer.onStop = null; //prevent recursion
13549 Ext.TaskMgr.stop(this.waitTimer);
13550 this.waitTimer = null;
13554 onDestroy: function(){
13557 if(this.textEl.isComposite){
13558 this.textEl.clear();
13560 Ext.destroyMembers(this, 'textEl', 'progressBar', 'textTopEl');
13562 Ext.ProgressBar.superclass.onDestroy.call(this);
13565 Ext.reg('progress', Ext.ProgressBar);