3 * Copyright(c) 2006-2009 Ext JS, LLC
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 * Checks if a Component type is registered.
79 * @param {Ext.Component} xtype The mnemonic string by which the Component class may be looked up
80 * @return {Boolean} Whether the type is registered.
82 isRegistered : function(xtype){
83 return types[xtype] !== undefined;
87 * <p>Registers a new Component constructor, keyed by a new
88 * {@link Ext.Component#xtype}.</p>
89 * <p>Use this method (or its alias {@link Ext#reg Ext.reg}) to register new
90 * subclasses of {@link Ext.Component} so that lazy instantiation may be used when specifying
92 * see {@link Ext.Container#items}</p>
93 * @param {String} xtype The mnemonic string by which the Component class may be looked up.
94 * @param {Constructor} cls The new Component class.
96 registerType : function(xtype, cls){
102 * Creates a new Component from the specified config object using the
103 * config object's {@link Ext.component#xtype xtype} to determine the class to instantiate.
104 * @param {Object} config A configuration object for the Component you wish to create.
105 * @param {Constructor} defaultType The constructor to provide the default Component type if
106 * the config object does not contain a <code>xtype</code>. (Optional if the config contains a <code>xtype</code>).
107 * @return {Ext.Component} The newly instantiated Component.
109 create : function(config, defaultType){
110 return config.render ? config : new types[config.xtype || defaultType](config);
114 * <p>Registers a new Plugin constructor, keyed by a new
115 * {@link Ext.Component#ptype}.</p>
116 * <p>Use this method (or its alias {@link Ext#preg Ext.preg}) to register new
117 * plugins for {@link Ext.Component}s so that lazy instantiation may be used when specifying
119 * @param {String} ptype The mnemonic string by which the Plugin class may be looked up.
120 * @param {Constructor} cls The new Plugin class.
122 registerPlugin : function(ptype, cls){
128 * Creates a new Plugin from the specified config object using the
129 * config object's {@link Ext.component#ptype ptype} to determine the class to instantiate.
130 * @param {Object} config A configuration object for the Plugin you wish to create.
131 * @param {Constructor} defaultType The constructor to provide the default Plugin type if
132 * the config object does not contain a <code>ptype</code>. (Optional if the config contains a <code>ptype</code>).
133 * @return {Ext.Component} The newly instantiated Plugin.
135 createPlugin : function(config, defaultType){
136 var PluginCls = ptypes[config.ptype || defaultType];
137 if (PluginCls.init) {
140 return new PluginCls(config);
147 * Shorthand for {@link Ext.ComponentMgr#registerType}
148 * @param {String} xtype The {@link Ext.component#xtype mnemonic string} by which the Component class
150 * @param {Constructor} cls The new Component class.
154 Ext.reg = Ext.ComponentMgr.registerType; // this will be called a lot internally, shorthand to keep the bytes down
156 * Shorthand for {@link Ext.ComponentMgr#registerPlugin}
157 * @param {String} ptype The {@link Ext.component#ptype mnemonic string} by which the Plugin class
159 * @param {Constructor} cls The new Plugin class.
163 Ext.preg = Ext.ComponentMgr.registerPlugin;
165 * Shorthand for {@link Ext.ComponentMgr#create}
166 * Creates a new Component from the specified config object using the
167 * config object's {@link Ext.component#xtype xtype} to determine the class to instantiate.
168 * @param {Object} config A configuration object for the Component you wish to create.
169 * @param {Constructor} defaultType The constructor to provide the default Component type if
170 * the config object does not contain a <code>xtype</code>. (Optional if the config contains a <code>xtype</code>).
171 * @return {Ext.Component} The newly instantiated Component.
175 Ext.create = Ext.ComponentMgr.create;/**
176 * @class Ext.Component
177 * @extends Ext.util.Observable
178 * <p>Base class for all Ext components. All subclasses of Component may participate in the automated
179 * Ext component lifecycle of creation, rendering and destruction which is provided by the {@link Ext.Container Container} class.
180 * Components may be added to a Container through the {@link Ext.Container#items items} config option at the time the Container is created,
181 * or they may be added dynamically via the {@link Ext.Container#add add} method.</p>
182 * <p>The Component base class has built-in support for basic hide/show and enable/disable behavior.</p>
183 * <p>All Components are registered with the {@link Ext.ComponentMgr} on construction so that they can be referenced at any time via
184 * {@link Ext#getCmp}, passing the {@link #id}.</p>
185 * <p>All user-developed visual widgets that are required to participate in automated lifecycle and size management should subclass Component (or
186 * {@link Ext.BoxComponent} if managed box model handling is required, ie height and width management).</p>
187 * <p>See the <a href="http://extjs.com/learn/Tutorial:Creating_new_UI_controls">Creating new UI controls</a> tutorial for details on how
188 * and to either extend or augment ExtJs base classes to create custom Components.</p>
189 * <p>Every component has a specific xtype, which is its Ext-specific type name, along with methods for checking the
190 * xtype like {@link #getXType} and {@link #isXType}. This is the list of all valid xtypes:</p>
193 ------------- ------------------
194 box {@link Ext.BoxComponent}
195 button {@link Ext.Button}
196 buttongroup {@link Ext.ButtonGroup}
197 colorpalette {@link Ext.ColorPalette}
198 component {@link Ext.Component}
199 container {@link Ext.Container}
200 cycle {@link Ext.CycleButton}
201 dataview {@link Ext.DataView}
202 datepicker {@link Ext.DatePicker}
203 editor {@link Ext.Editor}
204 editorgrid {@link Ext.grid.EditorGridPanel}
205 flash {@link Ext.FlashComponent}
206 grid {@link Ext.grid.GridPanel}
207 listview {@link Ext.ListView}
208 panel {@link Ext.Panel}
209 progress {@link Ext.ProgressBar}
210 propertygrid {@link Ext.grid.PropertyGrid}
211 slider {@link Ext.Slider}
212 spacer {@link Ext.Spacer}
213 splitbutton {@link Ext.SplitButton}
214 tabpanel {@link Ext.TabPanel}
215 treepanel {@link Ext.tree.TreePanel}
216 viewport {@link Ext.ViewPort}
217 window {@link Ext.Window}
220 ---------------------------------------
221 paging {@link Ext.PagingToolbar}
222 toolbar {@link Ext.Toolbar}
223 tbbutton {@link Ext.Toolbar.Button} (deprecated; use button)
224 tbfill {@link Ext.Toolbar.Fill}
225 tbitem {@link Ext.Toolbar.Item}
226 tbseparator {@link Ext.Toolbar.Separator}
227 tbspacer {@link Ext.Toolbar.Spacer}
228 tbsplit {@link Ext.Toolbar.SplitButton} (deprecated; use splitbutton)
229 tbtext {@link Ext.Toolbar.TextItem}
232 ---------------------------------------
233 menu {@link Ext.menu.Menu}
234 colormenu {@link Ext.menu.ColorMenu}
235 datemenu {@link Ext.menu.DateMenu}
236 menubaseitem {@link Ext.menu.BaseItem}
237 menucheckitem {@link Ext.menu.CheckItem}
238 menuitem {@link Ext.menu.Item}
239 menuseparator {@link Ext.menu.Separator}
240 menutextitem {@link Ext.menu.TextItem}
243 ---------------------------------------
244 form {@link Ext.form.FormPanel}
245 checkbox {@link Ext.form.Checkbox}
246 checkboxgroup {@link Ext.form.CheckboxGroup}
247 combo {@link Ext.form.ComboBox}
248 datefield {@link Ext.form.DateField}
249 displayfield {@link Ext.form.DisplayField}
250 field {@link Ext.form.Field}
251 fieldset {@link Ext.form.FieldSet}
252 hidden {@link Ext.form.Hidden}
253 htmleditor {@link Ext.form.HtmlEditor}
254 label {@link Ext.form.Label}
255 numberfield {@link Ext.form.NumberField}
256 radio {@link Ext.form.Radio}
257 radiogroup {@link Ext.form.RadioGroup}
258 textarea {@link Ext.form.TextArea}
259 textfield {@link Ext.form.TextField}
260 timefield {@link Ext.form.TimeField}
261 trigger {@link Ext.form.TriggerField}
264 ---------------------------------------
265 chart {@link Ext.chart.Chart}
266 barchart {@link Ext.chart.BarChart}
267 cartesianchart {@link Ext.chart.CartesianChart}
268 columnchart {@link Ext.chart.ColumnChart}
269 linechart {@link Ext.chart.LineChart}
270 piechart {@link Ext.chart.PieChart}
273 ---------------------------------------
274 arraystore {@link Ext.data.ArrayStore}
275 directstore {@link Ext.data.DirectStore}
276 groupingstore {@link Ext.data.GroupingStore}
277 jsonstore {@link Ext.data.JsonStore}
278 simplestore {@link Ext.data.SimpleStore} (deprecated; use arraystore)
279 store {@link Ext.data.Store}
280 xmlstore {@link Ext.data.XmlStore}
283 * @param {Ext.Element/String/Object} config The configuration options may be specified as either:
284 * <div class="mdetail-params"><ul>
285 * <li><b>an element</b> :
286 * <p class="sub-desc">it is set as the internal element and its id used as the component id</p></li>
287 * <li><b>a string</b> :
288 * <p class="sub-desc">it is assumed to be the id of an existing element and is used as the component id</p></li>
289 * <li><b>anything else</b> :
290 * <p class="sub-desc">it is assumed to be a standard config object and is applied to the component</p></li>
293 Ext.Component = function(config){
294 config = config || {};
295 if(config.initialConfig){
296 if(config.isAction){ // actions
297 this.baseAction = config;
299 config = config.initialConfig; // component cloning / action set up
300 }else if(config.tagName || config.dom || Ext.isString(config)){ // element object
301 config = {applyTo: config, id: config.id || config};
305 * This Component's initial configuration specification. Read-only.
307 * @property initialConfig
309 this.initialConfig = config;
311 Ext.apply(this, config);
315 * Fires when a component is added to an Ext.Container
316 * @param {Ext.Component} this
317 * @param {Ext.Container} ownerCt Container which holds the component
318 * @param {number} index Position at which the component was added
323 * Fires after the component is disabled.
324 * @param {Ext.Component} this
329 * Fires after the component is enabled.
330 * @param {Ext.Component} this
335 * Fires before the component is shown by calling the {@link #show} method.
336 * Return false from an event handler to stop the show.
337 * @param {Ext.Component} this
342 * Fires after the component is shown when calling the {@link #show} method.
343 * @param {Ext.Component} this
348 * Fires before the component is hidden by calling the {@link #hide} method.
349 * Return false from an event handler to stop the hide.
350 * @param {Ext.Component} this
355 * Fires after the component is hidden.
356 * Fires after the component is hidden when calling the {@link #hide} method.
357 * @param {Ext.Component} this
362 * Fires when a component is removed from an Ext.Container
363 * @param {Ext.Component} this
364 * @param {Ext.Container} ownerCt Container which holds the component
368 * @event beforerender
369 * Fires before the component is {@link #rendered}. Return false from an
370 * event handler to stop the {@link #render}.
371 * @param {Ext.Component} this
376 * Fires after the component markup is {@link #rendered}.
377 * @param {Ext.Component} this
382 * <p>Fires after the component rendering is finished.</p>
383 * <p>The afterrender event is fired after this Component has been {@link #rendered}, been postprocesed
384 * by any afterRender method defined for the Component, and, if {@link #stateful}, after state
385 * has been restored.</p>
386 * @param {Ext.Component} this
390 * @event beforedestroy
391 * Fires before the component is {@link #destroy}ed. Return false from an event handler to stop the {@link #destroy}.
392 * @param {Ext.Component} this
397 * Fires after the component is {@link #destroy}ed.
398 * @param {Ext.Component} this
402 * @event beforestaterestore
403 * Fires before the state of the component is restored. Return false from an event handler to stop the restore.
404 * @param {Ext.Component} this
405 * @param {Object} state The hash of state values returned from the StateProvider. If this
406 * event is not vetoed, then the state object is passed to <b><tt>applyState</tt></b>. By default,
407 * that simply copies property values into this Component. The method maybe overriden to
408 * provide custom state restoration.
410 'beforestaterestore',
412 * @event staterestore
413 * Fires after the state of the component is restored.
414 * @param {Ext.Component} this
415 * @param {Object} state The hash of state values returned from the StateProvider. This is passed
416 * to <b><tt>applyState</tt></b>. By default, that simply copies property values into this
417 * Component. The method maybe overriden to provide custom state restoration.
421 * @event beforestatesave
422 * Fires before the state of the component is saved to the configured state provider. Return false to stop the save.
423 * @param {Ext.Component} this
424 * @param {Object} state The hash of state values. This is determined by calling
425 * <b><tt>getState()</tt></b> on the Component. This method must be provided by the
426 * developer to return whetever representation of state is required, by default, Ext.Component
427 * has a null implementation.
432 * Fires after the state of the component is saved to the configured state provider.
433 * @param {Ext.Component} this
434 * @param {Object} state The hash of state values. This is determined by calling
435 * <b><tt>getState()</tt></b> on the Component. This method must be provided by the
436 * developer to return whetever representation of state is required, by default, Ext.Component
437 * has a null implementation.
442 Ext.ComponentMgr.register(this);
443 Ext.Component.superclass.constructor.call(this);
446 this.baseAction.addComponent(this);
449 this.initComponent();
452 if(Ext.isArray(this.plugins)){
453 for(var i = 0, len = this.plugins.length; i < len; i++){
454 this.plugins[i] = this.initPlugin(this.plugins[i]);
457 this.plugins = this.initPlugin(this.plugins);
461 if(this.stateful !== false){
466 this.applyToMarkup(this.applyTo);
468 }else if(this.renderTo){
469 this.render(this.renderTo);
470 delete this.renderTo;
475 Ext.Component.AUTO_ID = 1000;
477 Ext.extend(Ext.Component, Ext.util.Observable, {
478 // Configs below are used for all Components when rendered by FormLayout.
480 * @cfg {String} fieldLabel <p>The label text to display next to this Component (defaults to '').</p>
481 * <br><p><b>Note</b>: this config is only used when this Component is rendered by a Container which
482 * has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout manager (e.g.
483 * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>).</p><br>
484 * <p>Also see <tt>{@link #hideLabel}</tt> and
485 * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</p>
486 * Example use:<pre><code>
489 renderTo: Ext.getBody(),
498 * @cfg {String} labelStyle <p>A CSS style specification string to apply directly to this field's
499 * label. Defaults to the container's labelStyle value if set (e.g.,
500 * <tt>{@link Ext.layout.FormLayout#labelStyle}</tt> , or '').</p>
501 * <br><p><b>Note</b>: see the note for <code>{@link #clearCls}</code>.</p><br>
502 * <p>Also see <code>{@link #hideLabel}</code> and
503 * <code>{@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</code></p>
504 * Example use:<pre><code>
507 renderTo: Ext.getBody(),
511 labelStyle: 'font-weight:bold;'
517 * @cfg {String} labelSeparator <p>The separator to display after the text of each
518 * <tt>{@link #fieldLabel}</tt>. This property may be configured at various levels.
519 * The order of precedence is:
520 * <div class="mdetail-params"><ul>
521 * <li>field / component level</li>
522 * <li>container level</li>
523 * <li>{@link Ext.layout.FormLayout#labelSeparator layout level} (defaults to colon <tt>':'</tt>)</li>
525 * To display no separator for this field's label specify empty string ''.</p>
526 * <br><p><b>Note</b>: see the note for <tt>{@link #clearCls}</tt>.</p><br>
527 * <p>Also see <tt>{@link #hideLabel}</tt> and
528 * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</p>
529 * Example use:<pre><code>
532 renderTo: Ext.getBody(),
534 labelSeparator: '~' // layout config has lowest priority (defaults to ':')
536 {@link Ext.layout.FormLayout#labelSeparator labelSeparator}: '>>', // config at container level
539 fieldLabel: 'Field 1',
540 labelSeparator: '...' // field/component level config supersedes others
543 fieldLabel: 'Field 2' // labelSeparator will be '='
549 * @cfg {Boolean} hideLabel <p><tt>true</tt> to completely hide the label element
550 * ({@link #fieldLabel label} and {@link #labelSeparator separator}). Defaults to <tt>false</tt>.
551 * By default, even if you do not specify a <tt>{@link #fieldLabel}</tt> the space will still be
552 * reserved so that the field will line up with other fields that do have labels.
553 * Setting this to <tt>true</tt> will cause the field to not reserve that space.</p>
554 * <br><p><b>Note</b>: see the note for <tt>{@link #clearCls}</tt>.</p><br>
555 * Example use:<pre><code>
558 renderTo: Ext.getBody(),
567 * @cfg {String} clearCls <p>The CSS class used to to apply to the special clearing div rendered
568 * directly after each form field wrapper to provide field clearing (defaults to
569 * <tt>'x-form-clear-left'</tt>).</p>
570 * <br><p><b>Note</b>: this config is only used when this Component is rendered by a Container
571 * which has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout
572 * manager (e.g. {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>) and either a
573 * <tt>{@link #fieldLabel}</tt> is specified or <tt>isFormField=true</tt> is specified.</p><br>
574 * <p>See {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl} also.</p>
577 * @cfg {String} itemCls
578 * <p><b>Note</b>: this config is only used when this Component is rendered by a Container which
579 * has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout manager (e.g.
580 * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>).</p><br>
581 * <p>An additional CSS class to apply to the div wrapping the form item
582 * element of this field. If supplied, <tt>itemCls</tt> at the <b>field</b> level will override
583 * the default <tt>itemCls</tt> supplied at the <b>container</b> level. The value specified for
584 * <tt>itemCls</tt> will be added to the default class (<tt>'x-form-item'</tt>).</p>
585 * <p>Since it is applied to the item wrapper (see
586 * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}), it allows
587 * you to write standard CSS rules that can apply to the field, the label (if specified), or
588 * any other element within the markup for the field.</p>
589 * <br><p><b>Note</b>: see the note for <tt>{@link #fieldLabel}</tt>.</p><br>
590 * Example use:<pre><code>
591 // Apply a style to the field's label:
593 .required .x-form-item-label {font-weight:bold;color:red;}
598 renderTo: Ext.getBody(),
602 itemCls: 'required' //this label will be styled
605 fieldLabel: 'Favorite Color'
611 // Configs below are used for all Components when rendered by AnchorLayout.
613 * @cfg {String} anchor <p><b>Note</b>: this config is only used when this Component is rendered
614 * by a Container which has been configured to use an <b>{@link Ext.layout.AnchorLayout AnchorLayout}</b>
615 * based layout manager, for example:<div class="mdetail-params"><ul>
616 * <li>{@link Ext.form.FormPanel}</li>
617 * <li>specifying <code>layout: 'anchor' // or 'form', or 'absolute'</code></li>
619 * <p>See {@link Ext.layout.AnchorLayout}.{@link Ext.layout.AnchorLayout#anchor anchor} also.</p>
624 * <p>The <b>unique</b> id of this component (defaults to an {@link #getId auto-assigned id}).
625 * You should assign an id if you need to be able to access the component later and you do
626 * not have an object reference available (e.g., using {@link Ext}.{@link Ext#getCmp getCmp}).</p>
627 * <p>Note that this id will also be used as the element id for the containing HTML element
628 * that is rendered to the page for this component. This allows you to write id-based CSS
629 * rules to style the specific instance of this component uniquely, and also to select
630 * sub-elements using this component's id as the parent.</p>
631 * <p><b>Note</b>: to avoid complications imposed by a unique <tt>id</tt> also see
632 * <code>{@link #itemId}</code> and <code>{@link #ref}</code>.</p>
633 * <p><b>Note</b>: to access the container of an item see <code>{@link #ownerCt}</code>.</p>
636 * @cfg {String} itemId
637 * <p>An <tt>itemId</tt> can be used as an alternative way to get a reference to a component
638 * when no object reference is available. Instead of using an <code>{@link #id}</code> with
639 * {@link Ext}.{@link Ext#getCmp getCmp}, use <code>itemId</code> with
640 * {@link Ext.Container}.{@link Ext.Container#getComponent getComponent} which will retrieve
641 * <code>itemId</code>'s or <tt>{@link #id}</tt>'s. Since <code>itemId</code>'s are an index to the
642 * container's internal MixedCollection, the <code>itemId</code> is scoped locally to the container --
643 * avoiding potential conflicts with {@link Ext.ComponentMgr} which requires a <b>unique</b>
644 * <code>{@link #id}</code>.</p>
646 var c = new Ext.Panel({ //
647 {@link Ext.BoxComponent#height height}: 300,
648 {@link #renderTo}: document.body,
649 {@link Ext.Container#layout layout}: 'auto',
650 {@link Ext.Container#items items}: [
653 {@link Ext.Panel#title title}: 'Panel 1',
654 {@link Ext.BoxComponent#height height}: 150
658 {@link Ext.Panel#title title}: 'Panel 2',
659 {@link Ext.BoxComponent#height height}: 150
663 p1 = c.{@link Ext.Container#getComponent getComponent}('p1'); // not the same as {@link Ext#getCmp Ext.getCmp()}
664 p2 = p1.{@link #ownerCt}.{@link Ext.Container#getComponent getComponent}('p2'); // reference via a sibling
666 * <p>Also see <tt>{@link #id}</tt> and <code>{@link #ref}</code>.</p>
667 * <p><b>Note</b>: to access the container of an item see <tt>{@link #ownerCt}</tt>.</p>
670 * @cfg {String} xtype
671 * The registered <tt>xtype</tt> to create. This config option is not used when passing
672 * a config object into a constructor. This config option is used only when
673 * lazy instantiation is being used, and a child item of a Container is being
674 * specified not as a fully instantiated Component, but as a <i>Component config
675 * object</i>. The <tt>xtype</tt> will be looked up at render time up to determine what
676 * type of child Component to create.<br><br>
677 * The predefined xtypes are listed {@link Ext.Component here}.
679 * If you subclass Components to create your own Components, you may register
680 * them using {@link Ext.ComponentMgr#registerType} in order to be able to
681 * take advantage of lazy instantiation and rendering.
684 * @cfg {String} ptype
685 * The registered <tt>ptype</tt> to create. This config option is not used when passing
686 * a config object into a constructor. This config option is used only when
687 * lazy instantiation is being used, and a Plugin is being
688 * specified not as a fully instantiated Component, but as a <i>Component config
689 * object</i>. The <tt>ptype</tt> will be looked up at render time up to determine what
690 * type of Plugin to create.<br><br>
691 * If you create your own Plugins, you may register them using
692 * {@link Ext.ComponentMgr#registerPlugin} in order to be able to
693 * take advantage of lazy instantiation and rendering.
697 * An optional extra CSS class that will be added to this component's Element (defaults to ''). This can be
698 * useful for adding customized styles to the component or any of its children using standard CSS rules.
701 * @cfg {String} overCls
702 * An optional extra CSS class that will be added to this component's Element when the mouse moves
703 * over the Element, and removed when the mouse moves out. (defaults to ''). This can be
704 * useful for adding customized 'active' or 'hover' styles to the component or any of its children using standard CSS rules.
707 * @cfg {String} style
708 * A custom style specification to be applied to this component's Element. Should be a valid argument to
709 * {@link Ext.Element#applyStyles}.
713 renderTo: Ext.getBody(),
714 width: 400, height: 300,
735 * @cfg {String} ctCls
736 * <p>An optional extra CSS class that will be added to this component's container. This can be useful for
737 * adding customized styles to the container or any of its children using standard CSS rules. See
738 * {@link Ext.layout.ContainerLayout}.{@link Ext.layout.ContainerLayout#extraCls extraCls} also.</p>
739 * <p><b>Note</b>: <tt>ctCls</tt> defaults to <tt>''</tt> except for the following class
740 * which assigns a value by default:
741 * <div class="mdetail-params"><ul>
742 * <li>{@link Ext.layout.Box Box Layout} : <tt>'x-box-layout-ct'</tt></li>
744 * To configure the above Class with an extra CSS class append to the default. For example,
745 * for BoxLayout (Hbox and Vbox):<pre><code>
746 * ctCls: 'x-box-layout-ct custom-class'
751 * @cfg {Boolean} disabled
752 * Render this component disabled (default is false).
756 * @cfg {Boolean} hidden
757 * Render this component hidden (default is false). If <tt>true</tt>, the
758 * {@link #hide} method will be called internally.
762 * @cfg {Object/Array} plugins
763 * An object or array of objects that will provide custom functionality for this component. The only
764 * requirement for a valid plugin is that it contain an init method that accepts a reference of type Ext.Component.
765 * When a component is created, if any plugins are available, the component will call the init method on each
766 * plugin, passing a reference to itself. Each plugin can then call methods or respond to events on the
767 * component as needed to provide its functionality.
770 * @cfg {Mixed} applyTo
771 * <p>Specify the id of the element, a DOM element or an existing Element corresponding to a DIV
772 * that is already present in the document that specifies some structural markup for this
773 * component.</p><div><ul>
774 * <li><b>Description</b> : <ul>
775 * <div class="sub-desc">When <tt>applyTo</tt> is used, constituent parts of the component can also be specified
776 * by id or CSS class name within the main element, and the component being created may attempt
777 * to create its subcomponents from that markup if applicable.</div>
779 * <li><b>Notes</b> : <ul>
780 * <div class="sub-desc">When using this config, a call to render() is not required.</div>
781 * <div class="sub-desc">If applyTo is specified, any value passed for {@link #renderTo} will be ignored and the target
782 * element's parent node will automatically be used as the component's container.</div>
787 * @cfg {Mixed} renderTo
788 * <p>Specify the id of the element, a DOM element or an existing Element that this component
789 * will be rendered into.</p><div><ul>
790 * <li><b>Notes</b> : <ul>
791 * <div class="sub-desc">Do <u>not</u> use this option if the Component is to be a child item of
792 * a {@link Ext.Container Container}. It is the responsibility of the
793 * {@link Ext.Container Container}'s {@link Ext.Container#layout layout manager}
794 * to render and manage its child items.</div>
795 * <div class="sub-desc">When using this config, a call to render() is not required.</div>
798 * <p>See <tt>{@link #render}</tt> also.</p>
801 * @cfg {Boolean} stateful
802 * <p>A flag which causes the Component to attempt to restore the state of
803 * internal properties from a saved state on startup. The component must have
804 * either a <code>{@link #stateId}</code> or <code>{@link #id}</code> assigned
805 * for state to be managed. Auto-generated ids are not guaranteed to be stable
806 * across page loads and cannot be relied upon to save and restore the same
807 * state for a component.<p>
808 * <p>For state saving to work, the state manager's provider must have been
809 * set to an implementation of {@link Ext.state.Provider} which overrides the
810 * {@link Ext.state.Provider#set set} and {@link Ext.state.Provider#get get}
811 * methods to save and recall name/value pairs. A built-in implementation,
812 * {@link Ext.state.CookieProvider} is available.</p>
813 * <p>To set the state provider for the current page:</p>
815 Ext.state.Manager.setProvider(new Ext.state.CookieProvider({
816 expires: new Date(new Date().getTime()+(1000*60*60*24*7)), //7 days from now
819 * <p>A stateful Component attempts to save state when one of the events
820 * listed in the <code>{@link #stateEvents}</code> configuration fires.</p>
821 * <p>To save state, a stateful Component first serializes its state by
822 * calling <b><code>getState</code></b>. By default, this function does
823 * nothing. The developer must provide an implementation which returns an
824 * object hash which represents the Component's restorable state.</p>
825 * <p>The value yielded by getState is passed to {@link Ext.state.Manager#set}
826 * which uses the configured {@link Ext.state.Provider} to save the object
827 * keyed by the Component's <code>{@link stateId}</code>, or, if that is not
828 * specified, its <code>{@link #id}</code>.</p>
829 * <p>During construction, a stateful Component attempts to <i>restore</i>
830 * its state by calling {@link Ext.state.Manager#get} passing the
831 * <code>{@link #stateId}</code>, or, if that is not specified, the
832 * <code>{@link #id}</code>.</p>
833 * <p>The resulting object is passed to <b><code>applyState</code></b>.
834 * The default implementation of <code>applyState</code> simply copies
835 * properties into the object, but a developer may override this to support
836 * more behaviour.</p>
837 * <p>You can perform extra processing on state save and restore by attaching
838 * handlers to the {@link #beforestaterestore}, {@link #staterestore},
839 * {@link #beforestatesave} and {@link #statesave} events.</p>
842 * @cfg {String} stateId
843 * The unique id for this component to use for state management purposes
844 * (defaults to the component id if one was set, otherwise null if the
845 * component is using a generated id).
846 * <p>See <code>{@link #stateful}</code> for an explanation of saving and
847 * restoring Component state.</p>
850 * @cfg {Array} stateEvents
851 * <p>An array of events that, when fired, should trigger this component to
852 * save its state (defaults to none). <code>stateEvents</code> may be any type
853 * of event supported by this component, including browser or custom events
854 * (e.g., <tt>['click', 'customerchange']</tt>).</p>
855 * <p>See <code>{@link #stateful}</code> for an explanation of saving and
856 * restoring Component state.</p>
859 * @cfg {Mixed} autoEl
860 * <p>A tag name or {@link Ext.DomHelper DomHelper} spec used to create the {@link #getEl Element} which will
861 * encapsulate this Component.</p>
862 * <p>You do not normally need to specify this. For the base classes {@link Ext.Component}, {@link Ext.BoxComponent},
863 * and {@link Ext.Container}, this defaults to <b><tt>'div'</tt></b>. The more complex Ext classes use a more complex
864 * DOM structure created by their own onRender methods.</p>
865 * <p>This is intended to allow the developer to create application-specific utility Components encapsulated by
866 * different DOM elements. Example usage:</p><pre><code>
871 src: 'http://www.example.com/example.jpg'
877 html: 'autoEl is cool!'
882 cls: 'ux-unordered-list',
886 html: 'First list item'
894 * @cfg {String} disabledClass
895 * CSS class added to the component when it is disabled (defaults to 'x-item-disabled').
897 disabledClass : 'x-item-disabled',
899 * @cfg {Boolean} allowDomMove
900 * Whether the component can move the Dom node when rendering (defaults to true).
904 * @cfg {Boolean} autoShow
905 * True if the component should check for hidden classes (e.g. 'x-hidden' or 'x-hide-display') and remove
906 * them on render (defaults to false).
910 * @cfg {String} hideMode
911 * <p>How this component should be hidden. Supported values are <tt>'visibility'</tt>
912 * (css visibility), <tt>'offsets'</tt> (negative offset position) and <tt>'display'</tt>
914 * <br><p><b>Note</b>: the default of <tt>'display'</tt> is generally preferred
915 * since items are automatically laid out when they are first shown (no sizing
916 * is done while hidden).</p>
918 hideMode : 'display',
920 * @cfg {Boolean} hideParent
921 * True to hide and show the component's container when hide/show is called on the component, false to hide
922 * and show the component itself (defaults to false). For example, this can be used as a shortcut for a hide
923 * button on a window by setting hide:true on the button when adding it to its parent container.
927 * <p>The {@link Ext.Element} which encapsulates this Component. Read-only.</p>
928 * <p>This will <i>usually</i> be a <DIV> element created by the class's onRender method, but
929 * that may be overridden using the <code>{@link #autoEl}</code> config.</p>
930 * <br><p><b>Note</b>: this element will not be available until this Component has been rendered.</p><br>
931 * <p>To add listeners for <b>DOM events</b> to this Component (as opposed to listeners
932 * for this Component's own Observable events), see the {@link Ext.util.Observable#listeners listeners}
933 * config for a suggestion, or use a render listener directly:</p><pre><code>
935 title: 'The Clickable Panel',
937 render: function(p) {
938 // Append the Panel to the click handler's argument list.
939 p.getEl().on('click', handlePanelClick.createDelegate(null, [p], true));
941 single: true // Remove the listener after first invocation
945 * <p>See also <tt>{@link #getEl getEl}</p>
950 * This Component's owner {@link Ext.Container Container} (defaults to undefined, and is set automatically when
951 * this Component is added to a Container). Read-only.
952 * <p><b>Note</b>: to access items within the Container see <tt>{@link #itemId}</tt>.</p>
953 * @type Ext.Container
957 * True if this component is hidden. Read-only.
962 * True if this component is disabled. Read-only.
967 * True if this component has been rendered. Read-only.
974 * @cfg {String} contentEl
975 * <p>Optional. Specify an existing HTML element, or the <code>id</code> of an existing HTML element to use as the content
976 * for this component.</p>
978 * <li><b>Description</b> :
979 * <div class="sub-desc">This config option is used to take an existing HTML element and place it in the layout element
980 * 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>
982 * <div class="sub-desc">The specified HTML element is appended to the layout element of the component <i>after any configured
983 * {@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>
984 * <div class="sub-desc">The specified HTML element used will not participate in any <code><b>{@link Ext.Container#layout layout}</b></code>
985 * scheme that the Component may use. It is just HTML. Layouts operate on child <code><b>{@link Ext.Container#items items}</b></code>.</div>
986 * <div class="sub-desc">Add either the <code>x-hidden</code> or the <code>x-hide-display</code> CSS class to
987 * prevent a brief flicker of the content before it is rendered to the panel.</div></li>
991 * @cfg {String/Object} html
992 * An HTML fragment, or a {@link Ext.DomHelper DomHelper} specification to use as the layout element
993 * content (defaults to ''). The HTML content is added after the component is rendered,
994 * so the document will not contain this HTML at the time the {@link #render} event is fired.
995 * This content is inserted into the body <i>before</i> any configured {@link #contentEl} is appended.
1000 * An <bold>{@link Ext.Template}</bold>, <bold>{@link Ext.XTemplate}</bold>
1001 * or an array of strings to form an Ext.XTemplate.
1002 * Used in conjunction with the <code>{@link #data}</code> and
1003 * <code>{@link #tplWriteMode}</code> configurations.
1007 * @cfg {String} tplWriteMode The Ext.(X)Template method to use when
1008 * updating the content area of the Component. Defaults to <tt>'overwrite'</tt>
1009 * (see <code>{@link Ext.XTemplate#overwrite}</code>).
1011 tplWriteMode : 'overwrite',
1015 * The initial set of data to apply to the <code>{@link #tpl}</code> to
1016 * update the content area of the Component.
1021 ctype : 'Ext.Component',
1027 getActionEl : function(){
1028 return this[this.actionMode];
1031 initPlugin : function(p){
1032 if(p.ptype && !Ext.isFunction(p.init)){
1033 p = Ext.ComponentMgr.createPlugin(p);
1034 }else if(Ext.isString(p)){
1035 p = Ext.ComponentMgr.createPlugin({
1044 * Function to be implemented by Component subclasses to be part of standard component initialization flow (it is empty by default).
1046 // Traditional constructor:
1047 Ext.Foo = function(config){
1048 // call superclass constructor:
1049 Ext.Foo.superclass.constructor.call(this, config);
1055 Ext.extend(Ext.Foo, Ext.Bar, {
1059 // initComponent replaces the constructor:
1060 Ext.Foo = Ext.extend(Ext.Bar, {
1061 initComponent : function(){
1062 // call superclass initComponent
1063 Ext.Container.superclass.initComponent.call(this);
1072 initComponent : Ext.emptyFn,
1075 * <p>Render this Component into the passed HTML element.</p>
1076 * <p><b>If you are using a {@link Ext.Container Container} object to house this Component, then
1077 * do not use the render method.</b></p>
1078 * <p>A Container's child Components are rendered by that Container's
1079 * {@link Ext.Container#layout layout} manager when the Container is first rendered.</p>
1080 * <p>Certain layout managers allow dynamic addition of child components. Those that do
1081 * include {@link Ext.layout.CardLayout}, {@link Ext.layout.AnchorLayout},
1082 * {@link Ext.layout.FormLayout}, {@link Ext.layout.TableLayout}.</p>
1083 * <p>If the Container is already rendered when a new child Component is added, you may need to call
1084 * the Container's {@link Ext.Container#doLayout doLayout} to refresh the view which causes any
1085 * unrendered child Components to be rendered. This is required so that you can add multiple
1086 * child components if needed while only refreshing the layout once.</p>
1087 * <p>When creating complex UIs, it is important to remember that sizing and positioning
1088 * of child items is the responsibility of the Container's {@link Ext.Container#layout layout} manager.
1089 * If you expect child items to be sized in response to user interactions, you must
1090 * configure the Container with a layout manager which creates and manages the type of layout you
1092 * <p><b>Omitting the Container's {@link Ext.Container#layout layout} config means that a basic
1093 * layout manager is used which does nothing but render child components sequentially into the
1094 * Container. No sizing or positioning will be performed in this situation.</b></p>
1095 * @param {Element/HTMLElement/String} container (optional) The element this Component should be
1096 * rendered into. If it is being created from existing markup, this should be omitted.
1097 * @param {String/Number} position (optional) The element ID or DOM node index within the container <b>before</b>
1098 * which this component will be inserted (defaults to appending to the end of the container)
1100 render : function(container, position){
1101 if(!this.rendered && this.fireEvent('beforerender', this) !== false){
1102 if(!container && this.el){
1103 this.el = Ext.get(this.el);
1104 container = this.el.dom.parentNode;
1105 this.allowDomMove = false;
1107 this.container = Ext.get(container);
1109 this.container.addClass(this.ctCls);
1111 this.rendered = true;
1112 if(position !== undefined){
1113 if(Ext.isNumber(position)){
1114 position = this.container.dom.childNodes[position];
1116 position = Ext.getDom(position);
1119 this.onRender(this.container, position || null);
1121 this.el.removeClass(['x-hidden','x-hide-' + this.hideMode]);
1124 this.el.addClass(this.cls);
1128 this.el.applyStyles(this.style);
1132 this.el.addClassOnOver(this.overCls);
1134 this.fireEvent('render', this);
1137 // Populate content of the component with html, contentEl or
1139 var contentTarget = this.getContentTarget();
1141 contentTarget.update(Ext.DomHelper.markup(this.html));
1144 if (this.contentEl){
1145 var ce = Ext.getDom(this.contentEl);
1146 Ext.fly(ce).removeClass(['x-hidden', 'x-hide-display']);
1147 contentTarget.appendChild(ce);
1150 if (!this.tpl.compile) {
1151 this.tpl = new Ext.XTemplate(this.tpl);
1154 this.tpl[this.tplWriteMode](contentTarget, this.data);
1158 this.afterRender(this.container);
1162 // call this so we don't fire initial hide events.
1166 // pass silent so the event doesn't fire the first time.
1170 if(this.stateful !== false){
1171 this.initStateEvents();
1173 this.fireEvent('afterrender', this);
1180 * Update the content area of a component.
1181 * @param {Mixed} htmlOrData
1182 * If this component has been configured with a template via the tpl config
1183 * then it will use this argument as data to populate the template.
1184 * If this component was not configured with a template, the components
1185 * content area will be updated via Ext.Element update
1186 * @param {Boolean} loadScripts
1187 * (optional) Only legitimate when using the html configuration. Defaults to false
1188 * @param {Function} callback
1189 * (optional) Only legitimate when using the html configuration. Callback to execute when scripts have finished loading
1191 update: function(htmlOrData, loadScripts, cb) {
1192 var contentTarget = this.getContentTarget();
1193 if (this.tpl && typeof htmlOrData !== "string") {
1194 this.tpl[this.tplWriteMode](contentTarget, htmlOrData || {});
1196 var html = Ext.isObject(htmlOrData) ? Ext.DomHelper.markup(htmlOrData) : htmlOrData;
1197 contentTarget.update(html, loadScripts, cb);
1204 * Method to manage awareness of when components are added to their
1205 * respective Container, firing an added event.
1206 * References are established at add time rather than at render time.
1207 * @param {Ext.Container} container Container which holds the component
1208 * @param {number} pos Position at which the component was added
1210 onAdded : function(container, pos) {
1211 this.ownerCt = container;
1213 this.fireEvent('added', this, container, pos);
1218 * Method to manage awareness of when components are removed from their
1219 * respective Container, firing an removed event. References are properly
1220 * cleaned up after removing a component from its owning container.
1222 onRemoved : function() {
1224 this.fireEvent('removed', this, this.ownerCt);
1225 delete this.ownerCt;
1230 * Method to establish a reference to a component.
1232 initRef : function() {
1235 * <p>A path specification, relative to the Component's <code>{@link #ownerCt}</code>
1236 * specifying into which ancestor Container to place a named reference to this Component.</p>
1237 * <p>The ancestor axis can be traversed by using '/' characters in the path.
1238 * For example, to put a reference to a Toolbar Button into <i>the Panel which owns the Toolbar</i>:</p><pre><code>
1239 var myGrid = new Ext.grid.EditorGridPanel({
1240 title: 'My EditorGridPanel',
1242 colModel: myColModel,
1245 handler: saveChanges,
1247 ref: '../saveButton'
1250 afteredit: function() {
1251 // The button reference is in the GridPanel
1252 myGrid.saveButton.enable();
1257 * <p>In the code above, if the <code>ref</code> had been <code>'saveButton'</code>
1258 * the reference would have been placed into the Toolbar. Each '/' in the <code>ref</code>
1259 * moves up one level from the Component's <code>{@link #ownerCt}</code>.</p>
1260 * <p>Also see the <code>{@link #added}</code> and <code>{@link #removed}</code> events.</p>
1262 if(this.ref && !this.refOwner){
1263 var levels = this.ref.split('/'),
1264 last = levels.length,
1268 while(t && i < last){
1273 t[this.refName = levels[--i]] = this;
1275 * @type Ext.Container
1276 * @property refOwner
1277 * The ancestor Container into which the {@link #ref} reference was inserted if this Component
1278 * is a child of a Container, and has been configured with a <code>ref</code>.
1285 removeRef : function() {
1286 if (this.refOwner && this.refName) {
1287 delete this.refOwner[this.refName];
1288 delete this.refOwner;
1293 initState : function(){
1294 if(Ext.state.Manager){
1295 var id = this.getStateId();
1297 var state = Ext.state.Manager.get(id);
1299 if(this.fireEvent('beforestaterestore', this, state) !== false){
1300 this.applyState(Ext.apply({}, state));
1301 this.fireEvent('staterestore', this, state);
1309 getStateId : function(){
1310 return this.stateId || ((this.id.indexOf('ext-comp-') == 0 || this.id.indexOf('ext-gen') == 0) ? null : this.id);
1314 initStateEvents : function(){
1315 if(this.stateEvents){
1316 for(var i = 0, e; e = this.stateEvents[i]; i++){
1317 this.on(e, this.saveState, this, {delay:100});
1323 applyState : function(state){
1325 Ext.apply(this, state);
1330 getState : function(){
1335 saveState : function(){
1336 if(Ext.state.Manager && this.stateful !== false){
1337 var id = this.getStateId();
1339 var state = this.getState();
1340 if(this.fireEvent('beforestatesave', this, state) !== false){
1341 Ext.state.Manager.set(id, state);
1342 this.fireEvent('statesave', this, state);
1349 * Apply this component to existing markup that is valid. With this function, no call to render() is required.
1350 * @param {String/HTMLElement} el
1352 applyToMarkup : function(el){
1353 this.allowDomMove = false;
1354 this.el = Ext.get(el);
1355 this.render(this.el.dom.parentNode);
1359 * Adds a CSS class to the component's underlying element.
1360 * @param {string} cls The CSS class name to add
1361 * @return {Ext.Component} this
1363 addClass : function(cls){
1365 this.el.addClass(cls);
1367 this.cls = this.cls ? this.cls + ' ' + cls : cls;
1373 * Removes a CSS class from the component's underlying element.
1374 * @param {string} cls The CSS class name to remove
1375 * @return {Ext.Component} this
1377 removeClass : function(cls){
1379 this.el.removeClass(cls);
1381 this.cls = this.cls.split(' ').remove(cls).join(' ');
1387 // default function is not really useful
1388 onRender : function(ct, position){
1389 if(!this.el && this.autoEl){
1390 if(Ext.isString(this.autoEl)){
1391 this.el = document.createElement(this.autoEl);
1393 var div = document.createElement('div');
1394 Ext.DomHelper.overwrite(div, this.autoEl);
1395 this.el = div.firstChild;
1398 this.el.id = this.getId();
1402 this.el = Ext.get(this.el);
1403 if(this.allowDomMove !== false){
1404 ct.dom.insertBefore(this.el.dom, position);
1406 Ext.removeNode(div);
1414 getAutoCreate : function(){
1415 var cfg = Ext.isObject(this.autoCreate) ?
1416 this.autoCreate : Ext.apply({}, this.defaultAutoCreate);
1417 if(this.id && !cfg.id){
1424 afterRender : Ext.emptyFn,
1427 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
1428 * removing the component from its {@link Ext.Container} (if applicable) and unregistering it from
1429 * {@link Ext.ComponentMgr}. Destruction is generally handled automatically by the framework and this method
1430 * should usually not need to be called directly.
1433 destroy : function(){
1434 if(!this.isDestroyed){
1435 if(this.fireEvent('beforedestroy', this) !== false){
1436 this.destroying = true;
1437 this.beforeDestroy();
1438 if(this.ownerCt && this.ownerCt.remove){
1439 this.ownerCt.remove(this, false);
1443 if(this.actionMode == 'container' || this.removeMode == 'container'){
1444 this.container.remove();
1448 Ext.ComponentMgr.unregister(this);
1449 this.fireEvent('destroy', this);
1450 this.purgeListeners();
1451 this.destroying = false;
1452 this.isDestroyed = true;
1457 deleteMembers : function(){
1458 var args = arguments;
1459 for(var i = 0, len = args.length; i < len; ++i){
1460 delete this[args[i]];
1465 beforeDestroy : Ext.emptyFn,
1468 onDestroy : Ext.emptyFn,
1471 * <p>Returns the {@link Ext.Element} which encapsulates this Component.</p>
1472 * <p>This will <i>usually</i> be a <DIV> element created by the class's onRender method, but
1473 * that may be overridden using the {@link #autoEl} config.</p>
1474 * <br><p><b>Note</b>: this element will not be available until this Component has been rendered.</p><br>
1475 * <p>To add listeners for <b>DOM events</b> to this Component (as opposed to listeners
1476 * for this Component's own Observable events), see the {@link #listeners} config for a suggestion,
1477 * or use a render listener directly:</p><pre><code>
1479 title: 'The Clickable Panel',
1481 render: function(p) {
1482 // Append the Panel to the click handler's argument list.
1483 p.getEl().on('click', handlePanelClick.createDelegate(null, [p], true));
1485 single: true // Remove the listener after first invocation
1489 * @return {Ext.Element} The Element which encapsulates this Component.
1496 getContentTarget : function(){
1501 * Returns the <code>id</code> of this component or automatically generates and
1502 * returns an <code>id</code> if an <code>id</code> is not defined yet:<pre><code>
1503 * 'ext-comp-' + (++Ext.Component.AUTO_ID)
1505 * @return {String} id
1508 return this.id || (this.id = 'ext-comp-' + (++Ext.Component.AUTO_ID));
1512 * Returns the <code>{@link #itemId}</code> of this component. If an
1513 * <code>{@link #itemId}</code> was not assigned through configuration the
1514 * <code>id</code> is returned using <code>{@link #getId}</code>.
1517 getItemId : function(){
1518 return this.itemId || this.getId();
1522 * Try to focus this component.
1523 * @param {Boolean} selectText (optional) If applicable, true to also select the text in this component
1524 * @param {Boolean/Number} delay (optional) Delay the focus this number of milliseconds (true for 10 milliseconds)
1525 * @return {Ext.Component} this
1527 focus : function(selectText, delay){
1529 this.focus.defer(Ext.isNumber(delay) ? delay : 10, this, [selectText, false]);
1534 if(selectText === true){
1535 this.el.dom.select();
1550 * Disable this component and fire the 'disable' event.
1551 * @return {Ext.Component} this
1553 disable : function(/* private */ silent){
1557 this.disabled = true;
1558 if(silent !== true){
1559 this.fireEvent('disable', this);
1565 onDisable : function(){
1566 this.getActionEl().addClass(this.disabledClass);
1567 this.el.dom.disabled = true;
1571 * Enable this component and fire the 'enable' event.
1572 * @return {Ext.Component} this
1574 enable : function(){
1578 this.disabled = false;
1579 this.fireEvent('enable', this);
1584 onEnable : function(){
1585 this.getActionEl().removeClass(this.disabledClass);
1586 this.el.dom.disabled = false;
1590 * Convenience function for setting disabled/enabled by boolean.
1591 * @param {Boolean} disabled
1592 * @return {Ext.Component} this
1594 setDisabled : function(disabled){
1595 return this[disabled ? 'disable' : 'enable']();
1599 * Show this component. Listen to the '{@link #beforeshow}' event and return
1600 * <tt>false</tt> to cancel showing the component. Fires the '{@link #show}'
1601 * event after showing the component.
1602 * @return {Ext.Component} this
1605 if(this.fireEvent('beforeshow', this) !== false){
1606 this.hidden = false;
1607 if(this.autoRender){
1608 this.render(Ext.isBoolean(this.autoRender) ? Ext.getBody() : this.autoRender);
1613 this.fireEvent('show', this);
1619 onShow : function(){
1620 this.getVisibilityEl().removeClass('x-hide-' + this.hideMode);
1624 * Hide this component. Listen to the '{@link #beforehide}' event and return
1625 * <tt>false</tt> to cancel hiding the component. Fires the '{@link #hide}'
1626 * event after hiding the component. Note this method is called internally if
1627 * the component is configured to be <code>{@link #hidden}</code>.
1628 * @return {Ext.Component} this
1631 if(this.fireEvent('beforehide', this) !== false){
1633 this.fireEvent('hide', this);
1647 onHide : function(){
1648 this.getVisibilityEl().addClass('x-hide-' + this.hideMode);
1652 getVisibilityEl : function(){
1653 return this.hideParent ? this.container : this.getActionEl();
1657 * Convenience function to hide or show this component by boolean.
1658 * @param {Boolean} visible True to show, false to hide
1659 * @return {Ext.Component} this
1661 setVisible : function(visible){
1662 return this[visible ? 'show' : 'hide']();
1666 * Returns true if this component is visible.
1667 * @return {Boolean} True if this component is visible, false otherwise.
1669 isVisible : function(){
1670 return this.rendered && this.getVisibilityEl().isVisible();
1674 * Clone the current component using the original config values passed into this instance by default.
1675 * @param {Object} overrides A new config containing any properties to override in the cloned version.
1676 * An id property can be passed on this object, otherwise one will be generated to avoid duplicates.
1677 * @return {Ext.Component} clone The cloned copy of this component
1679 cloneConfig : function(overrides){
1680 overrides = overrides || {};
1681 var id = overrides.id || Ext.id();
1682 var cfg = Ext.applyIf(overrides, this.initialConfig);
1683 cfg.id = id; // prevent dup id
1684 return new this.constructor(cfg);
1688 * Gets the xtype for this component as registered with {@link Ext.ComponentMgr}. For a list of all
1689 * available xtypes, see the {@link Ext.Component} header. Example usage:
1691 var t = new Ext.form.TextField();
1692 alert(t.getXType()); // alerts 'textfield'
1694 * @return {String} The xtype
1696 getXType : function(){
1697 return this.constructor.xtype;
1701 * <p>Tests whether or not this Component is of a specific xtype. This can test whether this Component is descended
1702 * from the xtype (default) or whether it is directly of the xtype specified (shallow = true).</p>
1703 * <p><b>If using your own subclasses, be aware that a Component must register its own xtype
1704 * to participate in determination of inherited xtypes.</b></p>
1705 * <p>For a list of all available xtypes, see the {@link Ext.Component} header.</p>
1706 * <p>Example usage:</p>
1708 var t = new Ext.form.TextField();
1709 var isText = t.isXType('textfield'); // true
1710 var isBoxSubclass = t.isXType('box'); // true, descended from BoxComponent
1711 var isBoxInstance = t.isXType('box', true); // false, not a direct BoxComponent instance
1713 * @param {String} xtype The xtype to check for this Component
1714 * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
1715 * the default), or true to check whether this Component is directly of the specified xtype.
1716 * @return {Boolean} True if this component descends from the specified xtype, false otherwise.
1718 isXType : function(xtype, shallow){
1719 //assume a string by default
1720 if (Ext.isFunction(xtype)){
1721 xtype = xtype.xtype; //handle being passed the class, e.g. Ext.Component
1722 }else if (Ext.isObject(xtype)){
1723 xtype = xtype.constructor.xtype; //handle being passed an instance
1726 return !shallow ? ('/' + this.getXTypes() + '/').indexOf('/' + xtype + '/') != -1 : this.constructor.xtype == xtype;
1730 * <p>Returns this Component's xtype hierarchy as a slash-delimited string. For a list of all
1731 * available xtypes, see the {@link Ext.Component} header.</p>
1732 * <p><b>If using your own subclasses, be aware that a Component must register its own xtype
1733 * to participate in determination of inherited xtypes.</b></p>
1734 * <p>Example usage:</p>
1736 var t = new Ext.form.TextField();
1737 alert(t.getXTypes()); // alerts 'component/box/field/textfield'
1739 * @return {String} The xtype hierarchy string
1741 getXTypes : function(){
1742 var tc = this.constructor;
1744 var c = [], sc = this;
1745 while(sc && sc.constructor.xtype){
1746 c.unshift(sc.constructor.xtype);
1747 sc = sc.constructor.superclass;
1750 tc.xtypes = c.join('/');
1756 * Find a container above this component at any level by a custom function. If the passed function returns
1757 * true, the container will be returned.
1758 * @param {Function} fn The custom function to call with the arguments (container, this component).
1759 * @return {Ext.Container} The first Container for which the custom function returns true
1761 findParentBy : function(fn) {
1762 for (var p = this.ownerCt; (p != null) && !fn(p, this); p = p.ownerCt);
1767 * Find a container above this component at any level by xtype or class
1768 * @param {String/Class} xtype The xtype string for a component, or the class of the component directly
1769 * @return {Ext.Container} The first Container which matches the given xtype or class
1771 findParentByType : function(xtype) {
1772 return Ext.isFunction(xtype) ?
1773 this.findParentBy(function(p){
1774 return p.constructor === xtype;
1776 this.findParentBy(function(p){
1777 return p.constructor.xtype === xtype;
1782 getPositionEl : function(){
1783 return this.positionEl || this.el;
1787 purgeListeners : function(){
1788 Ext.Component.superclass.purgeListeners.call(this);
1790 this.on('beforedestroy', this.clearMons, this, {single: true});
1795 clearMons : function(){
1796 Ext.each(this.mons, function(m){
1797 m.item.un(m.ename, m.fn, m.scope);
1803 createMons: function(){
1806 this.on('beforedestroy', this.clearMons, this, {single: true});
1811 * <p>Adds listeners to any Observable object (or Elements) which are automatically removed when this Component
1812 * is destroyed. Usage:</p><code><pre>
1813 myGridPanel.mon(myGridPanel.getSelectionModel(), 'selectionchange', handleSelectionChange, null, {buffer: 50});
1815 * <p>or:</p><code><pre>
1816 myGridPanel.mon(myGridPanel.getSelectionModel(), {
1817 selectionchange: handleSelectionChange,
1821 * @param {Observable|Element} item The item to which to add a listener/listeners.
1822 * @param {Object|String} ename The event name, or an object containing event name properties.
1823 * @param {Function} fn Optional. If the <code>ename</code> parameter was an event name, this
1824 * is the handler function.
1825 * @param {Object} scope Optional. If the <code>ename</code> parameter was an event name, this
1826 * is the scope (<code>this</code> reference) in which the handler function is executed.
1827 * @param {Object} opt Optional. If the <code>ename</code> parameter was an event name, this
1828 * is the {@link Ext.util.Observable#addListener addListener} options.
1830 mon : function(item, ename, fn, scope, opt){
1832 if(Ext.isObject(ename)){
1833 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
1840 if(Ext.isFunction(o[e])){
1843 item: item, ename: e, fn: o[e], scope: o.scope
1845 item.on(e, o[e], o.scope, o);
1847 // individual options
1849 item: item, ename: e, fn: o[e], scope: o.scope
1858 item: item, ename: ename, fn: fn, scope: scope
1860 item.on(ename, fn, scope, opt);
1864 * Removes listeners that were added by the {@link #mon} method.
1865 * @param {Observable|Element} item The item from which to remove a listener/listeners.
1866 * @param {Object|String} ename The event name, or an object containing event name properties.
1867 * @param {Function} fn Optional. If the <code>ename</code> parameter was an event name, this
1868 * is the handler function.
1869 * @param {Object} scope Optional. If the <code>ename</code> parameter was an event name, this
1870 * is the scope (<code>this</code> reference) in which the handler function is executed.
1872 mun : function(item, ename, fn, scope){
1875 for(var i = 0, len = this.mons.length; i < len; ++i){
1877 if(item === mon.item && ename == mon.ename && fn === mon.fn && scope === mon.scope){
1878 this.mons.splice(i, 1);
1879 item.un(ename, fn, scope);
1888 * Returns the next component in the owning container
1889 * @return Ext.Component
1891 nextSibling : function(){
1893 var index = this.ownerCt.items.indexOf(this);
1894 if(index != -1 && index+1 < this.ownerCt.items.getCount()){
1895 return this.ownerCt.items.itemAt(index+1);
1902 * Returns the previous component in the owning container
1903 * @return Ext.Component
1905 previousSibling : function(){
1907 var index = this.ownerCt.items.indexOf(this);
1909 return this.ownerCt.items.itemAt(index-1);
1916 * Provides the link for Observable's fireEvent method to bubble up the ownership hierarchy.
1917 * @return {Ext.Container} the Container which owns this Component.
1919 getBubbleTarget : function(){
1920 return this.ownerCt;
1924 Ext.reg('component', Ext.Component);/**
\r
1925 * @class Ext.Action
\r
1926 * <p>An Action is a piece of reusable functionality that can be abstracted out of any particular component so that it
\r
1927 * can be usefully shared among multiple components. Actions let you share handlers, configuration options and UI
\r
1928 * updates across any components that support the Action interface (primarily {@link Ext.Toolbar}, {@link Ext.Button}
\r
1929 * and {@link Ext.menu.Menu} components).</p>
\r
1930 * <p>Aside from supporting the config object interface, any component that needs to use Actions must also support
\r
1931 * the following method list, as these will be called as needed by the Action class: setText(string), setIconCls(string),
\r
1932 * setDisabled(boolean), setVisible(boolean) and setHandler(function).</p>
\r
1933 * Example usage:<br>
\r
1935 // Define the shared action. Each component below will have the same
\r
1936 // display text and icon, and will display the same message on click.
\r
1937 var action = new Ext.Action({
\r
1938 {@link #text}: 'Do something',
\r
1939 {@link #handler}: function(){
\r
1940 Ext.Msg.alert('Click', 'You did something.');
\r
1942 {@link #iconCls}: 'do-something',
\r
1943 {@link #itemId}: 'myAction'
\r
1946 var panel = new Ext.Panel({
\r
1951 // Add the action directly to a toolbar as a menu button
\r
1954 text: 'Action Menu',
\r
1955 // Add the action to a menu as a text item
\r
1960 // Add the action to the panel body as a standard button
\r
1961 new Ext.Button(action)
\r
1963 renderTo: Ext.getBody()
\r
1966 // Change the text for all components using the action
\r
1967 action.setText('Something else');
\r
1969 // Reference an action through a container using the itemId
\r
1970 var btn = panel.getComponent('myAction');
\r
1971 var aRef = btn.baseAction;
\r
1972 aRef.setText('New text');
\r
1975 * @param {Object} config The configuration options
\r
1977 Ext.Action = Ext.extend(Object, {
\r
1979 * @cfg {String} text The text to set for all components using this action (defaults to '').
\r
1982 * @cfg {String} iconCls
\r
1983 * The CSS class selector that specifies a background image to be used as the header icon for
\r
1984 * all components using this action (defaults to '').
\r
1985 * <p>An example of specifying a custom icon class would be something like:
\r
1987 // specify the property in the config for the class:
\r
1989 iconCls: 'do-something'
\r
1991 // css class that specifies background image to be used as the icon image:
\r
1992 .do-something { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
\r
1996 * @cfg {Boolean} disabled True to disable all components using this action, false to enable them (defaults to false).
\r
1999 * @cfg {Boolean} hidden True to hide all components using this action, false to show them (defaults to false).
\r
2002 * @cfg {Function} handler The function that will be invoked by each component tied to this action
\r
2003 * when the component's primary event is triggered (defaults to undefined).
\r
2006 * @cfg {String} itemId
\r
2007 * See {@link Ext.Component}.{@link Ext.Component#itemId itemId}.
\r
2010 * @cfg {Object} scope The scope (<tt><b>this</b></tt> reference) in which the
\r
2011 * <code>{@link #handler}</code> is executed. Defaults to this Button.
\r
2014 constructor : function(config){
\r
2015 this.initialConfig = config;
\r
2016 this.itemId = config.itemId = (config.itemId || config.id || Ext.id());
\r
2024 * Sets the text to be displayed by all components using this action.
\r
2025 * @param {String} text The text to display
\r
2027 setText : function(text){
\r
2028 this.initialConfig.text = text;
\r
2029 this.callEach('setText', [text]);
\r
2033 * Gets the text currently displayed by all components using this action.
\r
2035 getText : function(){
\r
2036 return this.initialConfig.text;
\r
2040 * Sets the icon CSS class for all components using this action. The class should supply
\r
2041 * a background image that will be used as the icon image.
\r
2042 * @param {String} cls The CSS class supplying the icon image
\r
2044 setIconClass : function(cls){
\r
2045 this.initialConfig.iconCls = cls;
\r
2046 this.callEach('setIconClass', [cls]);
\r
2050 * Gets the icon CSS class currently used by all components using this action.
\r
2052 getIconClass : function(){
\r
2053 return this.initialConfig.iconCls;
\r
2057 * Sets the disabled state of all components using this action. Shortcut method
\r
2058 * for {@link #enable} and {@link #disable}.
\r
2059 * @param {Boolean} disabled True to disable the component, false to enable it
\r
2061 setDisabled : function(v){
\r
2062 this.initialConfig.disabled = v;
\r
2063 this.callEach('setDisabled', [v]);
\r
2067 * Enables all components using this action.
\r
2069 enable : function(){
\r
2070 this.setDisabled(false);
\r
2074 * Disables all components using this action.
\r
2076 disable : function(){
\r
2077 this.setDisabled(true);
\r
2081 * Returns true if the components using this action are currently disabled, else returns false.
\r
2083 isDisabled : function(){
\r
2084 return this.initialConfig.disabled;
\r
2088 * Sets the hidden state of all components using this action. Shortcut method
\r
2089 * for <code>{@link #hide}</code> and <code>{@link #show}</code>.
\r
2090 * @param {Boolean} hidden True to hide the component, false to show it
\r
2092 setHidden : function(v){
\r
2093 this.initialConfig.hidden = v;
\r
2094 this.callEach('setVisible', [!v]);
\r
2098 * Shows all components using this action.
\r
2100 show : function(){
\r
2101 this.setHidden(false);
\r
2105 * Hides all components using this action.
\r
2107 hide : function(){
\r
2108 this.setHidden(true);
\r
2112 * Returns true if the components using this action are currently hidden, else returns false.
\r
2114 isHidden : function(){
\r
2115 return this.initialConfig.hidden;
\r
2119 * Sets the function that will be called by each Component using this action when its primary event is triggered.
\r
2120 * @param {Function} fn The function that will be invoked by the action's components. The function
\r
2121 * will be called with no arguments.
\r
2122 * @param {Object} scope The scope (<code>this</code> reference) in which the function is executed. Defaults to the Component firing the event.
\r
2124 setHandler : function(fn, scope){
\r
2125 this.initialConfig.handler = fn;
\r
2126 this.initialConfig.scope = scope;
\r
2127 this.callEach('setHandler', [fn, scope]);
\r
2131 * Executes the specified function once for each Component currently tied to this action. The function passed
\r
2132 * in should accept a single argument that will be an object that supports the basic Action config/method interface.
\r
2133 * @param {Function} fn The function to execute for each component
\r
2134 * @param {Object} scope The scope (<code>this</code> reference) in which the function is executed. Defaults to the Component.
\r
2136 each : function(fn, scope){
\r
2137 Ext.each(this.items, fn, scope);
\r
2141 callEach : function(fnName, args){
\r
2142 var cs = this.items;
\r
2143 for(var i = 0, len = cs.length; i < len; i++){
\r
2144 cs[i][fnName].apply(cs[i], args);
\r
2149 addComponent : function(comp){
\r
2150 this.items.push(comp);
\r
2151 comp.on('destroy', this.removeComponent, this);
\r
2155 removeComponent : function(comp){
\r
2156 this.items.remove(comp);
\r
2160 * Executes this action manually using the handler function specified in the original config object
\r
2161 * or the handler function set with <code>{@link #setHandler}</code>. Any arguments passed to this
\r
2162 * function will be passed on to the handler function.
\r
2163 * @param {Mixed} arg1 (optional) Variable number of arguments passed to the handler function
\r
2164 * @param {Mixed} arg2 (optional)
\r
2165 * @param {Mixed} etc... (optional)
\r
2167 execute : function(){
\r
2168 this.initialConfig.handler.apply(this.initialConfig.scope || window, arguments);
\r
2173 * @extends Ext.Element
2174 * An extended {@link Ext.Element} object that supports a shadow and shim, constrain to viewport and
2175 * automatic maintaining of shadow/shim positions.
2176 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
2177 * @cfg {String/Boolean} shadow True to automatically create an {@link Ext.Shadow}, or a string indicating the
2178 * shadow's display {@link Ext.Shadow#mode}. False to disable the shadow. (defaults to false)
2179 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: 'div', cls: 'x-layer'}).
2180 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
2181 * @cfg {String} cls CSS class to add to the element
2182 * @cfg {Number} zindex Starting z-index (defaults to 11000)
2183 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 4)
2184 * @cfg {Boolean} useDisplay
2185 * Defaults to use css offsets to hide the Layer. Specify <tt>true</tt>
2186 * to use css style <tt>'display:none;'</tt> to hide the Layer.
2188 * @param {Object} config An object with config options.
2189 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
2192 Ext.Layer = function(config, existingEl){
2193 config = config || {};
2194 var dh = Ext.DomHelper;
2195 var cp = config.parentEl, pel = cp ? Ext.getDom(cp) : document.body;
2197 this.dom = Ext.getDom(existingEl);
2200 var o = config.dh || {tag: 'div', cls: 'x-layer'};
2201 this.dom = dh.append(pel, o);
2204 this.addClass(config.cls);
2206 this.constrain = config.constrain !== false;
2207 this.setVisibilityMode(Ext.Element.VISIBILITY);
2209 this.id = this.dom.id = config.id;
2211 this.id = Ext.id(this.dom);
2213 this.zindex = config.zindex || this.getZIndex();
2214 this.position('absolute', this.zindex);
2216 this.shadowOffset = config.shadowOffset || 4;
2217 this.shadow = new Ext.Shadow({
2218 offset : this.shadowOffset,
2219 mode : config.shadow
2222 this.shadowOffset = 0;
2224 this.useShim = config.shim !== false && Ext.useShims;
2225 this.useDisplay = config.useDisplay;
2229 var supr = Ext.Element.prototype;
2231 // shims are shared among layer to keep from having 100 iframes
2234 Ext.extend(Ext.Layer, Ext.Element, {
2236 getZIndex : function(){
2237 return this.zindex || parseInt((this.getShim() || this).getStyle('z-index'), 10) || 11000;
2240 getShim : function(){
2247 var shim = shims.shift();
2249 shim = this.createShim();
2250 shim.enableDisplayMode('block');
2251 shim.dom.style.display = 'none';
2252 shim.dom.style.visibility = 'visible';
2254 var pn = this.dom.parentNode;
2255 if(shim.dom.parentNode != pn){
2256 pn.insertBefore(shim.dom, this.dom);
2258 shim.setStyle('z-index', this.getZIndex()-2);
2263 hideShim : function(){
2265 this.shim.setDisplayed(false);
2266 shims.push(this.shim);
2271 disableShadow : function(){
2273 this.shadowDisabled = true;
2275 this.lastShadowOffset = this.shadowOffset;
2276 this.shadowOffset = 0;
2280 enableShadow : function(show){
2282 this.shadowDisabled = false;
2283 this.shadowOffset = this.lastShadowOffset;
2284 delete this.lastShadowOffset;
2292 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
2293 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
2294 sync : function(doShow){
2295 var sw = this.shadow;
2296 if(!this.updating && this.isVisible() && (sw || this.useShim)){
2297 var sh = this.getShim();
2299 var w = this.getWidth(),
2300 h = this.getHeight();
2302 var l = this.getLeft(true),
2303 t = this.getTop(true);
2305 if(sw && !this.shadowDisabled){
2306 if(doShow && !sw.isVisible()){
2309 sw.realign(l, t, w, h);
2315 // fit the shim behind the shadow, so it is shimmed too
2316 var a = sw.adjusts, s = sh.dom.style;
2317 s.left = (Math.min(l, l+a.l))+'px';
2318 s.top = (Math.min(t, t+a.t))+'px';
2319 s.width = (w+a.w)+'px';
2320 s.height = (h+a.h)+'px';
2327 sh.setLeftTop(l, t);
2334 destroy : function(){
2339 this.removeAllListeners();
2340 Ext.removeNode(this.dom);
2344 remove : function(){
2349 beginUpdate : function(){
2350 this.updating = true;
2354 endUpdate : function(){
2355 this.updating = false;
2360 hideUnders : function(negOffset){
2368 constrainXY : function(){
2370 var vw = Ext.lib.Dom.getViewWidth(),
2371 vh = Ext.lib.Dom.getViewHeight();
2372 var s = Ext.getDoc().getScroll();
2374 var xy = this.getXY();
2375 var x = xy[0], y = xy[1];
2376 var so = this.shadowOffset;
2377 var w = this.dom.offsetWidth+so, h = this.dom.offsetHeight+so;
2378 // only move it if it needs it
2380 // first validate right/bottom
2381 if((x + w) > vw+s.left){
2385 if((y + h) > vh+s.top){
2389 // then make sure top/left isn't negative
2400 var ay = this.avoidY;
2401 if(y <= ay && (y+h) >= ay){
2407 supr.setXY.call(this, xy);
2414 isVisible : function(){
2415 return this.visible;
2419 showAction : function(){
2420 this.visible = true; // track visibility to prevent getStyle calls
2421 if(this.useDisplay === true){
2422 this.setDisplayed('');
2423 }else if(this.lastXY){
2424 supr.setXY.call(this, this.lastXY);
2425 }else if(this.lastLT){
2426 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
2431 hideAction : function(){
2432 this.visible = false;
2433 if(this.useDisplay === true){
2434 this.setDisplayed(false);
2436 this.setLeftTop(-10000,-10000);
2440 // overridden Element method
2441 setVisible : function(v, a, d, c, e){
2446 var cb = function(){
2451 }.createDelegate(this);
2452 supr.setVisible.call(this, true, true, d, cb, e);
2455 this.hideUnders(true);
2464 }.createDelegate(this);
2466 supr.setVisible.call(this, v, a, d, cb, e);
2476 storeXY : function(xy){
2481 storeLeftTop : function(left, top){
2483 this.lastLT = [left, top];
2487 beforeFx : function(){
2488 this.beforeAction();
2489 return Ext.Layer.superclass.beforeFx.apply(this, arguments);
2493 afterFx : function(){
2494 Ext.Layer.superclass.afterFx.apply(this, arguments);
2495 this.sync(this.isVisible());
2499 beforeAction : function(){
2500 if(!this.updating && this.shadow){
2505 // overridden Element method
2506 setLeft : function(left){
2507 this.storeLeftTop(left, this.getTop(true));
2508 supr.setLeft.apply(this, arguments);
2513 setTop : function(top){
2514 this.storeLeftTop(this.getLeft(true), top);
2515 supr.setTop.apply(this, arguments);
2520 setLeftTop : function(left, top){
2521 this.storeLeftTop(left, top);
2522 supr.setLeftTop.apply(this, arguments);
2527 setXY : function(xy, a, d, c, e){
2529 this.beforeAction();
2531 var cb = this.createCB(c);
2532 supr.setXY.call(this, xy, a, d, cb, e);
2540 createCB : function(c){
2551 // overridden Element method
2552 setX : function(x, a, d, c, e){
2553 this.setXY([x, this.getY()], a, d, c, e);
2557 // overridden Element method
2558 setY : function(y, a, d, c, e){
2559 this.setXY([this.getX(), y], a, d, c, e);
2563 // overridden Element method
2564 setSize : function(w, h, a, d, c, e){
2565 this.beforeAction();
2566 var cb = this.createCB(c);
2567 supr.setSize.call(this, w, h, a, d, cb, e);
2574 // overridden Element method
2575 setWidth : function(w, a, d, c, e){
2576 this.beforeAction();
2577 var cb = this.createCB(c);
2578 supr.setWidth.call(this, w, a, d, cb, e);
2585 // overridden Element method
2586 setHeight : function(h, a, d, c, e){
2587 this.beforeAction();
2588 var cb = this.createCB(c);
2589 supr.setHeight.call(this, h, a, d, cb, e);
2596 // overridden Element method
2597 setBounds : function(x, y, w, h, a, d, c, e){
2598 this.beforeAction();
2599 var cb = this.createCB(c);
2601 this.storeXY([x, y]);
2602 supr.setXY.call(this, [x, y]);
2603 supr.setSize.call(this, w, h, a, d, cb, e);
2606 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
2612 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
2613 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
2614 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
2615 * @param {Number} zindex The new z-index to set
2616 * @return {this} The Layer
2618 setZIndex : function(zindex){
2619 this.zindex = zindex;
2620 this.setStyle('z-index', zindex + 2);
2622 this.shadow.setZIndex(zindex + 1);
2625 this.shim.setStyle('z-index', zindex);
2633 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
2634 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
2635 * functionality that can also provide the same shadow effect, see the {@link Ext.Layer} class.
2637 * Create a new Shadow
2638 * @param {Object} config The config object
2640 Ext.Shadow = function(config){
2641 Ext.apply(this, config);
2642 if(typeof this.mode != "string"){
2643 this.mode = this.defaultMode;
2645 var o = this.offset, a = {h: 0};
2646 var rad = Math.floor(this.offset/2);
2647 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
2653 a.l -= this.offset + rad;
2654 a.t -= this.offset + rad;
2665 a.l -= (this.offset - rad);
2666 a.t -= this.offset + rad;
2668 a.w -= (this.offset - rad)*2;
2679 a.l -= (this.offset - rad);
2680 a.t -= (this.offset - rad);
2682 a.w -= (this.offset + rad + 1);
2683 a.h -= (this.offset + rad);
2692 Ext.Shadow.prototype = {
2694 * @cfg {String} mode
2695 * The shadow display mode. Supports the following options:<div class="mdetail-params"><ul>
2696 * <li><b><tt>sides</tt></b> : Shadow displays on both sides and bottom only</li>
2697 * <li><b><tt>frame</tt></b> : Shadow displays equally on all four sides</li>
2698 * <li><b><tt>drop</tt></b> : Traditional bottom-right drop shadow</li>
2702 * @cfg {String} offset
2703 * The number of pixels to offset the shadow from the element (defaults to <tt>4</tt>)
2708 defaultMode: "drop",
2711 * Displays the shadow under the target element
2712 * @param {Mixed} targetEl The id or element under which the shadow should display
2714 show : function(target){
2715 target = Ext.get(target);
2717 this.el = Ext.Shadow.Pool.pull();
2718 if(this.el.dom.nextSibling != target.dom){
2719 this.el.insertBefore(target);
2722 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
2724 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
2727 target.getLeft(true),
2728 target.getTop(true),
2732 this.el.dom.style.display = "block";
2736 * Returns true if the shadow is visible, else false
2738 isVisible : function(){
2739 return this.el ? true : false;
2743 * Direct alignment when values are already available. Show must be called at least once before
2744 * calling this method to ensure it is initialized.
2745 * @param {Number} left The target element left position
2746 * @param {Number} top The target element top position
2747 * @param {Number} width The target element width
2748 * @param {Number} height The target element height
2750 realign : function(l, t, w, h){
2754 var a = this.adjusts, d = this.el.dom, s = d.style;
2756 s.left = (l+a.l)+"px";
2757 s.top = (t+a.t)+"px";
2758 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
2759 if(s.width != sws || s.height != shs){
2763 var cn = d.childNodes;
2764 var sww = Math.max(0, (sw-12))+"px";
2765 cn[0].childNodes[1].style.width = sww;
2766 cn[1].childNodes[1].style.width = sww;
2767 cn[2].childNodes[1].style.width = sww;
2768 cn[1].style.height = Math.max(0, (sh-12))+"px";
2778 this.el.dom.style.display = "none";
2779 Ext.Shadow.Pool.push(this.el);
2785 * Adjust the z-index of this shadow
2786 * @param {Number} zindex The new z-index
2788 setZIndex : function(z){
2791 this.el.setStyle("z-index", z);
2796 // Private utility class that manages the internal Shadow cache
2797 Ext.Shadow.Pool = function(){
2799 var markup = Ext.isIE ?
2800 '<div class="x-ie-shadow"></div>' :
2801 '<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>';
2806 sh = Ext.get(Ext.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
2807 sh.autoBoxAdjust = false;
2812 push : function(sh){
2817 * @class Ext.BoxComponent
2818 * @extends Ext.Component
2819 * <p>Base class for any {@link Ext.Component Component} that is to be sized as a box, using width and height.</p>
2820 * <p>BoxComponent provides automatic box model adjustments for sizing and positioning and will work correctly
2821 * within the Component rendering model.</p>
2822 * <p>A BoxComponent may be created as a custom Component which encapsulates any HTML element, either a pre-existing
2823 * element, or one that is created to your specifications at render time. Usually, to participate in layouts,
2824 * a Component will need to be a <b>Box</b>Component in order to have its width and height managed.</p>
2825 * <p>To use a pre-existing element as a BoxComponent, configure it so that you preset the <b>el</b> property to the
2826 * element to reference:<pre><code>
2827 var pageHeader = new Ext.BoxComponent({
2830 * This may then be {@link Ext.Container#add added} to a {@link Ext.Container Container} as a child item.</p>
2831 * <p>To create a BoxComponent based around a HTML element to be created at render time, use the
2832 * {@link Ext.Component#autoEl autoEl} config option which takes the form of a
2833 * {@link Ext.DomHelper DomHelper} specification:<pre><code>
2834 var myImage = new Ext.BoxComponent({
2837 src: '/images/my-image.jpg'
2839 });</code></pre></p>
2841 * @param {Ext.Element/String/Object} config The configuration options.
2844 Ext.BoxComponent = Ext.extend(Ext.Component, {
2846 // tabTip config is used when a BoxComponent is a child of a TabPanel
2848 * @cfg {String} tabTip
2849 * <p><b>Note</b>: this config is only used when this BoxComponent is a child item of a TabPanel.</p>
2850 * A string to be used as innerHTML (html tags are accepted) to show in a tooltip when mousing over
2851 * the associated tab selector element. {@link Ext.QuickTips}.init()
2852 * must be called in order for the tips to render.
2854 // Configs below are used for all Components when rendered by BorderLayout.
2856 * @cfg {String} region <p><b>Note</b>: this config is only used when this BoxComponent is rendered
2857 * by a Container which has been configured to use the <b>{@link Ext.layout.BorderLayout BorderLayout}</b>
2858 * layout manager (e.g. specifying <tt>layout:'border'</tt>).</p><br>
2859 * <p>See {@link Ext.layout.BorderLayout} also.</p>
2861 // margins config is used when a BoxComponent is rendered by BorderLayout or BoxLayout.
2863 * @cfg {Object} margins <p><b>Note</b>: this config is only used when this BoxComponent is rendered
2864 * by a Container which has been configured to use the <b>{@link Ext.layout.BorderLayout BorderLayout}</b>
2865 * or one of the two <b>{@link Ext.layout.BoxLayout BoxLayout} subclasses.</b></p>
2866 * <p>An object containing margins to apply to this BoxComponent in the
2867 * format:</p><pre><code>
2870 right: (right margin),
2871 bottom: (bottom margin),
2874 * <p>May also be a string containing space-separated, numeric margin values. The order of the
2875 * sides associated with each value matches the way CSS processes margin values:</p>
2876 * <p><div class="mdetail-params"><ul>
2877 * <li>If there is only one value, it applies to all sides.</li>
2878 * <li>If there are two values, the top and bottom borders are set to the first value and the
2879 * right and left are set to the second.</li>
2880 * <li>If there are three values, the top is set to the first value, the left and right are set
2881 * to the second, and the bottom is set to the third.</li>
2882 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
2884 * <p>Defaults to:</p><pre><code>
2885 * {top:0, right:0, bottom:0, left:0}
2890 * The local x (left) coordinate for this component if contained within a positioning container.
2894 * The local y (top) coordinate for this component if contained within a positioning container.
2897 * @cfg {Number} pageX
2898 * The page level x coordinate for this component if contained within a positioning container.
2901 * @cfg {Number} pageY
2902 * The page level y coordinate for this component if contained within a positioning container.
2905 * @cfg {Number} height
2906 * The height of this component in pixels (defaults to auto).
2907 * <b>Note</b> to express this dimension as a percentage or offset see {@link Ext.Component#anchor}.
2910 * @cfg {Number} width
2911 * The width of this component in pixels (defaults to auto).
2912 * <b>Note</b> to express this dimension as a percentage or offset see {@link Ext.Component#anchor}.
2915 * @cfg {Number} boxMinHeight
2916 * <p>The minimum value in pixels which this BoxComponent will set its height to.</p>
2917 * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
2920 * @cfg {Number} boxMinWidth
2921 * <p>The minimum value in pixels which this BoxComponent will set its width to.</p>
2922 * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
2925 * @cfg {Number} boxMaxHeight
2926 * <p>The maximum value in pixels which this BoxComponent will set its height to.</p>
2927 * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
2930 * @cfg {Number} boxMaxWidth
2931 * <p>The maximum value in pixels which this BoxComponent will set its width to.</p>
2932 * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
2935 * @cfg {Boolean} autoHeight
2936 * <p>True to use height:'auto', false to use fixed height (or allow it to be managed by its parent
2937 * Container's {@link Ext.Container#layout layout manager}. Defaults to false.</p>
2938 * <p><b>Note</b>: Although many components inherit this config option, not all will
2939 * function as expected with a height of 'auto'. Setting autoHeight:true means that the
2940 * browser will manage height based on the element's contents, and that Ext will not manage it at all.</p>
2941 * <p>If the <i>browser</i> is managing the height, be aware that resizes performed by the browser in response
2942 * to changes within the structure of the Component cannot be detected. Therefore changes to the height might
2943 * result in elements needing to be synchronized with the new height. Example:</p><pre><code>
2944 var w = new Ext.Window({
2949 title: 'Collapse Me',
2954 beforecollapse: function() {
2957 beforeexpand: function() {
2960 collapse: function() {
2963 expand: function() {
2972 * @cfg {Boolean} autoWidth
2973 * <p>True to use width:'auto', false to use fixed width (or allow it to be managed by its parent
2974 * Container's {@link Ext.Container#layout layout manager}. Defaults to false.</p>
2975 * <p><b>Note</b>: Although many components inherit this config option, not all will
2976 * function as expected with a width of 'auto'. Setting autoWidth:true means that the
2977 * browser will manage width based on the element's contents, and that Ext will not manage it at all.</p>
2978 * <p>If the <i>browser</i> is managing the width, be aware that resizes performed by the browser in response
2979 * to changes within the structure of the Component cannot be detected. Therefore changes to the width might
2980 * result in elements needing to be synchronized with the new width. For example, where the target element is:</p><pre><code>
2981 <div id='grid-container' style='margin-left:25%;width:50%'></div>
2983 * A Panel rendered into that target element must listen for browser window resize in order to relay its
2984 * child items when the browser changes its width:<pre><code>
2985 var myPanel = new Ext.Panel({
2986 renderTo: 'grid-container',
2987 monitorResize: true, // relay on browser resize
3009 * @cfg {Boolean} autoScroll
3010 * <code>true</code> to use overflow:'auto' on the components layout element and show scroll bars automatically when
3011 * necessary, <code>false</code> to clip any overflowing content (defaults to <code>false</code>).
3014 /* // private internal config
3015 * {Boolean} deferHeight
3016 * True to defer height calculations to an external component, false to allow this component to set its own
3017 * height (defaults to false).
3021 initComponent : function(){
3022 Ext.BoxComponent.superclass.initComponent.call(this);
3026 * Fires after the component is resized.
3027 * @param {Ext.Component} this
3028 * @param {Number} adjWidth The box-adjusted width that was set
3029 * @param {Number} adjHeight The box-adjusted height that was set
3030 * @param {Number} rawWidth The width that was originally specified
3031 * @param {Number} rawHeight The height that was originally specified
3036 * Fires after the component is moved.
3037 * @param {Ext.Component} this
3038 * @param {Number} x The new x position
3039 * @param {Number} y The new y position
3045 // private, set in afterRender to signify that the component has been rendered
3047 // private, used to defer height settings to subclasses
3051 * Sets the width and height of this BoxComponent. This method fires the {@link #resize} event. This method can accept
3052 * either width and height as separate arguments, or you can pass a size object like <code>{width:10, height:20}</code>.
3053 * @param {Mixed} width The new width to set. This may be one of:<div class="mdetail-params"><ul>
3054 * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li>
3055 * <li>A String used to set the CSS width style.</li>
3056 * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>
3057 * <li><code>undefined</code> to leave the width unchanged.</li>
3059 * @param {Mixed} height The new height to set (not required if a size object is passed as the first arg).
3060 * This may be one of:<div class="mdetail-params"><ul>
3061 * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li>
3062 * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
3063 * <li><code>undefined</code> to leave the height unchanged.</li>
3065 * @return {Ext.BoxComponent} this
3067 setSize : function(w, h){
3069 // support for standard size objects
3070 if(typeof w == 'object'){
3071 h = w.height, w = w.width;
3073 if (Ext.isDefined(w) && Ext.isDefined(this.boxMinWidth) && (w < this.boxMinWidth)) {
3074 w = this.boxMinWidth;
3076 if (Ext.isDefined(h) && Ext.isDefined(this.boxMinHeight) && (h < this.boxMinHeight)) {
3077 h = this.boxMinHeight;
3079 if (Ext.isDefined(w) && Ext.isDefined(this.boxMaxWidth) && (w > this.boxMaxWidth)) {
3080 w = this.boxMaxWidth;
3082 if (Ext.isDefined(h) && Ext.isDefined(this.boxMaxHeight) && (h > this.boxMaxHeight)) {
3083 h = this.boxMaxHeight;
3087 this.width = w, this.height = h;
3091 // prevent recalcs when not needed
3092 if(this.cacheSizes !== false && this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
3095 this.lastSize = {width: w, height: h};
3096 var adj = this.adjustSize(w, h),
3100 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
3101 rz = this.getResizeEl();
3102 if(!this.deferHeight && aw !== undefined && ah !== undefined){
3104 }else if(!this.deferHeight && ah !== undefined){
3106 }else if(aw !== undefined){
3109 this.onResize(aw, ah, w, h);
3115 * Sets the width of the component. This method fires the {@link #resize} event.
3116 * @param {Number} width The new width to setThis may be one of:<div class="mdetail-params"><ul>
3117 * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li>
3118 * <li>A String used to set the CSS width style.</li>
3120 * @return {Ext.BoxComponent} this
3122 setWidth : function(width){
3123 return this.setSize(width);
3127 * Sets the height of the component. This method fires the {@link #resize} event.
3128 * @param {Number} height The new height to set. This may be one of:<div class="mdetail-params"><ul>
3129 * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li>
3130 * <li>A String used to set the CSS height style.</li>
3131 * <li><i>undefined</i> to leave the height unchanged.</li>
3133 * @return {Ext.BoxComponent} this
3135 setHeight : function(height){
3136 return this.setSize(undefined, height);
3140 * Gets the current size of the component's underlying element.
3141 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
3143 getSize : function(){
3144 return this.getResizeEl().getSize();
3148 * Gets the current width of the component's underlying element.
3151 getWidth : function(){
3152 return this.getResizeEl().getWidth();
3156 * Gets the current height of the component's underlying element.
3159 getHeight : function(){
3160 return this.getResizeEl().getHeight();
3164 * Gets the current size of the component's underlying element, including space taken by its margins.
3165 * @return {Object} An object containing the element's size {width: (element width + left/right margins), height: (element height + top/bottom margins)}
3167 getOuterSize : function(){
3168 var el = this.getResizeEl();
3169 return {width: el.getWidth() + el.getMargins('lr'),
3170 height: el.getHeight() + el.getMargins('tb')};
3174 * Gets the current XY position of the component's underlying element.
3175 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
3176 * @return {Array} The XY position of the element (e.g., [100, 200])
3178 getPosition : function(local){
3179 var el = this.getPositionEl();
3181 return [el.getLeft(true), el.getTop(true)];
3183 return this.xy || el.getXY();
3187 * Gets the current box measurements of the component's underlying element.
3188 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
3189 * @return {Object} box An object in the format {x, y, width, height}
3191 getBox : function(local){
3192 var pos = this.getPosition(local);
3193 var s = this.getSize();
3200 * Sets the current box measurements of the component's underlying element.
3201 * @param {Object} box An object in the format {x, y, width, height}
3202 * @return {Ext.BoxComponent} this
3204 updateBox : function(box){
3205 this.setSize(box.width, box.height);
3206 this.setPagePosition(box.x, box.y);
3211 * <p>Returns the outermost Element of this Component which defines the Components overall size.</p>
3212 * <p><i>Usually</i> this will return the same Element as <code>{@link #getEl}</code>,
3213 * but in some cases, a Component may have some more wrapping Elements around its main
3214 * active Element.</p>
3215 * <p>An example is a ComboBox. It is encased in a <i>wrapping</i> Element which
3216 * contains both the <code><input></code> Element (which is what would be returned
3217 * by its <code>{@link #getEl}</code> method, <i>and</i> the trigger button Element.
3218 * This Element is returned as the <code>resizeEl</code>.
3219 * @return {Ext.Element} The Element which is to be resized by size managing layouts.
3221 getResizeEl : function(){
3222 return this.resizeEl || this.el;
3226 * Sets the overflow on the content element of the component.
3227 * @param {Boolean} scroll True to allow the Component to auto scroll.
3228 * @return {Ext.BoxComponent} this
3230 setAutoScroll : function(scroll){
3232 this.getContentTarget().setOverflow(scroll ? 'auto' : '');
3234 this.autoScroll = scroll;
3239 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
3240 * This method fires the {@link #move} event.
3241 * @param {Number} left The new left
3242 * @param {Number} top The new top
3243 * @return {Ext.BoxComponent} this
3245 setPosition : function(x, y){
3246 if(x && typeof x[1] == 'number'){
3255 var adj = this.adjustPosition(x, y);
3256 var ax = adj.x, ay = adj.y;
3258 var el = this.getPositionEl();
3259 if(ax !== undefined || ay !== undefined){
3260 if(ax !== undefined && ay !== undefined){
3261 el.setLeftTop(ax, ay);
3262 }else if(ax !== undefined){
3264 }else if(ay !== undefined){
3267 this.onPosition(ax, ay);
3268 this.fireEvent('move', this, ax, ay);
3274 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
3275 * This method fires the {@link #move} event.
3276 * @param {Number} x The new x position
3277 * @param {Number} y The new y position
3278 * @return {Ext.BoxComponent} this
3280 setPagePosition : function(x, y){
3281 if(x && typeof x[1] == 'number'){
3290 if(x === undefined || y === undefined){ // cannot translate undefined points
3293 var p = this.getPositionEl().translatePoints(x, y);
3294 this.setPosition(p.left, p.top);
3299 afterRender : function(){
3300 Ext.BoxComponent.superclass.afterRender.call(this);
3302 this.resizeEl = Ext.get(this.resizeEl);
3304 if(this.positionEl){
3305 this.positionEl = Ext.get(this.positionEl);
3307 this.boxReady = true;
3308 this.setAutoScroll(this.autoScroll);
3309 this.setSize(this.width, this.height);
3310 if(this.x || this.y){
3311 this.setPosition(this.x, this.y);
3312 }else if(this.pageX || this.pageY){
3313 this.setPagePosition(this.pageX, this.pageY);
3318 * Force the component's size to recalculate based on the underlying element's current height and width.
3319 * @return {Ext.BoxComponent} this
3321 syncSize : function(){
3322 delete this.lastSize;
3323 this.setSize(this.autoWidth ? undefined : this.getResizeEl().getWidth(), this.autoHeight ? undefined : this.getResizeEl().getHeight());
3328 * Called after the component is resized, this method is empty by default but can be implemented by any
3329 * subclass that needs to perform custom logic after a resize occurs.
3330 * @param {Number} adjWidth The box-adjusted width that was set
3331 * @param {Number} adjHeight The box-adjusted height that was set
3332 * @param {Number} rawWidth The width that was originally specified
3333 * @param {Number} rawHeight The height that was originally specified
3335 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
3336 this.fireEvent('resize', this, adjWidth, adjHeight, rawWidth, rawHeight);
3340 * Called after the component is moved, this method is empty by default but can be implemented by any
3341 * subclass that needs to perform custom logic after a move occurs.
3342 * @param {Number} x The new x position
3343 * @param {Number} y The new y position
3345 onPosition : function(x, y){
3350 adjustSize : function(w, h){
3354 if(this.autoHeight){
3357 return {width : w, height: h};
3361 adjustPosition : function(x, y){
3362 return {x : x, y: y};
3365 Ext.reg('box', Ext.BoxComponent);
3370 * @extends Ext.BoxComponent
3371 * <p>Used to provide a sizable space in a layout.</p>
3373 * @param {Object} config
3375 Ext.Spacer = Ext.extend(Ext.BoxComponent, {
3378 Ext.reg('spacer', Ext.Spacer);/**
\r
3379 * @class Ext.SplitBar
\r
3380 * @extends Ext.util.Observable
\r
3381 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
\r
3385 var split = new Ext.SplitBar("elementToDrag", "elementToSize",
\r
3386 Ext.SplitBar.HORIZONTAL, Ext.SplitBar.LEFT);
\r
3387 split.setAdapter(new Ext.SplitBar.AbsoluteLayoutAdapter("container"));
\r
3388 split.minSize = 100;
\r
3389 split.maxSize = 600;
\r
3390 split.animate = true;
\r
3391 split.on('moved', splitterMoved);
\r
3394 * Create a new SplitBar
\r
3395 * @param {Mixed} dragElement The element to be dragged and act as the SplitBar.
\r
3396 * @param {Mixed} resizingElement The element to be resized based on where the SplitBar element is dragged
\r
3397 * @param {Number} orientation (optional) Either Ext.SplitBar.HORIZONTAL or Ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
\r
3398 * @param {Number} placement (optional) Either Ext.SplitBar.LEFT or Ext.SplitBar.RIGHT for horizontal or
\r
3399 Ext.SplitBar.TOP or Ext.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
\r
3400 position of the SplitBar).
\r
3402 Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
\r
3405 this.el = Ext.get(dragElement, true);
\r
3406 this.el.dom.unselectable = "on";
\r
3408 this.resizingEl = Ext.get(resizingElement, true);
\r
3412 * The orientation of the split. Either Ext.SplitBar.HORIZONTAL or Ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
\r
3413 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
\r
3416 this.orientation = orientation || Ext.SplitBar.HORIZONTAL;
\r
3419 * The increment, in pixels by which to move this SplitBar. When <i>undefined</i>, the SplitBar moves smoothly.
\r
3421 * @property tickSize
\r
3424 * The minimum size of the resizing element. (Defaults to 0)
\r
3430 * The maximum size of the resizing element. (Defaults to 2000)
\r
3433 this.maxSize = 2000;
\r
3436 * Whether to animate the transition to the new size
\r
3439 this.animate = false;
\r
3442 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
\r
3445 this.useShim = false;
\r
3450 if(!existingProxy){
\r
3452 this.proxy = Ext.SplitBar.createProxy(this.orientation);
\r
3454 this.proxy = Ext.get(existingProxy).dom;
\r
3457 this.dd = new Ext.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
\r
3460 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
\r
3463 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
\r
3466 this.dragSpecs = {};
\r
3469 * @private The adapter to use to positon and resize elements
\r
3471 this.adapter = new Ext.SplitBar.BasicLayoutAdapter();
\r
3472 this.adapter.init(this);
\r
3474 if(this.orientation == Ext.SplitBar.HORIZONTAL){
\r
3476 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Ext.SplitBar.LEFT : Ext.SplitBar.RIGHT);
\r
3477 this.el.addClass("x-splitbar-h");
\r
3480 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Ext.SplitBar.TOP : Ext.SplitBar.BOTTOM);
\r
3481 this.el.addClass("x-splitbar-v");
\r
3487 * Fires when the splitter is moved (alias for {@link #moved})
\r
3488 * @param {Ext.SplitBar} this
\r
3489 * @param {Number} newSize the new width or height
\r
3494 * Fires when the splitter is moved
\r
3495 * @param {Ext.SplitBar} this
\r
3496 * @param {Number} newSize the new width or height
\r
3500 * @event beforeresize
\r
3501 * Fires before the splitter is dragged
\r
3502 * @param {Ext.SplitBar} this
\r
3509 Ext.SplitBar.superclass.constructor.call(this);
\r
3512 Ext.extend(Ext.SplitBar, Ext.util.Observable, {
\r
3513 onStartProxyDrag : function(x, y){
\r
3514 this.fireEvent("beforeresize", this);
\r
3515 this.overlay = Ext.DomHelper.append(document.body, {cls: "x-drag-overlay", html: " "}, true);
\r
3516 this.overlay.unselectable();
\r
3517 this.overlay.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
\r
3518 this.overlay.show();
\r
3519 Ext.get(this.proxy).setDisplayed("block");
\r
3520 var size = this.adapter.getElementSize(this);
\r
3521 this.activeMinSize = this.getMinimumSize();
\r
3522 this.activeMaxSize = this.getMaximumSize();
\r
3523 var c1 = size - this.activeMinSize;
\r
3524 var c2 = Math.max(this.activeMaxSize - size, 0);
\r
3525 if(this.orientation == Ext.SplitBar.HORIZONTAL){
\r
3526 this.dd.resetConstraints();
\r
3527 this.dd.setXConstraint(
\r
3528 this.placement == Ext.SplitBar.LEFT ? c1 : c2,
\r
3529 this.placement == Ext.SplitBar.LEFT ? c2 : c1,
\r
3532 this.dd.setYConstraint(0, 0);
\r
3534 this.dd.resetConstraints();
\r
3535 this.dd.setXConstraint(0, 0);
\r
3536 this.dd.setYConstraint(
\r
3537 this.placement == Ext.SplitBar.TOP ? c1 : c2,
\r
3538 this.placement == Ext.SplitBar.TOP ? c2 : c1,
\r
3542 this.dragSpecs.startSize = size;
\r
3543 this.dragSpecs.startPoint = [x, y];
\r
3544 Ext.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
\r
3548 * @private Called after the drag operation by the DDProxy
\r
3550 onEndProxyDrag : function(e){
\r
3551 Ext.get(this.proxy).setDisplayed(false);
\r
3552 var endPoint = Ext.lib.Event.getXY(e);
\r
3554 Ext.destroy(this.overlay);
\r
3555 delete this.overlay;
\r
3558 if(this.orientation == Ext.SplitBar.HORIZONTAL){
\r
3559 newSize = this.dragSpecs.startSize +
\r
3560 (this.placement == Ext.SplitBar.LEFT ?
\r
3561 endPoint[0] - this.dragSpecs.startPoint[0] :
\r
3562 this.dragSpecs.startPoint[0] - endPoint[0]
\r
3565 newSize = this.dragSpecs.startSize +
\r
3566 (this.placement == Ext.SplitBar.TOP ?
\r
3567 endPoint[1] - this.dragSpecs.startPoint[1] :
\r
3568 this.dragSpecs.startPoint[1] - endPoint[1]
\r
3571 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
\r
3572 if(newSize != this.dragSpecs.startSize){
\r
3573 if(this.fireEvent('beforeapply', this, newSize) !== false){
\r
3574 this.adapter.setElementSize(this, newSize);
\r
3575 this.fireEvent("moved", this, newSize);
\r
3576 this.fireEvent("resize", this, newSize);
\r
3582 * Get the adapter this SplitBar uses
\r
3583 * @return The adapter object
\r
3585 getAdapter : function(){
\r
3586 return this.adapter;
\r
3590 * Set the adapter this SplitBar uses
\r
3591 * @param {Object} adapter A SplitBar adapter object
\r
3593 setAdapter : function(adapter){
\r
3594 this.adapter = adapter;
\r
3595 this.adapter.init(this);
\r
3599 * Gets the minimum size for the resizing element
\r
3600 * @return {Number} The minimum size
\r
3602 getMinimumSize : function(){
\r
3603 return this.minSize;
\r
3607 * Sets the minimum size for the resizing element
\r
3608 * @param {Number} minSize The minimum size
\r
3610 setMinimumSize : function(minSize){
\r
3611 this.minSize = minSize;
\r
3615 * Gets the maximum size for the resizing element
\r
3616 * @return {Number} The maximum size
\r
3618 getMaximumSize : function(){
\r
3619 return this.maxSize;
\r
3623 * Sets the maximum size for the resizing element
\r
3624 * @param {Number} maxSize The maximum size
\r
3626 setMaximumSize : function(maxSize){
\r
3627 this.maxSize = maxSize;
\r
3631 * Sets the initialize size for the resizing element
\r
3632 * @param {Number} size The initial size
\r
3634 setCurrentSize : function(size){
\r
3635 var oldAnimate = this.animate;
\r
3636 this.animate = false;
\r
3637 this.adapter.setElementSize(this, size);
\r
3638 this.animate = oldAnimate;
\r
3642 * Destroy this splitbar.
\r
3643 * @param {Boolean} removeEl True to remove the element
\r
3645 destroy : function(removeEl){
\r
3646 Ext.destroy(this.shim, Ext.get(this.proxy));
\r
3651 this.purgeListeners();
\r
3656 * @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.
\r
3658 Ext.SplitBar.createProxy = function(dir){
\r
3659 var proxy = new Ext.Element(document.createElement("div"));
\r
3660 document.body.appendChild(proxy.dom);
\r
3661 proxy.unselectable();
\r
3662 var cls = 'x-splitbar-proxy';
\r
3663 proxy.addClass(cls + ' ' + (dir == Ext.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
\r
3668 * @class Ext.SplitBar.BasicLayoutAdapter
\r
3669 * Default Adapter. It assumes the splitter and resizing element are not positioned
\r
3670 * elements and only gets/sets the width of the element. Generally used for table based layouts.
\r
3672 Ext.SplitBar.BasicLayoutAdapter = function(){
\r
3675 Ext.SplitBar.BasicLayoutAdapter.prototype = {
\r
3676 // do nothing for now
\r
3677 init : function(s){
\r
3681 * Called before drag operations to get the current size of the resizing element.
\r
3682 * @param {Ext.SplitBar} s The SplitBar using this adapter
\r
3684 getElementSize : function(s){
\r
3685 if(s.orientation == Ext.SplitBar.HORIZONTAL){
\r
3686 return s.resizingEl.getWidth();
\r
3688 return s.resizingEl.getHeight();
\r
3693 * Called after drag operations to set the size of the resizing element.
\r
3694 * @param {Ext.SplitBar} s The SplitBar using this adapter
\r
3695 * @param {Number} newSize The new size to set
\r
3696 * @param {Function} onComplete A function to be invoked when resizing is complete
\r
3698 setElementSize : function(s, newSize, onComplete){
\r
3699 if(s.orientation == Ext.SplitBar.HORIZONTAL){
\r
3701 s.resizingEl.setWidth(newSize);
\r
3703 onComplete(s, newSize);
\r
3706 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
\r
3711 s.resizingEl.setHeight(newSize);
\r
3713 onComplete(s, newSize);
\r
3716 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
\r
3723 *@class Ext.SplitBar.AbsoluteLayoutAdapter
\r
3724 * @extends Ext.SplitBar.BasicLayoutAdapter
\r
3725 * Adapter that moves the splitter element to align with the resized sizing element.
\r
3726 * Used with an absolute positioned SplitBar.
\r
3727 * @param {Mixed} container The container that wraps around the absolute positioned content. If it's
\r
3728 * document.body, make sure you assign an id to the body element.
\r
3730 Ext.SplitBar.AbsoluteLayoutAdapter = function(container){
\r
3731 this.basic = new Ext.SplitBar.BasicLayoutAdapter();
\r
3732 this.container = Ext.get(container);
\r
3735 Ext.SplitBar.AbsoluteLayoutAdapter.prototype = {
\r
3736 init : function(s){
\r
3737 this.basic.init(s);
\r
3740 getElementSize : function(s){
\r
3741 return this.basic.getElementSize(s);
\r
3744 setElementSize : function(s, newSize, onComplete){
\r
3745 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
\r
3748 moveSplitter : function(s){
\r
3749 var yes = Ext.SplitBar;
\r
3750 switch(s.placement){
\r
3752 s.el.setX(s.resizingEl.getRight());
\r
3755 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
\r
3758 s.el.setY(s.resizingEl.getBottom());
\r
3761 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
\r
3768 * Orientation constant - Create a vertical SplitBar
\r
3772 Ext.SplitBar.VERTICAL = 1;
\r
3775 * Orientation constant - Create a horizontal SplitBar
\r
3779 Ext.SplitBar.HORIZONTAL = 2;
\r
3782 * Placement constant - The resizing element is to the left of the splitter element
\r
3786 Ext.SplitBar.LEFT = 1;
\r
3789 * Placement constant - The resizing element is to the right of the splitter element
\r
3793 Ext.SplitBar.RIGHT = 2;
\r
3796 * Placement constant - The resizing element is positioned above the splitter element
\r
3800 Ext.SplitBar.TOP = 3;
\r
3803 * Placement constant - The resizing element is positioned under splitter element
\r
3807 Ext.SplitBar.BOTTOM = 4;
\r
3809 * @class Ext.Container
3810 * @extends Ext.BoxComponent
3811 * <p>Base class for any {@link Ext.BoxComponent} that may contain other Components. Containers handle the
3812 * basic behavior of containing items, namely adding, inserting and removing items.</p>
3814 * <p>The most commonly used Container classes are {@link Ext.Panel}, {@link Ext.Window} and {@link Ext.TabPanel}.
3815 * If you do not need the capabilities offered by the aforementioned classes you can create a lightweight
3816 * Container to be encapsulated by an HTML element to your specifications by using the
3817 * <code><b>{@link Ext.Component#autoEl autoEl}</b></code> config option. This is a useful technique when creating
3818 * embedded {@link Ext.layout.ColumnLayout column} layouts inside {@link Ext.form.FormPanel FormPanels}
3821 * <p>The code below illustrates both how to explicitly create a Container, and how to implicitly
3822 * create one using the <b><code>'container'</code></b> xtype:<pre><code>
3823 // explicitly create a Container
3824 var embeddedColumns = new Ext.Container({
3825 autoEl: 'div', // This is the default
3828 // implicitly create Container by specifying xtype
3830 autoEl: 'div', // This is the default.
3837 // The two items below will be Ext.Containers, each encapsulated by a <DIV> element.
3842 fieldLabel: 'Start date'
3848 fieldLabel: 'End date'
3851 });</code></pre></p>
3853 * <p><u><b>Layout</b></u></p>
3854 * <p>Container classes delegate the rendering of child Components to a layout
3855 * manager class which must be configured into the Container using the
3856 * <code><b>{@link #layout}</b></code> configuration property.</p>
3857 * <p>When either specifying child <code>{@link #items}</code> of a Container,
3858 * or dynamically {@link #add adding} Components to a Container, remember to
3859 * consider how you wish the Container to arrange those child elements, and
3860 * whether those child elements need to be sized using one of Ext's built-in
3861 * <b><code>{@link #layout}</code></b> schemes. By default, Containers use the
3862 * {@link Ext.layout.ContainerLayout ContainerLayout} scheme which only
3863 * renders child components, appending them one after the other inside the
3864 * Container, and <b>does not apply any sizing</b> at all.</p>
3865 * <p>A common mistake is when a developer neglects to specify a
3866 * <b><code>{@link #layout}</code></b> (e.g. widgets like GridPanels or
3867 * TreePanels are added to Containers for which no <code><b>{@link #layout}</b></code>
3868 * has been specified). If a Container is left to use the default
3869 * {@link Ext.layout.ContainerLayout ContainerLayout} scheme, none of its
3870 * child components will be resized, or changed in any way when the Container
3872 * <p>Certain layout managers allow dynamic addition of child components.
3873 * Those that do include {@link Ext.layout.CardLayout},
3874 * {@link Ext.layout.AnchorLayout}, {@link Ext.layout.FormLayout}, and
3875 * {@link Ext.layout.TableLayout}. For example:<pre><code>
3876 // Create the GridPanel.
3877 var myNewGrid = new Ext.grid.GridPanel({
3879 columns: myColumnModel,
3880 title: 'Results', // the title becomes the title of the tab
3883 myTabPanel.add(myNewGrid); // {@link Ext.TabPanel} implicitly uses {@link Ext.layout.CardLayout CardLayout}
3884 myTabPanel.{@link Ext.TabPanel#setActiveTab setActiveTab}(myNewGrid);
3886 * <p>The example above adds a newly created GridPanel to a TabPanel. Note that
3887 * a TabPanel uses {@link Ext.layout.CardLayout} as its layout manager which
3888 * means all its child items are sized to {@link Ext.layout.FitLayout fit}
3889 * exactly into its client area.
3890 * <p><b><u>Overnesting is a common problem</u></b>.
3891 * An example of overnesting occurs when a GridPanel is added to a TabPanel
3892 * by wrapping the GridPanel <i>inside</i> a wrapping Panel (that has no
3893 * <code><b>{@link #layout}</b></code> specified) and then add that wrapping Panel
3894 * to the TabPanel. The point to realize is that a GridPanel <b>is</b> a
3895 * Component which can be added directly to a Container. If the wrapping Panel
3896 * has no <code><b>{@link #layout}</b></code> configuration, then the overnested
3897 * GridPanel will not be sized as expected.<p>
3899 * <p><u><b>Adding via remote configuration</b></u></p>
3901 * <p>A server side script can be used to add Components which are generated dynamically on the server.
3902 * An example of adding a GridPanel to a TabPanel where the GridPanel is generated by the server
3903 * based on certain parameters:
3905 // execute an Ajax request to invoke server side script:
3907 url: 'gen-invoice-grid.php',
3908 // send additional parameters to instruct server script
3910 startDate: Ext.getCmp('start-date').getValue(),
3911 endDate: Ext.getCmp('end-date').getValue()
3913 // process the response object to add it to the TabPanel:
3914 success: function(xhr) {
3915 var newComponent = eval(xhr.responseText); // see discussion below
3916 myTabPanel.add(newComponent); // add the component to the TabPanel
3917 myTabPanel.setActiveTab(newComponent);
3919 failure: function() {
3920 Ext.Msg.alert("Grid create failed", "Server communication failure");
3924 * <p>The server script needs to return an executable Javascript statement which, when processed
3925 * using <code>eval()</code>, will return either a config object with an {@link Ext.Component#xtype xtype},
3926 * or an instantiated Component. The server might return this for example:</p><pre><code>
3928 function formatDate(value){
3929 return value ? value.dateFormat('M d, Y') : '';
3932 var store = new Ext.data.Store({
3933 url: 'get-invoice-data.php',
3935 startDate: '01/01/2008',
3936 endDate: '01/31/2008'
3938 reader: new Ext.data.JsonReader({
3939 record: 'transaction',
3941 totalRecords: 'total'
3945 {name: 'date', type: 'date', dateFormat: 'm/d/Y'},
3946 {name: 'value', type: 'float'}
3950 var grid = new Ext.grid.GridPanel({
3951 title: 'Invoice Report',
3952 bbar: new Ext.PagingToolbar(store),
3955 {header: "Customer", width: 250, dataIndex: 'customer', sortable: true},
3956 {header: "Invoice Number", width: 120, dataIndex: 'invNo', sortable: true},
3957 {header: "Invoice Date", width: 100, dataIndex: 'date', renderer: formatDate, sortable: true},
3958 {header: "Value", width: 120, dataIndex: 'value', renderer: 'usMoney', sortable: true}
3962 return grid; // return instantiated component
3965 * <p>When the above code fragment is passed through the <code>eval</code> function in the success handler
3966 * of the Ajax request, the code is executed by the Javascript processor, and the anonymous function
3967 * runs, and returns the instantiated grid component.</p>
3968 * <p>Note: since the code above is <i>generated</i> by a server script, the <code>baseParams</code> for
3969 * the Store, the metadata to allow generation of the Record layout, and the ColumnModel
3970 * can all be generated into the code since these are all known on the server.</p>
3974 Ext.Container = Ext.extend(Ext.BoxComponent, {
3976 * @cfg {Boolean} monitorResize
3977 * True to automatically monitor window resize events to handle anything that is sensitive to the current size
3978 * of the viewport. This value is typically managed by the chosen <code>{@link #layout}</code> and should not need
3979 * to be set manually.
3982 * @cfg {String/Object} layout
3983 * <p><b>*Important</b>: In order for child items to be correctly sized and
3984 * positioned, typically a layout manager <b>must</b> be specified through
3985 * the <code>layout</code> configuration option.</p>
3986 * <br><p>The sizing and positioning of child {@link items} is the responsibility of
3987 * the Container's layout manager which creates and manages the type of layout
3988 * you have in mind. For example:</p><pre><code>
3990 width:300, height: 300,
3991 layout: 'fit', // explicitly set layout manager: override the default (layout:'auto')
3993 title: 'Panel inside a Window'
3997 * <p>If the {@link #layout} configuration is not explicitly specified for
3998 * a general purpose container (e.g. Container or Panel) the
3999 * {@link Ext.layout.ContainerLayout default layout manager} will be used
4000 * which does nothing but render child components sequentially into the
4001 * Container (no sizing or positioning will be performed in this situation).
4002 * Some container classes implicitly specify a default layout
4003 * (e.g. FormPanel specifies <code>layout:'form'</code>). Other specific
4004 * purpose classes internally specify/manage their internal layout (e.g.
4005 * GridPanel, TabPanel, TreePanel, Toolbar, Menu, etc.).</p>
4006 * <br><p><b><code>layout</code></b> may be specified as either as an Object or
4007 * as a String:</p><div><ul class="mdetail-params">
4009 * <li><u>Specify as an Object</u></li>
4010 * <div><ul class="mdetail-params">
4011 * <li>Example usage:</li>
4020 * <li><code><b>type</b></code></li>
4021 * <br/><p>The layout type to be used for this container. If not specified,
4022 * a default {@link Ext.layout.ContainerLayout} will be created and used.</p>
4023 * <br/><p>Valid layout <code>type</code> values are:</p>
4024 * <div class="sub-desc"><ul class="mdetail-params">
4025 * <li><code><b>{@link Ext.layout.AbsoluteLayout absolute}</b></code></li>
4026 * <li><code><b>{@link Ext.layout.AccordionLayout accordion}</b></code></li>
4027 * <li><code><b>{@link Ext.layout.AnchorLayout anchor}</b></code></li>
4028 * <li><code><b>{@link Ext.layout.ContainerLayout auto}</b></code> <b>Default</b></li>
4029 * <li><code><b>{@link Ext.layout.BorderLayout border}</b></code></li>
4030 * <li><code><b>{@link Ext.layout.CardLayout card}</b></code></li>
4031 * <li><code><b>{@link Ext.layout.ColumnLayout column}</b></code></li>
4032 * <li><code><b>{@link Ext.layout.FitLayout fit}</b></code></li>
4033 * <li><code><b>{@link Ext.layout.FormLayout form}</b></code></li>
4034 * <li><code><b>{@link Ext.layout.HBoxLayout hbox}</b></code></li>
4035 * <li><code><b>{@link Ext.layout.MenuLayout menu}</b></code></li>
4036 * <li><code><b>{@link Ext.layout.TableLayout table}</b></code></li>
4037 * <li><code><b>{@link Ext.layout.ToolbarLayout toolbar}</b></code></li>
4038 * <li><code><b>{@link Ext.layout.VBoxLayout vbox}</b></code></li>
4041 * <li>Layout specific configuration properties</li>
4042 * <br/><p>Additional layout specific configuration properties may also be
4043 * specified. For complete details regarding the valid config options for
4044 * each layout type, see the layout class corresponding to the <code>type</code>
4049 * <li><u>Specify as a String</u></li>
4050 * <div><ul class="mdetail-params">
4051 * <li>Example usage:</li>
4059 * <li><code><b>layout</b></code></li>
4060 * <br/><p>The layout <code>type</code> to be used for this container (see list
4061 * of valid layout type values above).</p><br/>
4062 * <li><code><b>{@link #layoutConfig}</b></code></li>
4063 * <br/><p>Additional layout specific configuration properties. For complete
4064 * details regarding the valid config options for each layout type, see the
4065 * layout class corresponding to the <code>layout</code> specified.</p>
4066 * </ul></div></ul></div>
4069 * @cfg {Object} layoutConfig
4070 * This is a config object containing properties specific to the chosen
4071 * <b><code>{@link #layout}</code></b> if <b><code>{@link #layout}</code></b>
4072 * has been specified as a <i>string</i>.</p>
4075 * @cfg {Boolean/Number} bufferResize
4076 * When set to true (50 milliseconds) or a number of milliseconds, the layout assigned for this container will buffer
4077 * the frequency it calculates and does a re-layout of components. This is useful for heavy containers or containers
4078 * with a large quantity of sub-components for which frequent layout calls would be expensive. Defaults to <code>50</code>.
4083 * @cfg {String/Number} activeItem
4084 * A string component id or the numeric index of the component that should be initially activated within the
4085 * container's layout on render. For example, activeItem: 'item-1' or activeItem: 0 (index 0 = the first
4086 * item in the container's collection). activeItem only applies to layout styles that can display
4087 * items one at a time (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout} and
4088 * {@link Ext.layout.FitLayout}). Related to {@link Ext.layout.ContainerLayout#activeItem}.
4091 * @cfg {Object/Array} items
4092 * <pre><b>** IMPORTANT</b>: be sure to <b>{@link #layout specify a <code>layout</code>} if needed ! **</b></pre>
4093 * <p>A single item, or an array of child Components to be added to this container,
4096 // specifying a single item
4098 layout: 'fit', // specify a layout!
4100 // specifying multiple items
4101 items: [{...}, {...}],
4102 layout: 'anchor', // specify a layout!
4104 * <p>Each item may be:</p>
4105 * <div><ul class="mdetail-params">
4106 * <li>any type of object based on {@link Ext.Component}</li>
4107 * <li>a fully instanciated object or</li>
4108 * <li>an object literal that:</li>
4109 * <div><ul class="mdetail-params">
4110 * <li>has a specified <code>{@link Ext.Component#xtype xtype}</code></li>
4111 * <li>the {@link Ext.Component#xtype} specified is associated with the Component
4112 * desired and should be chosen from one of the available xtypes as listed
4113 * in {@link Ext.Component}.</li>
4114 * <li>If an <code>{@link Ext.Component#xtype xtype}</code> is not explicitly
4115 * specified, the {@link #defaultType} for that Container is used.</li>
4116 * <li>will be "lazily instanciated", avoiding the overhead of constructing a fully
4117 * instanciated Component object</li>
4118 * </ul></div></ul></div>
4119 * <p><b>Notes</b>:</p>
4120 * <div><ul class="mdetail-params">
4121 * <li>Ext uses lazy rendering. Child Components will only be rendered
4122 * should it become necessary. Items are automatically laid out when they are first
4123 * shown (no sizing is done while hidden), or in response to a {@link #doLayout} call.</li>
4124 * <li>Do not specify <code>{@link Ext.Panel#contentEl contentEl}</code>/
4125 * <code>{@link Ext.Panel#html html}</code> with <code>items</code>.</li>
4129 * @cfg {Object|Function} defaults
4130 * <p>This option is a means of applying default settings to all added items whether added through the {@link #items}
4131 * config or via the {@link #add} or {@link #insert} methods.</p>
4132 * <p>If an added item is a config object, and <b>not</b> an instantiated Component, then the default properties are
4133 * unconditionally applied. If the added item <b>is</b> an instantiated Component, then the default properties are
4134 * applied conditionally so as not to override existing properties in the item.</p>
4135 * <p>If the defaults option is specified as a function, then the function will be called using this Container as the
4136 * scope (<code>this</code> reference) and passing the added item as the first parameter. Any resulting object
4137 * from that call is then applied to the item as default properties.</p>
4138 * <p>For example, to automatically apply padding to the body of each of a set of
4139 * contained {@link Ext.Panel} items, you could pass: <code>defaults: {bodyStyle:'padding:15px'}</code>.</p>
4140 * <p>Usage:</p><pre><code>
4141 defaults: { // defaults are applied to items, not the container
4146 xtype: 'panel', // defaults <b>do not</b> have precedence over
4147 id: 'panel1', // options in config objects, so the defaults
4148 autoScroll: false // will not be applied here, panel1 will be autoScroll:false
4150 new Ext.Panel({ // defaults <b>do</b> have precedence over options
4151 id: 'panel2', // options in components, so the defaults
4152 autoScroll: false // will be applied here, panel2 will be autoScroll:true.
4159 /** @cfg {Boolean} autoDestroy
4160 * If true the container will automatically destroy any contained component that is removed from it, else
4161 * destruction must be handled manually (defaults to true).
4165 /** @cfg {Boolean} forceLayout
4166 * If true the container will force a layout initially even if hidden or collapsed. This option
4167 * is useful for forcing forms to render in collapsed or hidden containers. (defaults to false).
4171 /** @cfg {Boolean} hideBorders
4172 * True to hide the borders of each contained component, false to defer to the component's existing
4173 * border settings (defaults to false).
4175 /** @cfg {String} defaultType
4176 * <p>The default {@link Ext.Component xtype} of child Components to create in this Container when
4177 * a child item is specified as a raw configuration object, rather than as an instantiated Component.</p>
4178 * <p>Defaults to <code>'panel'</code>, except {@link Ext.menu.Menu} which defaults to <code>'menuitem'</code>,
4179 * and {@link Ext.Toolbar} and {@link Ext.ButtonGroup} which default to <code>'button'</code>.</p>
4181 defaultType : 'panel',
4183 /** @cfg {String} resizeEvent
4184 * The event to listen to for resizing in layouts. Defaults to <code>'resize'</code>.
4186 resizeEvent: 'resize',
4189 * @cfg {Array} bubbleEvents
4190 * <p>An array of events that, when fired, should be bubbled to any parent container.
4191 * See {@link Ext.util.Observable#enableBubble}.
4192 * Defaults to <code>['add', 'remove']</code>.
4194 bubbleEvents: ['add', 'remove'],
4197 initComponent : function(){
4198 Ext.Container.superclass.initComponent.call(this);
4202 * @event afterlayout
4203 * Fires when the components in this container are arranged by the associated layout manager.
4204 * @param {Ext.Container} this
4205 * @param {ContainerLayout} layout The ContainerLayout implementation for this container
4210 * Fires before any {@link Ext.Component} is added or inserted into the container.
4211 * A handler can return false to cancel the add.
4212 * @param {Ext.Container} this
4213 * @param {Ext.Component} component The component being added
4214 * @param {Number} index The index at which the component will be added to the container's items collection
4218 * @event beforeremove
4219 * Fires before any {@link Ext.Component} is removed from the container. A handler can return
4220 * false to cancel the remove.
4221 * @param {Ext.Container} this
4222 * @param {Ext.Component} component The component being removed
4228 * Fires after any {@link Ext.Component} is added or inserted into the container.
4229 * @param {Ext.Container} this
4230 * @param {Ext.Component} component The component that was added
4231 * @param {Number} index The index at which the component was added to the container's items collection
4237 * Fires after any {@link Ext.Component} is removed from the container.
4238 * @param {Ext.Container} this
4239 * @param {Ext.Component} component The component that was removed
4244 this.enableBubble(this.bubbleEvents);
4247 * The collection of components in this container as a {@link Ext.util.MixedCollection}
4248 * @type MixedCollection
4251 var items = this.items;
4259 initItems : function(){
4261 this.items = new Ext.util.MixedCollection(false, this.getComponentId);
4262 this.getLayout(); // initialize the layout
4267 setLayout : function(layout){
4268 if(this.layout && this.layout != layout){
4269 this.layout.setContainer(null);
4272 this.layout = layout;
4273 layout.setContainer(this);
4276 afterRender: function(){
4277 this.layoutDone = false;
4279 this.layout = 'auto';
4281 if(Ext.isObject(this.layout) && !this.layout.layout){
4282 this.layoutConfig = this.layout;
4283 this.layout = this.layoutConfig.type;
4285 if(Ext.isString(this.layout)){
4286 this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig);
4288 this.setLayout(this.layout);
4290 // BoxComponent's afterRender will set the size.
4291 // This will will trigger a layout if the layout is configured to monitor resize
4292 Ext.Container.superclass.afterRender.call(this);
4294 if(Ext.isDefined(this.activeItem)){
4295 var item = this.activeItem;
4296 delete this.activeItem;
4297 this.layout.setActiveItem(item);
4300 // If we have no ownerCt and the BoxComponent's sizing did not trigger a layout, force a layout
4301 if(!this.ownerCt && !this.layoutDone){
4302 this.doLayout(false, true);
4305 if(this.monitorResize === true){
4306 Ext.EventManager.onWindowResize(this.doLayout, this, [false]);
4311 * <p>Returns the Element to be used to contain the child Components of this Container.</p>
4312 * <p>An implementation is provided which returns the Container's {@link #getEl Element}, but
4313 * if there is a more complex structure to a Container, this may be overridden to return
4314 * the element into which the {@link #layout layout} renders child Components.</p>
4315 * @return {Ext.Element} The Element to render child Components into.
4317 getLayoutTarget : function(){
4321 // private - used as the key lookup function for the items collection
4322 getComponentId : function(comp){
4323 return comp.getItemId();
4327 * <p>Adds {@link Ext.Component Component}(s) to this Container.</p>
4328 * <br><p><b>Description</b></u> :
4329 * <div><ul class="mdetail-params">
4330 * <li>Fires the {@link #beforeadd} event before adding</li>
4331 * <li>The Container's {@link #defaults default config values} will be applied
4332 * accordingly (see <code>{@link #defaults}</code> for details).</li>
4333 * <li>Fires the {@link #add} event after the component has been added.</li>
4335 * <br><p><b>Notes</b></u> :
4336 * <div><ul class="mdetail-params">
4337 * <li>If the Container is <i>already rendered</i> when <code>add</code>
4338 * is called, you may need to call {@link #doLayout} to refresh the view which causes
4339 * any unrendered child Components to be rendered. This is required so that you can
4340 * <code>add</code> multiple child components if needed while only refreshing the layout
4341 * once. For example:<pre><code>
4342 var tb = new {@link Ext.Toolbar}();
4343 tb.render(document.body); // toolbar is rendered
4344 tb.add({text:'Button 1'}); // add multiple items ({@link #defaultType} for {@link Ext.Toolbar Toolbar} is 'button')
4345 tb.add({text:'Button 2'});
4346 tb.{@link #doLayout}(); // refresh the layout
4347 * </code></pre></li>
4348 * <li><i>Warning:</i> Containers directly managed by the BorderLayout layout manager
4349 * may not be removed or added. See the Notes for {@link Ext.layout.BorderLayout BorderLayout}
4350 * for more details.</li>
4352 * @param {Object/Array} component
4353 * <p>Either a single component or an Array of components to add. See
4354 * <code>{@link #items}</code> for additional information.</p>
4355 * @param {Object} (Optional) component_2
4356 * @param {Object} (Optional) component_n
4357 * @return {Ext.Component} component The Component (or config object) that was added.
4359 add : function(comp){
4361 var args = arguments.length > 1;
4362 if(args || Ext.isArray(comp)){
4364 Ext.each(args ? arguments : comp, function(c){
4365 result.push(this.add(c));
4369 var c = this.lookupComponent(this.applyDefaults(comp));
4370 var index = this.items.length;
4371 if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){
4374 c.onAdded(this, index);
4376 this.fireEvent('add', this, c, index);
4381 onAdd : function(c){
4382 // Empty template method
4386 onAdded : function(container, pos) {
4387 //overridden here so we can cascade down, not worth creating a template method.
4388 this.ownerCt = container;
4390 //initialize references for child items
4391 this.cascade(function(c){
4394 this.fireEvent('added', this, container, pos);
4398 * Inserts a Component into this Container at a specified index. Fires the
4399 * {@link #beforeadd} event before inserting, then fires the {@link #add} event after the
4400 * Component has been inserted.
4401 * @param {Number} index The index at which the Component will be inserted
4402 * into the Container's items collection
4403 * @param {Ext.Component} component The child Component to insert.<br><br>
4404 * Ext uses lazy rendering, and will only render the inserted Component should
4405 * it become necessary.<br><br>
4406 * A Component config object may be passed in order to avoid the overhead of
4407 * constructing a real Component object if lazy rendering might mean that the
4408 * inserted Component will not be rendered immediately. To take advantage of
4409 * this 'lazy instantiation', set the {@link Ext.Component#xtype} config
4410 * property to the registered type of the Component wanted.<br><br>
4411 * For a list of all available xtypes, see {@link Ext.Component}.
4412 * @return {Ext.Component} component The Component (or config object) that was
4413 * inserted with the Container's default config values applied.
4415 insert : function(index, comp){
4417 var a = arguments, len = a.length;
4420 for(var i = len-1; i >= 1; --i) {
4421 result.push(this.insert(index, a[i]));
4425 var c = this.lookupComponent(this.applyDefaults(comp));
4426 index = Math.min(index, this.items.length);
4427 if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){
4428 if(c.ownerCt == this){
4429 this.items.remove(c);
4431 this.items.insert(index, c);
4432 c.onAdded(this, index);
4434 this.fireEvent('add', this, c, index);
4440 applyDefaults : function(c){
4441 var d = this.defaults;
4443 if(Ext.isFunction(d)){
4444 d = d.call(this, c);
4446 if(Ext.isString(c)){
4447 c = Ext.ComponentMgr.get(c);
4449 }else if(!c.events){
4459 onBeforeAdd : function(item){
4461 item.ownerCt.remove(item, false);
4463 if(this.hideBorders === true){
4464 item.border = (item.border === true);
4469 * Removes a component from this container. Fires the {@link #beforeremove} event before removing, then fires
4470 * the {@link #remove} event after the component has been removed.
4471 * @param {Component/String} component The component reference or id to remove.
4472 * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
4473 * Defaults to the value of this Container's {@link #autoDestroy} config.
4474 * @return {Ext.Component} component The Component that was removed.
4476 remove : function(comp, autoDestroy){
4478 var c = this.getComponent(comp);
4479 if(c && this.fireEvent('beforeremove', this, c) !== false){
4480 this.doRemove(c, autoDestroy);
4481 this.fireEvent('remove', this, c);
4486 onRemove: function(c){
4487 // Empty template method
4491 doRemove: function(c, autoDestroy){
4492 if(this.layout && this.rendered){
4493 this.layout.onRemove(c);
4495 this.items.remove(c);
4498 if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){
4504 * Removes all components from this container.
4505 * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
4506 * Defaults to the value of this Container's {@link #autoDestroy} config.
4507 * @return {Array} Array of the destroyed components
4509 removeAll: function(autoDestroy){
4511 var item, rem = [], items = [];
4512 this.items.each(function(i){
4515 for (var i = 0, len = rem.length; i < len; ++i){
4517 this.remove(item, autoDestroy);
4518 if(item.ownerCt !== this){
4526 * Examines this container's <code>{@link #items}</code> <b>property</b>
4527 * and gets a direct child component of this container.
4528 * @param {String/Number} comp This parameter may be any of the following:
4529 * <div><ul class="mdetail-params">
4530 * <li>a <b><code>String</code></b> : representing the <code>{@link Ext.Component#itemId itemId}</code>
4531 * or <code>{@link Ext.Component#id id}</code> of the child component </li>
4532 * <li>a <b><code>Number</code></b> : representing the position of the child component
4533 * within the <code>{@link #items}</code> <b>property</b></li>
4535 * <p>For additional information see {@link Ext.util.MixedCollection#get}.
4536 * @return Ext.Component The component (if found).
4538 getComponent : function(comp){
4539 if(Ext.isObject(comp)){
4540 comp = comp.getItemId();
4542 return this.items.get(comp);
4546 lookupComponent : function(comp){
4547 if(Ext.isString(comp)){
4548 return Ext.ComponentMgr.get(comp);
4549 }else if(!comp.events){
4550 return this.createComponent(comp);
4556 createComponent : function(config, defaultType){
4557 // add in ownerCt at creation time but then immediately
4558 // remove so that onBeforeAdd can handle it
4559 var c = config.render ? config : Ext.create(Ext.apply({
4561 }, config), defaultType || this.defaultType);
4567 * We can only lay out if there is a view area in which to layout.
4568 * display:none on the layout target, *or any of its parent elements* will mean it has no view area.
4570 canLayout: function() {
4571 var el = this.getLayoutTarget(), vs;
4572 return !!(el && (vs = el.dom.offsetWidth || el.dom.offsetHeight));
4576 * Force this container's layout to be recalculated. A call to this function is required after adding a new component
4577 * to an already rendered container, or possibly after changing sizing/position properties of child components.
4578 * @param {Boolean} shallow (optional) True to only calc the layout of this component, and let child components auto
4579 * calc layouts as required (defaults to false, which calls doLayout recursively for each subcontainer)
4580 * @param {Boolean} force (optional) True to force a layout to occur, even if the item is hidden.
4581 * @return {Ext.Container} this
4583 doLayout: function(shallow, force){
4584 var rendered = this.rendered,
4585 forceLayout = force || this.forceLayout,
4588 this.layoutDone = true;
4589 if(!this.canLayout() || this.collapsed){
4590 this.deferLayout = this.deferLayout || !shallow;
4594 shallow = shallow && !this.deferLayout;
4596 delete this.deferLayout;
4599 cs = (shallow !== true && this.items) ? this.items.items : [];
4601 // Inhibit child Containers from relaying on resize since we are about to to explicitly call doLayout on them all!
4602 for(i = 0, len = cs.length; i < len; i++){
4603 if ((c = cs[i]).layout) {
4604 c.suspendLayoutResize = true;
4608 // Tell the layout manager to ensure all child items are rendered, and sized according to their rules.
4609 // Will not cause the child items to relayout.
4610 if(rendered && this.layout){
4611 this.layout.layout();
4614 // Explicitly lay out all child items
4615 for(i = 0; i < len; i++){
4616 if((c = cs[i]).doLayout){
4617 c.doLayout(false, forceLayout);
4621 this.onLayout(shallow, forceLayout);
4623 // Initial layout completed
4624 this.hasLayout = true;
4625 delete this.forceLayout;
4627 // Re-enable child layouts relaying on resize.
4628 for(i = 0; i < len; i++){
4629 if ((c = cs[i]).layout) {
4630 delete c.suspendLayoutResize;
4636 onLayout : Ext.emptyFn,
4638 onResize: function(adjWidth, adjHeight, rawWidth, rawHeight){
4639 Ext.Container.superclass.onResize.apply(this, arguments);
4640 if ((this.rendered && this.layout && this.layout.monitorResize) && !this.suspendLayoutResize) {
4641 this.layout.onResize();
4646 hasLayoutPending: function(){
4647 // Traverse hierarchy to see if any parent container has a pending layout.
4648 var pending = this.layoutPending;
4649 this.ownerCt.bubble(function(c){
4650 return !(pending = c.layoutPending);
4656 onShow : function(){
4657 Ext.Container.superclass.onShow.call(this);
4658 if(Ext.isDefined(this.deferLayout)){
4659 this.doLayout(true);
4664 * Returns the layout currently in use by the container. If the container does not currently have a layout
4665 * set, a default {@link Ext.layout.ContainerLayout} will be created and set as the container's layout.
4666 * @return {ContainerLayout} layout The container's layout
4668 getLayout : function(){
4670 var layout = new Ext.layout.ContainerLayout(this.layoutConfig);
4671 this.setLayout(layout);
4677 beforeDestroy : function(){
4680 while(c = this.items.first()){
4681 this.doRemove(c, true);
4684 if(this.monitorResize){
4685 Ext.EventManager.removeResizeListener(this.doLayout, this);
4687 Ext.destroy(this.layout);
4688 Ext.Container.superclass.beforeDestroy.call(this);
4692 * Bubbles up the component/container heirarchy, calling the specified function with each component. The scope (<i>this</i>) of
4693 * function call will be the scope provided or the current component. The arguments to the function
4694 * will be the args provided or the current component. If the function returns false at any point,
4695 * the bubble is stopped.
4696 * @param {Function} fn The function to call
4697 * @param {Object} scope (optional) The scope of the function (defaults to current node)
4698 * @param {Array} args (optional) The args to call the function with (default to passing the current component)
4699 * @return {Ext.Container} this
4701 bubble : function(fn, scope, args){
4704 if(fn.apply(scope || p, args || [p]) === false){
4713 * Cascades down the component/container heirarchy from this component (called first), calling the specified function with
4714 * each component. The scope (<i>this</i>) of
4715 * function call will be the scope provided or the current component. The arguments to the function
4716 * will be the args provided or the current component. If the function returns false at any point,
4717 * the cascade is stopped on that branch.
4718 * @param {Function} fn The function to call
4719 * @param {Object} scope (optional) The scope of the function (defaults to current component)
4720 * @param {Array} args (optional) The args to call the function with (defaults to passing the current component)
4721 * @return {Ext.Container} this
4723 cascade : function(fn, scope, args){
4724 if(fn.apply(scope || this, args || [this]) !== false){
4726 var cs = this.items.items;
4727 for(var i = 0, len = cs.length; i < len; i++){
4729 cs[i].cascade(fn, scope, args);
4731 fn.apply(scope || cs[i], args || [cs[i]]);
4740 * Find a component under this container at any level by id
4741 * @param {String} id
4742 * @return Ext.Component
4744 findById : function(id){
4746 this.cascade(function(c){
4747 if(ct != c && c.id === id){
4756 * Find a component under this container at any level by xtype or class
4757 * @param {String/Class} xtype The xtype string for a component, or the class of the component directly
4758 * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
4759 * the default), or true to check whether this Component is directly of the specified xtype.
4760 * @return {Array} Array of Ext.Components
4762 findByType : function(xtype, shallow){
4763 return this.findBy(function(c){
4764 return c.isXType(xtype, shallow);
4769 * Find a component under this container at any level by property
4770 * @param {String} prop
4771 * @param {String} value
4772 * @return {Array} Array of Ext.Components
4774 find : function(prop, value){
4775 return this.findBy(function(c){
4776 return c[prop] === value;
4781 * Find a component under this container at any level by a custom function. If the passed function returns
4782 * true, the component will be included in the results. The passed function is called with the arguments (component, this container).
4783 * @param {Function} fn The function to call
4784 * @param {Object} scope (optional)
4785 * @return {Array} Array of Ext.Components
4787 findBy : function(fn, scope){
4788 var m = [], ct = this;
4789 this.cascade(function(c){
4790 if(ct != c && fn.call(scope || c, c, ct) === true){
4798 * Get a component contained by this container (alias for items.get(key))
4799 * @param {String/Number} key The index or id of the component
4800 * @return {Ext.Component} Ext.Component
4802 get : function(key){
4803 return this.items.get(key);
4807 Ext.Container.LAYOUTS = {};
4808 Ext.reg('container', Ext.Container);
4810 * @class Ext.layout.ContainerLayout
4811 * <p>The ContainerLayout class is the default layout manager delegated by {@link Ext.Container} to
4812 * render any child Components when no <tt>{@link Ext.Container#layout layout}</tt> is configured into
4813 * a {@link Ext.Container Container}. ContainerLayout provides the basic foundation for all other layout
4814 * classes in Ext. It simply renders all child Components into the Container, performing no sizing or
4815 * positioning services. To utilize a layout that provides sizing and positioning of child Components,
4816 * specify an appropriate <tt>{@link Ext.Container#layout layout}</tt>.</p>
4817 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
4818 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
4820 Ext.layout.ContainerLayout = Ext.extend(Object, {
4822 * @cfg {String} extraCls
4823 * <p>An optional extra CSS class that will be added to the container. This can be useful for adding
4824 * customized styles to the container or any of its children using standard CSS rules. See
4825 * {@link Ext.Component}.{@link Ext.Component#ctCls ctCls} also.</p>
4826 * <p><b>Note</b>: <tt>extraCls</tt> defaults to <tt>''</tt> except for the following classes
4827 * which assign a value by default:
4828 * <div class="mdetail-params"><ul>
4829 * <li>{@link Ext.layout.AbsoluteLayout Absolute Layout} : <tt>'x-abs-layout-item'</tt></li>
4830 * <li>{@link Ext.layout.Box Box Layout} : <tt>'x-box-item'</tt></li>
4831 * <li>{@link Ext.layout.ColumnLayout Column Layout} : <tt>'x-column'</tt></li>
4833 * To configure the above Classes with an extra CSS class append to the default. For example,
4834 * for ColumnLayout:<pre><code>
4835 * extraCls: 'x-column custom-class'
4840 * @cfg {Boolean} renderHidden
4841 * True to hide each contained item on render (defaults to false).
4845 * A reference to the {@link Ext.Component} that is active. For example, <pre><code>
4846 * if(myPanel.layout.activeItem.id == 'item-1') { ... }
4848 * <tt>activeItem</tt> only applies to layout styles that can display items one at a time
4849 * (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout}
4850 * and {@link Ext.layout.FitLayout}). Read-only. Related to {@link Ext.Container#activeItem}.
4851 * @type {Ext.Component}
4852 * @property activeItem
4856 monitorResize:false,
4860 constructor : function(config){
4861 Ext.apply(this, config);
4865 layout : function(){
4866 var target = this.container.getLayoutTarget();
4867 if(!(this.hasLayout || Ext.isEmpty(this.targetCls))){
4868 target.addClass(this.targetCls)
4870 this.onLayout(this.container, target);
4871 this.container.fireEvent('afterlayout', this.container, this);
4872 this.hasLayout = true;
4876 onLayout : function(ct, target){
4877 this.renderAll(ct, target);
4881 isValidParent : function(c, target){
4882 return target && c.getPositionEl().dom.parentNode == (target.dom || target);
4886 renderAll : function(ct, target){
4887 var items = ct.items.items;
4888 for(var i = 0, len = items.length; i < len; i++) {
4890 if(c && (!c.rendered || !this.isValidParent(c, target))){
4891 this.renderItem(c, i, target);
4897 renderItem : function(c, position, target){
4898 if(c && !c.rendered){
4899 c.render(target, position);
4900 this.configureItem(c, position);
4901 }else if(c && !this.isValidParent(c, target)){
4902 if(Ext.isNumber(position)){
4903 position = target.dom.childNodes[position];
4905 target.dom.insertBefore(c.getPositionEl().dom, position || null);
4906 c.container = target;
4907 this.configureItem(c, position);
4912 configureItem: function(c, position){
4914 var t = c.getPositionEl ? c.getPositionEl() : c;
4915 t.addClass(this.extraCls);
4917 // If we are forcing a layout, do so *before* we hide so elements have height/width
4918 if(c.doLayout && this.forceLayout){
4919 c.doLayout(false, true);
4921 if (this.renderHidden && c != this.activeItem) {
4926 onRemove: function(c){
4927 if(this.activeItem == c){
4928 delete this.activeItem;
4930 if(c.rendered && this.extraCls){
4931 var t = c.getPositionEl ? c.getPositionEl() : c;
4932 t.removeClass(this.extraCls);
4937 onResize: function(){
4938 var ct = this.container,
4939 b = ct.bufferResize;
4945 // Not having an ownerCt negates the buffering: floating and top level
4946 // Containers (Viewport, Window, ToolTip, Menu) need to lay out ASAP.
4947 if (b && ct.ownerCt) {
4948 // If we do NOT already have a layout pending from an ancestor, schedule one.
4949 // If there is a layout pending, we do nothing here.
4950 // buffering to be deprecated soon
4951 if (!ct.hasLayoutPending()){
4952 if(!this.resizeTask){
4953 this.resizeTask = new Ext.util.DelayedTask(this.runLayout, this);
4954 this.resizeBuffer = Ext.isNumber(b) ? b : 50;
4956 ct.layoutPending = true;
4957 this.resizeTask.delay(this.resizeBuffer);
4960 ct.doLayout(false, this.forceLayout);
4965 runLayout: function(){
4966 var ct = this.container;
4968 delete ct.layoutPending;
4972 setContainer : function(ct){
4973 // No longer use events to handle resize. Instead this will be handled through a direct function call.
4975 if(this.monitorResize && ct != this.container){
4976 var old = this.container;
4978 old.un(old.resizeEvent, this.onResize, this);
4981 ct.on(ct.resizeEvent, this.onResize, this);
4985 this.container = ct;
4989 parseMargins : function(v){
4990 if(Ext.isNumber(v)){
4993 var ms = v.split(' ');
4994 var len = ms.length;
5008 top:parseInt(ms[0], 10) || 0,
5009 right:parseInt(ms[1], 10) || 0,
5010 bottom:parseInt(ms[2], 10) || 0,
5011 left:parseInt(ms[3], 10) || 0
5016 * The {@link Ext.Template Ext.Template} used by Field rendering layout classes (such as
5017 * {@link Ext.layout.FormLayout}) to create the DOM structure of a fully wrapped,
5018 * labeled and styled form Field. A default Template is supplied, but this may be
5019 * overriden to create custom field structures. The template processes values returned from
5020 * {@link Ext.layout.FormLayout#getTemplateArgs}.
5021 * @property fieldTpl
5022 * @type Ext.Template
5024 fieldTpl: (function() {
5025 var t = new Ext.Template(
5026 '<div class="x-form-item {itemCls}" tabIndex="-1">',
5027 '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{labelSeparator}</label>',
5028 '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
5029 '</div><div class="{clearCls}"></div>',
5032 t.disableFormats = true;
5037 * Destroys this layout. This is a template method that is empty by default, but should be implemented
5038 * by subclasses that require explicit destruction to purge event handlers or remove DOM nodes.
5041 destroy : function(){
5042 if(!Ext.isEmpty(this.targetCls)){
5043 var target = this.container.getLayoutTarget();
5045 target.removeClass(this.targetCls);
5050 Ext.Container.LAYOUTS['auto'] = Ext.layout.ContainerLayout;
5052 * @class Ext.layout.FitLayout
\r
5053 * @extends Ext.layout.ContainerLayout
\r
5054 * <p>This is a base class for layouts that contain <b>a single item</b> that automatically expands to fill the layout's
\r
5055 * container. This class is intended to be extended or created via the <tt>layout:'fit'</tt> {@link Ext.Container#layout}
\r
5056 * config, and should generally not need to be created directly via the new keyword.</p>
\r
5057 * <p>FitLayout does not have any direct config options (other than inherited ones). To fit a panel to a container
\r
5058 * using FitLayout, simply set layout:'fit' on the container and add a single panel to it. If the container has
\r
5059 * multiple panels, only the first one will be displayed. Example usage:</p>
\r
5061 var p = new Ext.Panel({
\r
5062 title: 'Fit Layout',
\r
5065 title: 'Inner Panel',
\r
5066 html: '<p>This is the inner panel content</p>',
\r
5072 Ext.layout.FitLayout = Ext.extend(Ext.layout.ContainerLayout, {
\r
5074 monitorResize:true,
\r
5077 onLayout : function(ct, target){
\r
5078 Ext.layout.FitLayout.superclass.onLayout.call(this, ct, target);
\r
5079 if(!this.container.collapsed){
\r
5080 this.setItemSize(this.activeItem || ct.items.itemAt(0), target.getViewSize(true));
\r
5085 setItemSize : function(item, size){
\r
5086 if(item && size.height > 0){ // display none?
\r
5087 item.setSize(size);
\r
5091 Ext.Container.LAYOUTS['fit'] = Ext.layout.FitLayout;/**
\r
5092 * @class Ext.layout.CardLayout
\r
5093 * @extends Ext.layout.FitLayout
\r
5094 * <p>This layout manages multiple child Components, each fitted to the Container, where only a single child Component can be
\r
5095 * visible at any given time. This layout style is most commonly used for wizards, tab implementations, etc.
\r
5096 * This class is intended to be extended or created via the layout:'card' {@link Ext.Container#layout} config,
\r
5097 * and should generally not need to be created directly via the new keyword.</p>
\r
5098 * <p>The CardLayout's focal method is {@link #setActiveItem}. Since only one panel is displayed at a time,
\r
5099 * the only way to move from one Component to the next is by calling setActiveItem, passing the id or index of
\r
5100 * the next panel to display. The layout itself does not provide a user interface for handling this navigation,
\r
5101 * so that functionality must be provided by the developer.</p>
\r
5102 * <p>In the following example, a simplistic wizard setup is demonstrated. A button bar is added
\r
5103 * to the footer of the containing panel to provide navigation buttons. The buttons will be handled by a
\r
5104 * common navigation routine -- for this example, the implementation of that routine has been ommitted since
\r
5105 * it can be any type of custom logic. Note that other uses of a CardLayout (like a tab control) would require a
\r
5106 * completely different implementation. For serious implementations, a better approach would be to extend
\r
5107 * CardLayout to provide the custom functionality needed. Example usage:</p>
\r
5109 var navHandler = function(direction){
\r
5110 // This routine could contain business logic required to manage the navigation steps.
\r
5111 // It would call setActiveItem as needed, manage navigation button state, handle any
\r
5112 // branching logic that might be required, handle alternate actions like cancellation
\r
5113 // or finalization, etc. A complete wizard implementation could get pretty
\r
5114 // sophisticated depending on the complexity required, and should probably be
\r
5115 // done as a subclass of CardLayout in a real-world implementation.
\r
5118 var card = new Ext.Panel({
\r
5119 title: 'Example Wizard',
\r
5121 activeItem: 0, // make sure the active item is set on the container config!
\r
5122 bodyStyle: 'padding:15px',
\r
5124 // applied to each contained panel
\r
5127 // just an example of one possible navigation scheme, using buttons
\r
5132 handler: navHandler.createDelegate(this, [-1]),
\r
5135 '->', // greedy spacer so that the buttons are aligned to each side
\r
5139 handler: navHandler.createDelegate(this, [1])
\r
5142 // the panels (or "cards") within the layout
\r
5145 html: '<h1>Welcome to the Wizard!</h1><p>Step 1 of 3</p>'
\r
5148 html: '<p>Step 2 of 3</p>'
\r
5151 html: '<h1>Congratulations!</h1><p>Step 3 of 3 - Complete</p>'
\r
5156 Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, {
\r
5158 * @cfg {Boolean} deferredRender
\r
5159 * True to render each contained item at the time it becomes active, false to render all contained items
\r
5160 * as soon as the layout is rendered (defaults to false). If there is a significant amount of content or
\r
5161 * a lot of heavy controls being rendered into panels that are not displayed by default, setting this to
\r
5162 * true might improve performance.
\r
5164 deferredRender : false,
\r
5167 * @cfg {Boolean} layoutOnCardChange
\r
5168 * True to force a layout of the active item when the active card is changed. Defaults to false.
\r
5170 layoutOnCardChange : false,
\r
5173 * @cfg {Boolean} renderHidden @hide
\r
5176 renderHidden : true,
\r
5178 constructor: function(config){
\r
5179 Ext.layout.CardLayout.superclass.constructor.call(this, config);
\r
5180 // this.forceLayout = (this.deferredRender === false);
\r
5184 * Sets the active (visible) item in the layout.
\r
5185 * @param {String/Number} item The string component id or numeric index of the item to activate
\r
5187 setActiveItem : function(item){
\r
5188 var ai = this.activeItem;
\r
5189 item = this.container.getComponent(item);
\r
5193 ai.fireEvent('deactivate', ai);
\r
5195 var layout = item.doLayout && (this.layoutOnCardChange || !item.rendered);
\r
5196 this.activeItem = item;
\r
5201 if(item && layout){
\r
5204 item.fireEvent('activate', item);
\r
5209 renderAll : function(ct, target){
\r
5210 if(this.deferredRender){
\r
5211 this.renderItem(this.activeItem, undefined, target);
\r
5213 Ext.layout.CardLayout.superclass.renderAll.call(this, ct, target);
\r
5217 Ext.Container.LAYOUTS['card'] = Ext.layout.CardLayout;/**
5218 * @class Ext.layout.AnchorLayout
5219 * @extends Ext.layout.ContainerLayout
5220 * <p>This is a layout that enables anchoring of contained elements relative to the container's dimensions.
5221 * If the container is resized, all anchored items are automatically rerendered according to their
5222 * <b><tt>{@link #anchor}</tt></b> rules.</p>
5223 * <p>This class is intended to be extended or created via the layout:'anchor' {@link Ext.Container#layout}
5224 * config, and should generally not need to be created directly via the new keyword.</p>
5225 * <p>AnchorLayout does not have any direct config options (other than inherited ones). By default,
5226 * AnchorLayout will calculate anchor measurements based on the size of the container itself. However, the
5227 * container using the AnchorLayout can supply an anchoring-specific config property of <b>anchorSize</b>.
5228 * If anchorSize is specifed, the layout will use it as a virtual container for the purposes of calculating
5229 * anchor measurements based on it instead, allowing the container to be sized independently of the anchoring
5230 * logic if necessary. For example:</p>
5232 var viewport = new Ext.Viewport({
5234 anchorSize: {width:800, height:600},
5254 Ext.layout.AnchorLayout = Ext.extend(Ext.layout.ContainerLayout, {
5256 * @cfg {String} anchor
5257 * <p>This configuation option is to be applied to <b>child <tt>items</tt></b> of a container managed by
5258 * this layout (ie. configured with <tt>layout:'anchor'</tt>).</p><br/>
5260 * <p>This value is what tells the layout how an item should be anchored to the container. <tt>items</tt>
5261 * added to an AnchorLayout accept an anchoring-specific config property of <b>anchor</b> which is a string
5262 * containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%').
5263 * The following types of anchor values are supported:<div class="mdetail-params"><ul>
5265 * <li><b>Percentage</b> : Any value between 1 and 100, expressed as a percentage.<div class="sub-desc">
5266 * The first anchor is the percentage width that the item should take up within the container, and the
5267 * second is the percentage height. For example:<pre><code>
5268 // two values specified
5269 anchor: '100% 50%' // render item complete width of the container and
5270 // 1/2 height of the container
5271 // one value specified
5272 anchor: '100%' // the width value; the height will default to auto
5273 * </code></pre></div></li>
5275 * <li><b>Offsets</b> : Any positive or negative integer value.<div class="sub-desc">
5276 * This is a raw adjustment where the first anchor is the offset from the right edge of the container,
5277 * and the second is the offset from the bottom edge. For example:<pre><code>
5278 // two values specified
5279 anchor: '-50 -100' // render item the complete width of the container
5280 // minus 50 pixels and
5281 // the complete height minus 100 pixels.
5282 // one value specified
5283 anchor: '-50' // anchor value is assumed to be the right offset value
5284 // bottom offset will default to 0
5285 * </code></pre></div></li>
5287 * <li><b>Sides</b> : Valid values are <tt>'right'</tt> (or <tt>'r'</tt>) and <tt>'bottom'</tt>
5288 * (or <tt>'b'</tt>).<div class="sub-desc">
5289 * Either the container must have a fixed size or an anchorSize config value defined at render time in
5290 * order for these to have any effect.</div></li>
5292 * <li><b>Mixed</b> : <div class="sub-desc">
5293 * Anchor values can also be mixed as needed. For example, to render the width offset from the container
5294 * right edge by 50 pixels and 75% of the container's height use:
5297 * </code></pre></div></li>
5308 getAnchorViewSize : function(ct, target){
5309 return target.dom == document.body ?
5310 target.getViewSize(true) : target.getStyleSize();
5314 onLayout : function(ct, target){
5315 Ext.layout.AnchorLayout.superclass.onLayout.call(this, ct, target);
5317 var size = target.getViewSize(true);
5319 var w = size.width, h = size.height;
5321 if(w < 20 && h < 20){
5325 // find the container anchoring size
5328 if(typeof ct.anchorSize == 'number'){
5331 aw = ct.anchorSize.width;
5332 ah = ct.anchorSize.height;
5335 aw = ct.initialConfig.width;
5336 ah = ct.initialConfig.height;
5339 var cs = ct.items.items, len = cs.length, i, c, a, cw, ch, el, vs;
5340 for(i = 0; i < len; i++){
5342 el = c.getPositionEl();
5345 if(!a){ // cache all anchor values
5346 vs = c.anchor.split(' ');
5347 c.anchorSpec = a = {
5348 right: this.parseAnchor(vs[0], c.initialConfig.width, aw),
5349 bottom: this.parseAnchor(vs[1], c.initialConfig.height, ah)
5352 cw = a.right ? this.adjustWidthAnchor(a.right(w) - el.getMargins('lr'), c) : undefined;
5353 ch = a.bottom ? this.adjustHeightAnchor(a.bottom(h) - el.getMargins('tb'), c) : undefined;
5356 c.setSize(cw || undefined, ch || undefined);
5363 parseAnchor : function(a, start, cstart){
5364 if(a && a != 'none'){
5366 if(/^(r|right|b|bottom)$/i.test(a)){ // standard anchor
5367 var diff = cstart - start;
5374 }else if(a.indexOf('%') != -1){
5375 var ratio = parseFloat(a.replace('%', ''))*.01; // percentage
5379 return Math.floor(v*ratio);
5383 a = parseInt(a, 10);
5384 if(!isNaN(a)){ // simple offset adjustment
5398 adjustWidthAnchor : function(value, comp){
5403 adjustHeightAnchor : function(value, comp){
5408 * @property activeItem
5412 Ext.Container.LAYOUTS['anchor'] = Ext.layout.AnchorLayout;
5414 * @class Ext.layout.ColumnLayout
\r
5415 * @extends Ext.layout.ContainerLayout
\r
5416 * <p>This is the layout style of choice for creating structural layouts in a multi-column format where the width of
\r
5417 * each column can be specified as a percentage or fixed width, but the height is allowed to vary based on the content.
\r
5418 * This class is intended to be extended or created via the layout:'column' {@link Ext.Container#layout} config,
\r
5419 * and should generally not need to be created directly via the new keyword.</p>
\r
5420 * <p>ColumnLayout does not have any direct config options (other than inherited ones), but it does support a
\r
5421 * specific config property of <b><tt>columnWidth</tt></b> that can be included in the config of any panel added to it. The
\r
5422 * layout will use the columnWidth (if present) or width of each panel during layout to determine how to size each panel.
\r
5423 * If width or columnWidth is not specified for a given panel, its width will default to the panel's width (or auto).</p>
\r
5424 * <p>The width property is always evaluated as pixels, and must be a number greater than or equal to 1.
\r
5425 * The columnWidth property is always evaluated as a percentage, and must be a decimal value greater than 0 and
\r
5426 * less than 1 (e.g., .25).</p>
\r
5427 * <p>The basic rules for specifying column widths are pretty simple. The logic makes two passes through the
\r
5428 * set of contained panels. During the first layout pass, all panels that either have a fixed width or none
\r
5429 * specified (auto) are skipped, but their widths are subtracted from the overall container width. During the second
\r
5430 * pass, all panels with columnWidths are assigned pixel widths in proportion to their percentages based on
\r
5431 * the total <b>remaining</b> container width. In other words, percentage width panels are designed to fill the space
\r
5432 * left over by all the fixed-width and/or auto-width panels. Because of this, while you can specify any number of columns
\r
5433 * with different percentages, the columnWidths must always add up to 1 (or 100%) when added together, otherwise your
\r
5434 * layout may not render as expected. Example usage:</p>
\r
5436 // All columns are percentages -- they must add up to 1
\r
5437 var p = new Ext.Panel({
\r
5438 title: 'Column Layout - Percentage Only',
\r
5441 title: 'Column 1',
\r
5444 title: 'Column 2',
\r
5447 title: 'Column 3',
\r
5452 // Mix of width and columnWidth -- all columnWidth values must add up
\r
5453 // to 1. The first column will take up exactly 120px, and the last two
\r
5454 // columns will fill the remaining container width.
\r
5455 var p = new Ext.Panel({
\r
5456 title: 'Column Layout - Mixed',
\r
5459 title: 'Column 1',
\r
5462 title: 'Column 2',
\r
5465 title: 'Column 3',
\r
5471 Ext.layout.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, {
\r
5473 monitorResize:true,
\r
5475 extraCls: 'x-column',
\r
5481 targetCls: 'x-column-layout-ct',
\r
5483 isValidParent : function(c, target){
\r
5484 return c.getPositionEl().dom.parentNode == this.innerCt.dom;
\r
5488 onLayout : function(ct, target){
\r
5489 var cs = ct.items.items, len = cs.length, c, i;
\r
5491 if(!this.innerCt){
\r
5492 // the innerCt prevents wrapping and shuffling while
\r
5493 // the container is resizing
\r
5494 this.innerCt = target.createChild({cls:'x-column-inner'});
\r
5495 this.innerCt.createChild({cls:'x-clear'});
\r
5497 this.renderAll(ct, this.innerCt);
\r
5499 var size = target.getViewSize(true);
\r
5501 if(size.width < 1 && size.height < 1){ // display none?
\r
5505 var w = size.width - this.scrollOffset,
\r
5509 this.innerCt.setWidth(w);
\r
5511 // some columns can be percentages while others are fixed
\r
5512 // so we need to make 2 passes
\r
5514 for(i = 0; i < len; i++){
\r
5516 if(!c.columnWidth){
\r
5517 pw -= (c.getSize().width + c.getPositionEl().getMargins('lr'));
\r
5521 pw = pw < 0 ? 0 : pw;
\r
5523 for(i = 0; i < len; i++){
\r
5525 if(c.columnWidth){
\r
5526 c.setSize(Math.floor(c.columnWidth * pw) - c.getPositionEl().getMargins('lr'));
\r
5532 * @property activeItem
\r
5537 Ext.Container.LAYOUTS['column'] = Ext.layout.ColumnLayout;/**
5538 * @class Ext.layout.BorderLayout
5539 * @extends Ext.layout.ContainerLayout
5540 * <p>This is a multi-pane, application-oriented UI layout style that supports multiple
5541 * nested panels, automatic {@link Ext.layout.BorderLayout.Region#split split} bars between
5542 * {@link Ext.layout.BorderLayout.Region#BorderLayout.Region regions} and built-in
5543 * {@link Ext.layout.BorderLayout.Region#collapsible expanding and collapsing} of regions.</p>
5544 * <p>This class is intended to be extended or created via the <tt>layout:'border'</tt>
5545 * {@link Ext.Container#layout} config, and should generally not need to be created directly
5546 * via the new keyword.</p>
5547 * <p>BorderLayout does not have any direct config options (other than inherited ones).
5548 * All configuration options available for customizing the BorderLayout are at the
5549 * {@link Ext.layout.BorderLayout.Region} and {@link Ext.layout.BorderLayout.SplitRegion}
5551 * <p>Example usage:</p>
5553 var myBorderPanel = new Ext.Panel({
5554 {@link Ext.Component#renderTo renderTo}: document.body,
5555 {@link Ext.BoxComponent#width width}: 700,
5556 {@link Ext.BoxComponent#height height}: 500,
5557 {@link Ext.Panel#title title}: 'Border Layout',
5558 {@link Ext.Container#layout layout}: 'border',
5559 {@link Ext.Container#items items}: [{
5560 {@link Ext.Panel#title title}: 'South Region is resizable',
5561 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'south', // position for region
5562 {@link Ext.BoxComponent#height height}: 100,
5563 {@link Ext.layout.BorderLayout.Region#split split}: true, // enable resizing
5564 {@link Ext.SplitBar#minSize minSize}: 75, // defaults to {@link Ext.layout.BorderLayout.Region#minHeight 50}
5565 {@link Ext.SplitBar#maxSize maxSize}: 150,
5566 {@link Ext.layout.BorderLayout.Region#margins margins}: '0 5 5 5'
5568 // xtype: 'panel' implied by default
5569 {@link Ext.Panel#title title}: 'West Region is collapsible',
5570 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}:'west',
5571 {@link Ext.layout.BorderLayout.Region#margins margins}: '5 0 0 5',
5572 {@link Ext.BoxComponent#width width}: 200,
5573 {@link Ext.layout.BorderLayout.Region#collapsible collapsible}: true, // make collapsible
5574 {@link Ext.layout.BorderLayout.Region#cmargins cmargins}: '5 5 0 5', // adjust top margin when collapsed
5575 {@link Ext.Component#id id}: 'west-region-container',
5576 {@link Ext.Container#layout layout}: 'fit',
5577 {@link Ext.Panel#unstyled unstyled}: true
5579 {@link Ext.Panel#title title}: 'Center Region',
5580 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'center', // center region is required, no width/height specified
5581 {@link Ext.Component#xtype xtype}: 'container',
5582 {@link Ext.Container#layout layout}: 'fit',
5583 {@link Ext.layout.BorderLayout.Region#margins margins}: '5 5 0 0'
5587 * <p><b><u>Notes</u></b>:</p><div class="mdetail-params"><ul>
5588 * <li>Any container using the BorderLayout <b>must</b> have a child item with <tt>region:'center'</tt>.
5589 * The child item in the center region will always be resized to fill the remaining space not used by
5590 * the other regions in the layout.</li>
5591 * <li>Any child items with a region of <tt>west</tt> or <tt>east</tt> must have <tt>width</tt> defined
5592 * (an integer representing the number of pixels that the region should take up).</li>
5593 * <li>Any child items with a region of <tt>north</tt> or <tt>south</tt> must have <tt>height</tt> defined.</li>
5594 * <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
5595 * Components within a BorderLayout, have them wrapped by an additional Container which is directly
5596 * managed by the BorderLayout. If the region is to be collapsible, the Container used directly
5597 * by the BorderLayout manager should be a Panel. In the following example a Container (an Ext.Panel)
5598 * is added to the west region:
5599 * <div style="margin-left:16px"><pre><code>
5600 wrc = {@link Ext#getCmp Ext.getCmp}('west-region-container');
5601 wrc.{@link Ext.Panel#removeAll removeAll}();
5602 wrc.{@link Ext.Container#add add}({
5603 title: 'Added Panel',
5604 html: 'Some content'
5606 wrc.{@link Ext.Container#doLayout doLayout}();
5607 * </code></pre></div>
5609 * <li> To reference a {@link Ext.layout.BorderLayout.Region Region}:
5610 * <div style="margin-left:16px"><pre><code>
5611 wr = myBorderPanel.layout.west;
5612 * </code></pre></div>
5616 Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {
5622 targetCls: 'x-border-layout-ct',
5625 onLayout : function(ct, target){
5628 var items = ct.items.items;
5630 for(var i = 0, len = items.length; i < len; i++) {
5636 c.collapsed = false;
5638 c.render(target, i);
5639 c.getPositionEl().addClass('x-border-panel');
5641 this[pos] = pos != 'center' && c.split ?
5642 new Ext.layout.BorderLayout.SplitRegion(this, c.initialConfig, pos) :
5643 new Ext.layout.BorderLayout.Region(this, c.initialConfig, pos);
5644 this[pos].render(target, c);
5646 this.rendered = true;
5649 var size = target.getViewSize(false);
5650 if(size.width < 20 || size.height < 20){ // display none?
5652 this.restoreCollapsed = collapsed;
5655 }else if(this.restoreCollapsed){
5656 collapsed = this.restoreCollapsed;
5657 delete this.restoreCollapsed;
5660 var w = size.width, h = size.height;
5661 var centerW = w, centerH = h, centerY = 0, centerX = 0;
5663 var n = this.north, s = this.south, west = this.west, e = this.east, c = this.center;
5664 if(!c && Ext.layout.BorderLayout.WARN !== false){
5665 throw 'No center region defined in BorderLayout ' + ct.id;
5668 if(n && n.isVisible()){
5669 var b = n.getSize();
5670 var m = n.getMargins();
5671 b.width = w - (m.left+m.right);
5674 centerY = b.height + b.y + m.bottom;
5678 if(s && s.isVisible()){
5679 var b = s.getSize();
5680 var m = s.getMargins();
5681 b.width = w - (m.left+m.right);
5683 var totalHeight = (b.height + m.top + m.bottom);
5684 b.y = h - totalHeight + m.top;
5685 centerH -= totalHeight;
5688 if(west && west.isVisible()){
5689 var b = west.getSize();
5690 var m = west.getMargins();
5691 b.height = centerH - (m.top+m.bottom);
5693 b.y = centerY + m.top;
5694 var totalWidth = (b.width + m.left + m.right);
5695 centerX += totalWidth;
5696 centerW -= totalWidth;
5697 west.applyLayout(b);
5699 if(e && e.isVisible()){
5700 var b = e.getSize();
5701 var m = e.getMargins();
5702 b.height = centerH - (m.top+m.bottom);
5703 var totalWidth = (b.width + m.left + m.right);
5704 b.x = w - totalWidth + m.left;
5705 b.y = centerY + m.top;
5706 centerW -= totalWidth;
5710 var m = c.getMargins();
5712 x: centerX + m.left,
5714 width: centerW - (m.left+m.right),
5715 height: centerH - (m.top+m.bottom)
5717 c.applyLayout(centerBox);
5720 for(var i = 0, len = collapsed.length; i < len; i++){
5721 collapsed[i].collapse(false);
5724 if(Ext.isIE && Ext.isStrict){ // workaround IE strict repainting issue
5729 destroy: function() {
5730 var r = ['north', 'south', 'east', 'west'];
5731 for (var i = 0; i < r.length; i++) {
5732 var region = this[r[i]];
5736 }else if (region.split){
5737 region.split.destroy(true);
5741 Ext.layout.BorderLayout.superclass.destroy.call(this);
5745 * @property activeItem
5751 * @class Ext.layout.BorderLayout.Region
5752 * <p>This is a region of a {@link Ext.layout.BorderLayout BorderLayout} that acts as a subcontainer
5753 * within the layout. Each region has its own {@link Ext.layout.ContainerLayout layout} that is
5754 * independent of other regions and the containing BorderLayout, and can be any of the
5755 * {@link Ext.layout.ContainerLayout valid Ext layout types}.</p>
5756 * <p>Region size is managed automatically and cannot be changed by the user -- for
5757 * {@link #split resizable regions}, see {@link Ext.layout.BorderLayout.SplitRegion}.</p>
5759 * Create a new Region.
5760 * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region.
5761 * @param {Object} config The configuration options
5762 * @param {String} position The region position. Valid values are: <tt>north</tt>, <tt>south</tt>,
5763 * <tt>east</tt>, <tt>west</tt> and <tt>center</tt>. Every {@link Ext.layout.BorderLayout BorderLayout}
5764 * <b>must have a center region</b> for the primary content -- all other regions are optional.
5766 Ext.layout.BorderLayout.Region = function(layout, config, pos){
5767 Ext.apply(this, config);
5768 this.layout = layout;
5769 this.position = pos;
5771 if(typeof this.margins == 'string'){
5772 this.margins = this.layout.parseMargins(this.margins);
5774 this.margins = Ext.applyIf(this.margins || {}, this.defaultMargins);
5775 if(this.collapsible){
5776 if(typeof this.cmargins == 'string'){
5777 this.cmargins = this.layout.parseMargins(this.cmargins);
5779 if(this.collapseMode == 'mini' && !this.cmargins){
5780 this.cmargins = {left:0,top:0,right:0,bottom:0};
5782 this.cmargins = Ext.applyIf(this.cmargins || {},
5783 pos == 'north' || pos == 'south' ? this.defaultNSCMargins : this.defaultEWCMargins);
5788 Ext.layout.BorderLayout.Region.prototype = {
5790 * @cfg {Boolean} animFloat
5791 * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated
5792 * panel that will close again once the user mouses out of that panel (or clicks out if
5793 * <tt>{@link #autoHide} = false</tt>). Setting <tt>{@link #animFloat} = false</tt> will
5794 * prevent the open and close of these floated panels from being animated (defaults to <tt>true</tt>).
5797 * @cfg {Boolean} autoHide
5798 * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated
5799 * panel. If <tt>autoHide = true</tt>, the panel will automatically hide after the user mouses
5800 * out of the panel. If <tt>autoHide = false</tt>, the panel will continue to display until the
5801 * user clicks outside of the panel (defaults to <tt>true</tt>).
5804 * @cfg {String} collapseMode
5805 * <tt>collapseMode</tt> supports two configuration values:<div class="mdetail-params"><ul>
5806 * <li><b><tt>undefined</tt></b> (default)<div class="sub-desc">By default, {@link #collapsible}
5807 * regions are collapsed by clicking the expand/collapse tool button that renders into the region's
5808 * title bar.</div></li>
5809 * <li><b><tt>'mini'</tt></b><div class="sub-desc">Optionally, when <tt>collapseMode</tt> is set to
5810 * <tt>'mini'</tt> the region's split bar will also display a small collapse button in the center of
5811 * the bar. In <tt>'mini'</tt> mode the region will collapse to a thinner bar than in normal mode.
5814 * <p><b>Note</b>: if a collapsible region does not have a title bar, then set <tt>collapseMode =
5815 * 'mini'</tt> and <tt>{@link #split} = true</tt> in order for the region to be {@link #collapsible}
5816 * by the user as the expand/collapse tool button (that would go in the title bar) will not be rendered.</p>
5817 * <p>See also <tt>{@link #cmargins}</tt>.</p>
5820 * @cfg {Object} margins
5821 * An object containing margins to apply to the region when in the expanded state in the
5822 * format:<pre><code>
5825 right: (right margin),
5826 bottom: (bottom margin),
5829 * <p>May also be a string containing space-separated, numeric margin values. The order of the
5830 * sides associated with each value matches the way CSS processes margin values:</p>
5831 * <p><div class="mdetail-params"><ul>
5832 * <li>If there is only one value, it applies to all sides.</li>
5833 * <li>If there are two values, the top and bottom borders are set to the first value and the
5834 * right and left are set to the second.</li>
5835 * <li>If there are three values, the top is set to the first value, the left and right are set
5836 * to the second, and the bottom is set to the third.</li>
5837 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
5839 * <p>Defaults to:</p><pre><code>
5840 * {top:0, right:0, bottom:0, left:0}
5844 * @cfg {Object} cmargins
5845 * An object containing margins to apply to the region when in the collapsed state in the
5846 * format:<pre><code>
5849 right: (right margin),
5850 bottom: (bottom margin),
5853 * <p>May also be a string containing space-separated, numeric margin values. The order of the
5854 * sides associated with each value matches the way CSS processes margin values.</p>
5856 * <li>If there is only one value, it applies to all sides.</li>
5857 * <li>If there are two values, the top and bottom borders are set to the first value and the
5858 * right and left are set to the second.</li>
5859 * <li>If there are three values, the top is set to the first value, the left and right are set
5860 * to the second, and the bottom is set to the third.</li>
5861 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
5865 * @cfg {Boolean} collapsible
5866 * <p><tt>true</tt> to allow the user to collapse this region (defaults to <tt>false</tt>). If
5867 * <tt>true</tt>, an expand/collapse tool button will automatically be rendered into the title
5868 * bar of the region, otherwise the button will not be shown.</p>
5869 * <p><b>Note</b>: that a title bar is required to display the collapse/expand toggle button -- if
5870 * no <tt>title</tt> is specified for the region's panel, the region will only be collapsible if
5871 * <tt>{@link #collapseMode} = 'mini'</tt> and <tt>{@link #split} = true</tt>.
5873 collapsible : false,
5875 * @cfg {Boolean} split
5876 * <p><tt>true</tt> to create a {@link Ext.layout.BorderLayout.SplitRegion SplitRegion} and
5877 * display a 5px wide {@link Ext.SplitBar} between this region and its neighbor, allowing the user to
5878 * resize the regions dynamically. Defaults to <tt>false</tt> creating a
5879 * {@link Ext.layout.BorderLayout.Region Region}.</p><br>
5880 * <p><b>Notes</b>:</p><div class="mdetail-params"><ul>
5881 * <li>this configuration option is ignored if <tt>region='center'</tt></li>
5882 * <li>when <tt>split == true</tt>, it is common to specify a
5883 * <tt>{@link Ext.SplitBar#minSize minSize}</tt> and <tt>{@link Ext.SplitBar#maxSize maxSize}</tt>
5884 * for the {@link Ext.BoxComponent BoxComponent} representing the region. These are not native
5885 * configs of {@link Ext.BoxComponent BoxComponent}, and are used only by this class.</li>
5886 * <li>if <tt>{@link #collapseMode} = 'mini'</tt> requires <tt>split = true</tt> to reserve space
5887 * for the collapse tool</tt></li>
5892 * @cfg {Boolean} floatable
5893 * <tt>true</tt> to allow clicking a collapsed region's bar to display the region's panel floated
5894 * above the layout, <tt>false</tt> to force the user to fully expand a collapsed region by
5895 * clicking the expand button to see it again (defaults to <tt>true</tt>).
5899 * @cfg {Number} minWidth
5900 * <p>The minimum allowable width in pixels for this region (defaults to <tt>50</tt>).
5901 * <tt>maxWidth</tt> may also be specified.</p><br>
5902 * <p><b>Note</b>: setting the <tt>{@link Ext.SplitBar#minSize minSize}</tt> /
5903 * <tt>{@link Ext.SplitBar#maxSize maxSize}</tt> supersedes any specified
5904 * <tt>minWidth</tt> / <tt>maxWidth</tt>.</p>
5908 * @cfg {Number} minHeight
5909 * The minimum allowable height in pixels for this region (defaults to <tt>50</tt>)
5910 * <tt>maxHeight</tt> may also be specified.</p><br>
5911 * <p><b>Note</b>: setting the <tt>{@link Ext.SplitBar#minSize minSize}</tt> /
5912 * <tt>{@link Ext.SplitBar#maxSize maxSize}</tt> supersedes any specified
5913 * <tt>minHeight</tt> / <tt>maxHeight</tt>.</p>
5918 defaultMargins : {left:0,top:0,right:0,bottom:0},
5920 defaultNSCMargins : {left:5,top:5,right:5,bottom:5},
5922 defaultEWCMargins : {left:5,top:0,right:5,bottom:0},
5923 floatingZIndex: 100,
5926 * True if this region is collapsed. Read-only.
5930 isCollapsed : false,
5933 * This region's panel. Read-only.
5938 * This region's layout. Read-only.
5943 * This region's layout position (north, south, east, west or center). Read-only.
5945 * @property position
5949 render : function(ct, p){
5951 p.el.enableDisplayMode();
5955 var gs = p.getState, ps = this.position;
5956 p.getState = function(){
5957 return Ext.apply(gs.call(p) || {}, this.state);
5958 }.createDelegate(this);
5961 p.allowQueuedExpand = false;
5963 beforecollapse: this.beforeCollapse,
5964 collapse: this.onCollapse,
5965 beforeexpand: this.beforeExpand,
5966 expand: this.onExpand,
5971 if(this.collapsible || this.floatable){
5972 p.collapseEl = 'el';
5973 p.slideAnchor = this.getSlideAnchor();
5975 if(p.tools && p.tools.toggle){
5976 p.tools.toggle.addClass('x-tool-collapse-'+ps);
5977 p.tools.toggle.addClassOnOver('x-tool-collapse-'+ps+'-over');
5983 getCollapsedEl : function(){
5984 if(!this.collapsedEl){
5985 if(!this.toolTemplate){
5986 var tt = new Ext.Template(
5987 '<div class="x-tool x-tool-{id}"> </div>'
5989 tt.disableFormats = true;
5991 Ext.layout.BorderLayout.Region.prototype.toolTemplate = tt;
5993 this.collapsedEl = this.targetEl.createChild({
5994 cls: "x-layout-collapsed x-layout-collapsed-"+this.position,
5995 id: this.panel.id + '-xcollapsed'
5997 this.collapsedEl.enableDisplayMode('block');
5999 if(this.collapseMode == 'mini'){
6000 this.collapsedEl.addClass('x-layout-cmini-'+this.position);
6001 this.miniCollapsedEl = this.collapsedEl.createChild({
6002 cls: "x-layout-mini x-layout-mini-"+this.position, html: " "
6004 this.miniCollapsedEl.addClassOnOver('x-layout-mini-over');
6005 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
6006 this.collapsedEl.on('click', this.onExpandClick, this, {stopEvent:true});
6008 if(this.collapsible !== false && !this.hideCollapseTool) {
6009 var t = this.toolTemplate.append(
6010 this.collapsedEl.dom,
6011 {id:'expand-'+this.position}, true);
6012 t.addClassOnOver('x-tool-expand-'+this.position+'-over');
6013 t.on('click', this.onExpandClick, this, {stopEvent:true});
6015 if(this.floatable !== false || this.titleCollapse){
6016 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
6017 this.collapsedEl.on("click", this[this.floatable ? 'collapseClick' : 'onExpandClick'], this);
6021 return this.collapsedEl;
6025 onExpandClick : function(e){
6027 this.panel.expand(false);
6029 this.panel.expand();
6034 onCollapseClick : function(e){
6035 this.panel.collapse();
6039 beforeCollapse : function(p, animate){
6040 this.lastAnim = animate;
6042 this.splitEl.hide();
6044 this.getCollapsedEl().show();
6045 var el = this.panel.getEl();
6046 this.originalZIndex = el.getStyle('z-index');
6047 el.setStyle('z-index', 100);
6048 this.isCollapsed = true;
6049 this.layout.layout();
6053 onCollapse : function(animate){
6054 this.panel.el.setStyle('z-index', 1);
6055 if(this.lastAnim === false || this.panel.animCollapse === false){
6056 this.getCollapsedEl().dom.style.visibility = 'visible';
6058 this.getCollapsedEl().slideIn(this.panel.slideAnchor, {duration:.2});
6060 this.state.collapsed = true;
6061 this.panel.saveState();
6065 beforeExpand : function(animate){
6067 this.afterSlideIn();
6069 var c = this.getCollapsedEl();
6071 if(this.position == 'east' || this.position == 'west'){
6072 this.panel.setSize(undefined, c.getHeight());
6074 this.panel.setSize(c.getWidth(), undefined);
6077 c.dom.style.visibility = 'hidden';
6078 this.panel.el.setStyle('z-index', this.floatingZIndex);
6082 onExpand : function(){
6083 this.isCollapsed = false;
6085 this.splitEl.show();
6087 this.layout.layout();
6088 this.panel.el.setStyle('z-index', this.originalZIndex);
6089 this.state.collapsed = false;
6090 this.panel.saveState();
6094 collapseClick : function(e){
6096 e.stopPropagation();
6099 e.stopPropagation();
6105 onHide : function(){
6106 if(this.isCollapsed){
6107 this.getCollapsedEl().hide();
6108 }else if(this.splitEl){
6109 this.splitEl.hide();
6114 onShow : function(){
6115 if(this.isCollapsed){
6116 this.getCollapsedEl().show();
6117 }else if(this.splitEl){
6118 this.splitEl.show();
6123 * True if this region is currently visible, else false.
6126 isVisible : function(){
6127 return !this.panel.hidden;
6131 * Returns the current margins for this region. If the region is collapsed, the
6132 * {@link #cmargins} (collapsed margins) value will be returned, otherwise the
6133 * {@link #margins} value will be returned.
6134 * @return {Object} An object containing the element's margins: <tt>{left: (left
6135 * margin), top: (top margin), right: (right margin), bottom: (bottom margin)}</tt>
6137 getMargins : function(){
6138 return this.isCollapsed && this.cmargins ? this.cmargins : this.margins;
6142 * Returns the current size of this region. If the region is collapsed, the size of the
6143 * collapsedEl will be returned, otherwise the size of the region's panel will be returned.
6144 * @return {Object} An object containing the element's size: <tt>{width: (element width),
6145 * height: (element height)}</tt>
6147 getSize : function(){
6148 return this.isCollapsed ? this.getCollapsedEl().getSize() : this.panel.getSize();
6152 * Sets the specified panel as the container element for this region.
6153 * @param {Ext.Panel} panel The new panel
6155 setPanel : function(panel){
6160 * Returns the minimum allowable width for this region.
6161 * @return {Number} The minimum width
6163 getMinWidth: function(){
6164 return this.minWidth;
6168 * Returns the minimum allowable height for this region.
6169 * @return {Number} The minimum height
6171 getMinHeight: function(){
6172 return this.minHeight;
6176 applyLayoutCollapsed : function(box){
6177 var ce = this.getCollapsedEl();
6178 ce.setLeftTop(box.x, box.y);
6179 ce.setSize(box.width, box.height);
6183 applyLayout : function(box){
6184 if(this.isCollapsed){
6185 this.applyLayoutCollapsed(box);
6187 this.panel.setPosition(box.x, box.y);
6188 this.panel.setSize(box.width, box.height);
6193 beforeSlide: function(){
6194 this.panel.beforeEffect();
6198 afterSlide : function(){
6199 this.panel.afterEffect();
6203 initAutoHide : function(){
6204 if(this.autoHide !== false){
6205 if(!this.autoHideHd){
6206 var st = new Ext.util.DelayedTask(this.slideIn, this);
6208 "mouseout": function(e){
6209 if(!e.within(this.el, true)){
6213 "mouseover" : function(e){
6219 this.el.on(this.autoHideHd);
6220 this.collapsedEl.on(this.autoHideHd);
6225 clearAutoHide : function(){
6226 if(this.autoHide !== false){
6227 this.el.un("mouseout", this.autoHideHd.mouseout);
6228 this.el.un("mouseover", this.autoHideHd.mouseover);
6229 this.collapsedEl.un("mouseout", this.autoHideHd.mouseout);
6230 this.collapsedEl.un("mouseover", this.autoHideHd.mouseover);
6235 clearMonitor : function(){
6236 Ext.getDoc().un("click", this.slideInIf, this);
6240 * If this Region is {@link #floatable}, this method slides this Region into full visibility <i>over the top
6241 * of the center Region</i> where it floats until either {@link #slideIn} is called, or other regions of the layout
6242 * are clicked, or the mouse exits the Region.
6244 slideOut : function(){
6245 if(this.isSlid || this.el.hasActiveFx()){
6249 var ts = this.panel.tools;
6250 if(ts && ts.toggle){
6254 if(this.position == 'east' || this.position == 'west'){
6255 this.panel.setSize(undefined, this.collapsedEl.getHeight());
6257 this.panel.setSize(this.collapsedEl.getWidth(), undefined);
6259 this.restoreLT = [this.el.dom.style.left, this.el.dom.style.top];
6260 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
6261 this.el.setStyle("z-index", this.floatingZIndex+2);
6262 this.panel.el.replaceClass('x-panel-collapsed', 'x-panel-floating');
6263 if(this.animFloat !== false){
6265 this.el.slideIn(this.getSlideAnchor(), {
6266 callback: function(){
6268 this.initAutoHide();
6269 Ext.getDoc().on("click", this.slideInIf, this);
6275 this.initAutoHide();
6276 Ext.getDoc().on("click", this.slideInIf, this);
6281 afterSlideIn : function(){
6282 this.clearAutoHide();
6283 this.isSlid = false;
6284 this.clearMonitor();
6285 this.el.setStyle("z-index", "");
6286 this.panel.el.replaceClass('x-panel-floating', 'x-panel-collapsed');
6287 this.el.dom.style.left = this.restoreLT[0];
6288 this.el.dom.style.top = this.restoreLT[1];
6290 var ts = this.panel.tools;
6291 if(ts && ts.toggle){
6297 * If this Region is {@link #floatable}, and this Region has been slid into floating visibility, then this method slides
6298 * this region back into its collapsed state.
6300 slideIn : function(cb){
6301 if(!this.isSlid || this.el.hasActiveFx()){
6305 this.isSlid = false;
6306 if(this.animFloat !== false){
6308 this.el.slideOut(this.getSlideAnchor(), {
6309 callback: function(){
6312 this.afterSlideIn();
6320 this.afterSlideIn();
6325 slideInIf : function(e){
6326 if(!e.within(this.el)){
6356 getAnchor : function(){
6357 return this.anchors[this.position];
6361 getCollapseAnchor : function(){
6362 return this.canchors[this.position];
6366 getSlideAnchor : function(){
6367 return this.sanchors[this.position];
6371 getAlignAdj : function(){
6372 var cm = this.cmargins;
6373 switch(this.position){
6390 getExpandAdj : function(){
6391 var c = this.collapsedEl, cm = this.cmargins;
6392 switch(this.position){
6394 return [-(cm.right+c.getWidth()+cm.left), 0];
6397 return [cm.right+c.getWidth()+cm.left, 0];
6400 return [0, -(cm.top+cm.bottom+c.getHeight())];
6403 return [0, cm.top+cm.bottom+c.getHeight()];
6408 destroy : function(){
6409 Ext.destroy(this.miniCollapsedEl, this.collapsedEl);
6414 * @class Ext.layout.BorderLayout.SplitRegion
6415 * @extends Ext.layout.BorderLayout.Region
6416 * <p>This is a specialized type of {@link Ext.layout.BorderLayout.Region BorderLayout region} that
6417 * has a built-in {@link Ext.SplitBar} for user resizing of regions. The movement of the split bar
6418 * is configurable to move either {@link #tickSize smooth or incrementally}.</p>
6420 * Create a new SplitRegion.
6421 * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region.
6422 * @param {Object} config The configuration options
6423 * @param {String} position The region position. Valid values are: north, south, east, west and center. Every
6424 * BorderLayout must have a center region for the primary content -- all other regions are optional.
6426 Ext.layout.BorderLayout.SplitRegion = function(layout, config, pos){
6427 Ext.layout.BorderLayout.SplitRegion.superclass.constructor.call(this, layout, config, pos);
6429 this.applyLayout = this.applyFns[pos];
6432 Ext.extend(Ext.layout.BorderLayout.SplitRegion, Ext.layout.BorderLayout.Region, {
6434 * @cfg {Number} tickSize
6435 * The increment, in pixels by which to move this Region's {@link Ext.SplitBar SplitBar}.
6436 * By default, the {@link Ext.SplitBar SplitBar} moves smoothly.
6439 * @cfg {String} splitTip
6440 * The tooltip to display when the user hovers over a
6441 * {@link Ext.layout.BorderLayout.Region#collapsible non-collapsible} region's split bar
6442 * (defaults to <tt>"Drag to resize."</tt>). Only applies if
6443 * <tt>{@link #useSplitTips} = true</tt>.
6445 splitTip : "Drag to resize.",
6447 * @cfg {String} collapsibleSplitTip
6448 * The tooltip to display when the user hovers over a
6449 * {@link Ext.layout.BorderLayout.Region#collapsible collapsible} region's split bar
6450 * (defaults to "Drag to resize. Double click to hide."). Only applies if
6451 * <tt>{@link #useSplitTips} = true</tt>.
6453 collapsibleSplitTip : "Drag to resize. Double click to hide.",
6455 * @cfg {Boolean} useSplitTips
6456 * <tt>true</tt> to display a tooltip when the user hovers over a region's split bar
6457 * (defaults to <tt>false</tt>). The tooltip text will be the value of either
6458 * <tt>{@link #splitTip}</tt> or <tt>{@link #collapsibleSplitTip}</tt> as appropriate.
6460 useSplitTips : false,
6465 orientation: Ext.SplitBar.VERTICAL,
6466 placement: Ext.SplitBar.TOP,
6467 maxFn : 'getVMaxSize',
6468 minProp: 'minHeight',
6469 maxProp: 'maxHeight'
6472 orientation: Ext.SplitBar.VERTICAL,
6473 placement: Ext.SplitBar.BOTTOM,
6474 maxFn : 'getVMaxSize',
6475 minProp: 'minHeight',
6476 maxProp: 'maxHeight'
6479 orientation: Ext.SplitBar.HORIZONTAL,
6480 placement: Ext.SplitBar.RIGHT,
6481 maxFn : 'getHMaxSize',
6482 minProp: 'minWidth',
6486 orientation: Ext.SplitBar.HORIZONTAL,
6487 placement: Ext.SplitBar.LEFT,
6488 maxFn : 'getHMaxSize',
6489 minProp: 'minWidth',
6496 west : function(box){
6497 if(this.isCollapsed){
6498 return this.applyLayoutCollapsed(box);
6500 var sd = this.splitEl.dom, s = sd.style;
6501 this.panel.setPosition(box.x, box.y);
6502 var sw = sd.offsetWidth;
6503 s.left = (box.x+box.width-sw)+'px';
6504 s.top = (box.y)+'px';
6505 s.height = Math.max(0, box.height)+'px';
6506 this.panel.setSize(box.width-sw, box.height);
6508 east : function(box){
6509 if(this.isCollapsed){
6510 return this.applyLayoutCollapsed(box);
6512 var sd = this.splitEl.dom, s = sd.style;
6513 var sw = sd.offsetWidth;
6514 this.panel.setPosition(box.x+sw, box.y);
6515 s.left = (box.x)+'px';
6516 s.top = (box.y)+'px';
6517 s.height = Math.max(0, box.height)+'px';
6518 this.panel.setSize(box.width-sw, box.height);
6520 north : function(box){
6521 if(this.isCollapsed){
6522 return this.applyLayoutCollapsed(box);
6524 var sd = this.splitEl.dom, s = sd.style;
6525 var sh = sd.offsetHeight;
6526 this.panel.setPosition(box.x, box.y);
6527 s.left = (box.x)+'px';
6528 s.top = (box.y+box.height-sh)+'px';
6529 s.width = Math.max(0, box.width)+'px';
6530 this.panel.setSize(box.width, box.height-sh);
6532 south : function(box){
6533 if(this.isCollapsed){
6534 return this.applyLayoutCollapsed(box);
6536 var sd = this.splitEl.dom, s = sd.style;
6537 var sh = sd.offsetHeight;
6538 this.panel.setPosition(box.x, box.y+sh);
6539 s.left = (box.x)+'px';
6540 s.top = (box.y)+'px';
6541 s.width = Math.max(0, box.width)+'px';
6542 this.panel.setSize(box.width, box.height-sh);
6547 render : function(ct, p){
6548 Ext.layout.BorderLayout.SplitRegion.superclass.render.call(this, ct, p);
6550 var ps = this.position;
6552 this.splitEl = ct.createChild({
6553 cls: "x-layout-split x-layout-split-"+ps, html: " ",
6554 id: this.panel.id + '-xsplit'
6557 if(this.collapseMode == 'mini'){
6558 this.miniSplitEl = this.splitEl.createChild({
6559 cls: "x-layout-mini x-layout-mini-"+ps, html: " "
6561 this.miniSplitEl.addClassOnOver('x-layout-mini-over');
6562 this.miniSplitEl.on('click', this.onCollapseClick, this, {stopEvent:true});
6565 var s = this.splitSettings[ps];
6567 this.split = new Ext.SplitBar(this.splitEl.dom, p.el, s.orientation);
6568 this.split.tickSize = this.tickSize;
6569 this.split.placement = s.placement;
6570 this.split.getMaximumSize = this[s.maxFn].createDelegate(this);
6571 this.split.minSize = this.minSize || this[s.minProp];
6572 this.split.on("beforeapply", this.onSplitMove, this);
6573 this.split.useShim = this.useShim === true;
6574 this.maxSize = this.maxSize || this[s.maxProp];
6577 this.splitEl.hide();
6580 if(this.useSplitTips){
6581 this.splitEl.dom.title = this.collapsible ? this.collapsibleSplitTip : this.splitTip;
6583 if(this.collapsible){
6584 this.splitEl.on("dblclick", this.onCollapseClick, this);
6588 //docs inherit from superclass
6589 getSize : function(){
6590 if(this.isCollapsed){
6591 return this.collapsedEl.getSize();
6593 var s = this.panel.getSize();
6594 if(this.position == 'north' || this.position == 'south'){
6595 s.height += this.splitEl.dom.offsetHeight;
6597 s.width += this.splitEl.dom.offsetWidth;
6603 getHMaxSize : function(){
6604 var cmax = this.maxSize || 10000;
6605 var center = this.layout.center;
6606 return Math.min(cmax, (this.el.getWidth()+center.el.getWidth())-center.getMinWidth());
6610 getVMaxSize : function(){
6611 var cmax = this.maxSize || 10000;
6612 var center = this.layout.center;
6613 return Math.min(cmax, (this.el.getHeight()+center.el.getHeight())-center.getMinHeight());
6617 onSplitMove : function(split, newSize){
6618 var s = this.panel.getSize();
6619 this.lastSplitSize = newSize;
6620 if(this.position == 'north' || this.position == 'south'){
6621 this.panel.setSize(s.width, newSize);
6622 this.state.height = newSize;
6624 this.panel.setSize(newSize, s.height);
6625 this.state.width = newSize;
6627 this.layout.layout();
6628 this.panel.saveState();
6633 * Returns a reference to the split bar in use by this region.
6634 * @return {Ext.SplitBar} The split bar
6636 getSplitBar : function(){
6641 destroy : function() {
6642 Ext.destroy(this.miniSplitEl, this.split, this.splitEl);
6643 Ext.layout.BorderLayout.SplitRegion.superclass.destroy.call(this);
6647 Ext.Container.LAYOUTS['border'] = Ext.layout.BorderLayout;/**
6648 * @class Ext.layout.FormLayout
6649 * @extends Ext.layout.AnchorLayout
6650 * <p>This layout manager is specifically designed for rendering and managing child Components of
6651 * {@link Ext.form.FormPanel forms}. It is responsible for rendering the labels of
6652 * {@link Ext.form.Field Field}s.</p>
6654 * <p>This layout manager is used when a Container is configured with the <tt>layout:'form'</tt>
6655 * {@link Ext.Container#layout layout} config option, and should generally not need to be created directly
6656 * via the new keyword. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
6658 * <p>In an application, it will usually be preferrable to use a {@link Ext.form.FormPanel FormPanel}
6659 * (which is configured with FormLayout as its layout class by default) since it also provides built-in
6660 * functionality for {@link Ext.form.BasicForm#doAction loading, validating and submitting} the form.</p>
6662 * <p>A {@link Ext.Container Container} <i>using</i> the FormLayout layout manager (e.g.
6663 * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>) can also accept the following
6664 * layout-specific config properties:<div class="mdetail-params"><ul>
6665 * <li><b><tt>{@link Ext.form.FormPanel#hideLabels hideLabels}</tt></b></li>
6666 * <li><b><tt>{@link Ext.form.FormPanel#labelAlign labelAlign}</tt></b></li>
6667 * <li><b><tt>{@link Ext.form.FormPanel#labelPad labelPad}</tt></b></li>
6668 * <li><b><tt>{@link Ext.form.FormPanel#labelSeparator labelSeparator}</tt></b></li>
6669 * <li><b><tt>{@link Ext.form.FormPanel#labelWidth labelWidth}</tt></b></li>
6672 * <p>Any Component (including Fields) managed by FormLayout accepts the following as a config option:
6673 * <div class="mdetail-params"><ul>
6674 * <li><b><tt>{@link Ext.Component#anchor anchor}</tt></b></li>
6677 * <p>Any Component managed by FormLayout may be rendered as a form field (with an associated label) by
6678 * configuring it with a non-null <b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b>. Components configured
6679 * in this way may be configured with the following options which affect the way the FormLayout renders them:
6680 * <div class="mdetail-params"><ul>
6681 * <li><b><tt>{@link Ext.Component#clearCls clearCls}</tt></b></li>
6682 * <li><b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b></li>
6683 * <li><b><tt>{@link Ext.Component#hideLabel hideLabel}</tt></b></li>
6684 * <li><b><tt>{@link Ext.Component#itemCls itemCls}</tt></b></li>
6685 * <li><b><tt>{@link Ext.Component#labelSeparator labelSeparator}</tt></b></li>
6686 * <li><b><tt>{@link Ext.Component#labelStyle labelStyle}</tt></b></li>
6689 * <p>Example usage:</p>
6691 // Required if showing validation messages
6692 Ext.QuickTips.init();
6694 // While you can create a basic Panel with layout:'form', practically
6695 // you should usually use a FormPanel to also get its form functionality
6696 // since it already creates a FormLayout internally.
6697 var form = new Ext.form.FormPanel({
6698 title: 'Form Layout',
6699 bodyStyle: 'padding:15px',
6701 defaultType: 'textfield',
6703 // applied to each contained item
6708 fieldLabel: 'First Name',
6711 {@link Ext.Component#labelSeparator labelSeparator}: ':' // override labelSeparator layout config
6713 fieldLabel: 'Last Name',
6716 fieldLabel: 'Email',
6721 hideLabel: true, // override hideLabels layout config
6731 {@link #labelSeparator}: '~' // superseded by assignment below
6733 // config options applicable to container when layout='form':
6735 labelAlign: 'left', // or 'right' or 'top'
6736 {@link Ext.form.FormPanel#labelSeparator labelSeparator}: '>>', // takes precedence over layoutConfig value
6737 labelWidth: 65, // defaults to 100
6738 labelPad: 8 // defaults to 5, must specify labelWidth to be honored
6742 Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, {
6745 * @cfg {String} labelSeparator
6746 * See {@link Ext.form.FormPanel}.{@link Ext.form.FormPanel#labelSeparator labelSeparator}. Configuration
6747 * of this property at the <b>container</b> level takes precedence.
6749 labelSeparator : ':',
6752 * Read only. The CSS style specification string added to field labels in this layout if not
6753 * otherwise {@link Ext.Component#labelStyle specified by each contained field}.
6755 * @property labelStyle
6759 * @cfg {Boolean} trackLabels
6760 * True to show/hide the field label when the field is hidden. Defaults to <tt>false</tt>.
6765 onRemove: function(c){
6766 Ext.layout.FormLayout.superclass.onRemove.call(this, c);
6767 if(this.trackLabels){
6768 c.un('show', this.onFieldShow, this);
6769 c.un('hide', this.onFieldHide, this);
6771 // check for itemCt, since we may be removing a fieldset or something similar
6772 var el = c.getPositionEl(),
6773 ct = c.getItemCt && c.getItemCt();
6774 if(c.rendered && ct){
6779 Ext.destroyMembers(c, 'label', 'itemCt');
6781 Ext.destroyMembers(c, 'getItemCt', 'customItemCt');
6787 setContainer : function(ct){
6788 Ext.layout.FormLayout.superclass.setContainer.call(this, ct);
6790 ct.addClass('x-form-label-'+ct.labelAlign);
6795 labelStyle: 'display:none',
6796 elementStyle: 'padding-left:0;',
6800 this.labelSeparator = ct.labelSeparator || this.labelSeparator;
6801 ct.labelWidth = ct.labelWidth || 100;
6802 if(Ext.isNumber(ct.labelWidth)){
6803 var pad = Ext.isNumber(ct.labelPad) ? ct.labelPad : 5;
6805 labelAdjust: ct.labelWidth + pad,
6806 labelStyle: 'width:' + ct.labelWidth + 'px;',
6807 elementStyle: 'padding-left:' + (ct.labelWidth + pad) + 'px'
6810 if(ct.labelAlign == 'top'){
6812 labelStyle: 'width:auto;',
6814 elementStyle: 'padding-left:0;'
6821 isHide: function(c){
6822 return c.hideLabel || this.container.hideLabels;
6825 onFieldShow: function(c){
6826 c.getItemCt().removeClass('x-hide-' + c.hideMode);
6829 onFieldHide: function(c){
6830 c.getItemCt().addClass('x-hide-' + c.hideMode);
6834 getLabelStyle: function(s){
6835 var ls = '', items = [this.labelStyle, s];
6836 for (var i = 0, len = items.length; i < len; ++i){
6839 if (ls.substr(-1, 1) != ';'){
6848 * @cfg {Ext.Template} fieldTpl
6849 * A {@link Ext.Template#compile compile}d {@link Ext.Template} for rendering
6850 * the fully wrapped, labeled and styled form Field. Defaults to:</p><pre><code>
6852 '<div class="x-form-item {itemCls}" tabIndex="-1">',
6853 '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{labelSeparator}</label>',
6854 '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
6855 '</div><div class="{clearCls}"></div>',
6859 * <p>This may be specified to produce a different DOM structure when rendering form Fields.</p>
6860 * <p>A description of the properties within the template follows:</p><div class="mdetail-params"><ul>
6861 * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper
6862 * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt>
6863 * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt>
6864 * supplied at the container level.</div></li>
6865 * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li>
6866 * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc">
6867 * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the
6868 * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li>
6869 * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this
6870 * field (defaults to <tt>''</tt>)</div></li>
6871 * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after
6872 * the text of the label for this field (defaults to a colon <tt>':'</tt> or the
6873 * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li>
6874 * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li>
6875 * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div
6876 * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li>
6878 * <p>Also see <tt>{@link #getTemplateArgs}</tt></p>
6882 renderItem : function(c, position, target){
6883 if(c && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){
6884 var args = this.getTemplateArgs(c);
6885 if(Ext.isNumber(position)){
6886 position = target.dom.childNodes[position] || null;
6889 c.itemCt = this.fieldTpl.insertBefore(position, args, true);
6891 c.itemCt = this.fieldTpl.append(target, args, true);
6894 // Non form fields don't have getItemCt, apply it here
6895 // This will get cleaned up in onRemove
6897 getItemCt: function(){
6903 c.label = c.getItemCt().child('label.x-form-item-label');
6905 c.render('x-form-el-' + c.id);
6906 }else if(!this.isValidParent(c, target)){
6907 Ext.fly('x-form-el-' + c.id).appendChild(c.getPositionEl());
6909 if(this.trackLabels){
6911 this.onFieldHide(c);
6915 show: this.onFieldShow,
6916 hide: this.onFieldHide
6919 this.configureItem(c);
6921 Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments);
6926 * <p>Provides template arguments for rendering the fully wrapped, labeled and styled form Field.</p>
6927 * <p>This method returns an object hash containing properties used by the layout's {@link #fieldTpl}
6928 * to create a correctly wrapped, labeled and styled form Field. This may be overriden to
6929 * create custom layouts. The properties which must be returned are:</p><div class="mdetail-params"><ul>
6930 * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper
6931 * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt>
6932 * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt>
6933 * supplied at the container level.</div></li>
6934 * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li>
6935 * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc">
6936 * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the
6937 * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li>
6938 * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this
6939 * field (defaults to <tt>''</tt>)</div></li>
6940 * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after
6941 * the text of the label for this field (defaults to a colon <tt>':'</tt> or the
6942 * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li>
6943 * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li>
6944 * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div
6945 * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li>
6947 * @param (Ext.form.Field} field The {@link Ext.form.Field Field} being rendered.
6948 * @return An object hash containing the properties required to render the Field.
6950 getTemplateArgs: function(field) {
6951 var noLabelSep = !field.fieldLabel || field.hideLabel;
6954 label: field.fieldLabel,
6955 labelStyle: this.getLabelStyle(field.labelStyle),
6956 elementStyle: this.elementStyle||'',
6957 labelSeparator: noLabelSep ? '' : (Ext.isDefined(field.labelSeparator) ? field.labelSeparator : this.labelSeparator),
6958 itemCls: (field.itemCls||this.container.itemCls||'') + (field.hideLabel ? ' x-hide-label' : ''),
6959 clearCls: field.clearCls || 'x-form-clear-left'
6964 adjustWidthAnchor: function(value, c){
6965 if(c.label && !this.isHide(c) && (this.container.labelAlign != 'top')){
6966 var adjust = Ext.isIE6 || (Ext.isIE && !Ext.isStrict);
6967 return value - this.labelAdjust + (adjust ? -3 : 0);
6972 adjustHeightAnchor : function(value, c){
6973 if(c.label && !this.isHide(c) && (this.container.labelAlign == 'top')){
6974 return value - c.label.getHeight();
6980 isValidParent : function(c, target){
6981 return target && this.container.getEl().contains(c.getPositionEl());
6985 * @property activeItem
6990 Ext.Container.LAYOUTS['form'] = Ext.layout.FormLayout;
6992 * @class Ext.layout.AccordionLayout
\r
6993 * @extends Ext.layout.FitLayout
\r
6994 * <p>This is a layout that manages multiple Panels in an expandable accordion style such that only
\r
6995 * <b>one Panel can be expanded at any given time</b>. Each Panel has built-in support for expanding and collapsing.</p>
\r
6996 * <p>Note: Only Ext.Panels <b>and all subclasses of Ext.Panel</b> may be used in an accordion layout Container.</p>
\r
6997 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
\r
6998 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
\r
6999 * <p>Example usage:</p>
\r
7001 var accordion = new Ext.Panel({
\r
7002 title: 'Accordion Layout',
\r
7003 layout:'accordion',
\r
7005 // applied to each contained panel
\r
7006 bodyStyle: 'padding:15px'
\r
7009 // layout-specific configs go here
\r
7010 titleCollapse: false,
\r
7016 html: '<p>Panel content!</p>'
\r
7019 html: '<p>Panel content!</p>'
\r
7022 html: '<p>Panel content!</p>'
\r
7027 Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, {
\r
7029 * @cfg {Boolean} fill
\r
7030 * True to adjust the active item's height to fill the available space in the container, false to use the
\r
7031 * item's current height, or auto height if not explicitly set (defaults to true).
\r
7035 * @cfg {Boolean} autoWidth
\r
7036 * True to set each contained item's width to 'auto', false to use the item's current width (defaults to true).
\r
7037 * Note that some components, in particular the {@link Ext.grid.GridPanel grid}, will not function properly within
\r
7038 * layouts if they have auto width, so in such cases this config should be set to false.
\r
7042 * @cfg {Boolean} titleCollapse
\r
7043 * True to allow expand/collapse of each contained panel by clicking anywhere on the title bar, false to allow
\r
7044 * expand/collapse only when the toggle tool button is clicked (defaults to true). When set to false,
\r
7045 * {@link #hideCollapseTool} should be false also.
\r
7047 titleCollapse : true,
\r
7049 * @cfg {Boolean} hideCollapseTool
\r
7050 * True to hide the contained panels' collapse/expand toggle buttons, false to display them (defaults to false).
\r
7051 * When set to true, {@link #titleCollapse} should be true also.
\r
7053 hideCollapseTool : false,
\r
7055 * @cfg {Boolean} collapseFirst
\r
7056 * True to make sure the collapse/expand toggle button always renders first (to the left of) any other tools
\r
7057 * in the contained panels' title bars, false to render it last (defaults to false).
\r
7059 collapseFirst : false,
\r
7061 * @cfg {Boolean} animate
\r
7062 * True to slide the contained panels open and closed during expand/collapse using animation, false to open and
\r
7063 * close directly with no animation (defaults to false). Note: to defer to the specific config setting of each
\r
7064 * contained panel for this property, set this to undefined at the layout level.
\r
7068 * @cfg {Boolean} sequence
\r
7069 * <b>Experimental</b>. If animate is set to true, this will result in each animation running in sequence.
\r
7073 * @cfg {Boolean} activeOnTop
\r
7074 * True to swap the position of each panel as it is expanded so that it becomes the first item in the container,
\r
7075 * false to keep the panels in the rendered order. <b>This is NOT compatible with "animate:true"</b> (defaults to false).
\r
7077 activeOnTop : false,
\r
7079 renderItem : function(c){
\r
7080 if(this.animate === false){
\r
7081 c.animCollapse = false;
\r
7083 c.collapsible = true;
\r
7084 if(this.autoWidth){
\r
7085 c.autoWidth = true;
\r
7087 if(this.titleCollapse){
\r
7088 c.titleCollapse = true;
\r
7090 if(this.hideCollapseTool){
\r
7091 c.hideCollapseTool = true;
\r
7093 if(this.collapseFirst !== undefined){
\r
7094 c.collapseFirst = this.collapseFirst;
\r
7096 if(!this.activeItem && !c.collapsed){
\r
7097 this.setActiveItem(c, true);
\r
7098 }else if(this.activeItem && this.activeItem != c){
\r
7099 c.collapsed = true;
\r
7101 Ext.layout.AccordionLayout.superclass.renderItem.apply(this, arguments);
\r
7102 c.header.addClass('x-accordion-hd');
\r
7103 c.on('beforeexpand', this.beforeExpand, this);
\r
7106 onRemove: function(c){
\r
7107 Ext.layout.AccordionLayout.superclass.onRemove.call(this, c);
\r
7109 c.header.removeClass('x-accordion-hd');
\r
7111 c.un('beforeexpand', this.beforeExpand, this);
\r
7115 beforeExpand : function(p, anim){
\r
7116 var ai = this.activeItem;
\r
7118 if(this.sequence){
\r
7119 delete this.activeItem;
\r
7120 if (!ai.collapsed){
\r
7121 ai.collapse({callback:function(){
\r
7122 p.expand(anim || true);
\r
7127 ai.collapse(this.animate);
\r
7130 this.setActive(p);
\r
7131 if(this.activeOnTop){
\r
7132 p.el.dom.parentNode.insertBefore(p.el.dom, p.el.dom.parentNode.firstChild);
\r
7138 setItemSize : function(item, size){
\r
7139 if(this.fill && item){
\r
7141 this.container.items.each(function(p){
\r
7143 hh += p.header.getHeight();
\r
7146 size.height -= hh;
\r
7147 item.setSize(size);
\r
7152 * Sets the active (expanded) item in the layout.
\r
7153 * @param {String/Number} item The string component id or numeric index of the item to activate
\r
7155 setActiveItem : function(item){
\r
7156 this.setActive(item, true);
\r
7160 setActive : function(item, expand){
\r
7161 var ai = this.activeItem;
\r
7162 item = this.container.getComponent(item);
\r
7164 if(item.rendered && item.collapsed && expand){
\r
7168 ai.fireEvent('deactivate', ai);
\r
7170 this.activeItem = item;
\r
7171 item.fireEvent('activate', item);
\r
7176 Ext.Container.LAYOUTS.accordion = Ext.layout.AccordionLayout;
\r
7178 //backwards compat
\r
7179 Ext.layout.Accordion = Ext.layout.AccordionLayout;/**
\r
7180 * @class Ext.layout.TableLayout
\r
7181 * @extends Ext.layout.ContainerLayout
\r
7182 * <p>This layout allows you to easily render content into an HTML table. The total number of columns can be
\r
7183 * specified, and rowspan and colspan can be used to create complex layouts within the table.
\r
7184 * This class is intended to be extended or created via the layout:'table' {@link Ext.Container#layout} config,
\r
7185 * and should generally not need to be created directly via the new keyword.</p>
\r
7186 * <p>Note that when creating a layout via config, the layout-specific config properties must be passed in via
\r
7187 * the {@link Ext.Container#layoutConfig} object which will then be applied internally to the layout. In the
\r
7188 * case of TableLayout, the only valid layout config property is {@link #columns}. However, the items added to a
\r
7189 * TableLayout can supply the following table-specific config properties:</p>
\r
7191 * <li><b>rowspan</b> Applied to the table cell containing the item.</li>
\r
7192 * <li><b>colspan</b> Applied to the table cell containing the item.</li>
\r
7193 * <li><b>cellId</b> An id applied to the table cell containing the item.</li>
\r
7194 * <li><b>cellCls</b> A CSS class name added to the table cell containing the item.</li>
\r
7196 * <p>The basic concept of building up a TableLayout is conceptually very similar to building up a standard
\r
7197 * HTML table. You simply add each panel (or "cell") that you want to include along with any span attributes
\r
7198 * specified as the special config properties of rowspan and colspan which work exactly like their HTML counterparts.
\r
7199 * Rather than explicitly creating and nesting rows and columns as you would in HTML, you simply specify the
\r
7200 * total column count in the layoutConfig and start adding panels in their natural order from left to right,
\r
7201 * top to bottom. The layout will automatically figure out, based on the column count, rowspans and colspans,
\r
7202 * how to position each panel within the table. Just like with HTML tables, your rowspans and colspans must add
\r
7203 * up correctly in your overall layout or you'll end up with missing and/or extra cells! Example usage:</p>
\r
7205 // This code will generate a layout table that is 3 columns by 2 rows
\r
7206 // with some spanning included. The basic layout will be:
\r
7207 // +--------+-----------------+
\r
7209 // | |--------+--------|
\r
7211 // +--------+--------+--------+
\r
7212 var table = new Ext.Panel({
\r
7213 title: 'Table Layout',
\r
7216 // applied to each contained panel
\r
7217 bodyStyle:'padding:20px'
\r
7220 // The total column count must be specified here
\r
7224 html: '<p>Cell A content</p>',
\r
7227 html: '<p>Cell B content</p>',
\r
7230 html: '<p>Cell C content</p>',
\r
7231 cellCls: 'highlight'
\r
7233 html: '<p>Cell D content</p>'
\r
7238 Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, {
\r
7240 * @cfg {Number} columns
\r
7241 * The total number of columns to create in the table for this layout. If not specified, all Components added to
\r
7242 * this layout will be rendered into a single row using one column per Component.
\r
7246 monitorResize:false,
\r
7248 targetCls: 'x-table-layout-ct',
\r
7251 * @cfg {Object} tableAttrs
\r
7252 * <p>An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification
\r
7253 * used to create the layout's <tt><table></tt> element. Example:</p><pre><code>
\r
7270 setContainer : function(ct){
\r
7271 Ext.layout.TableLayout.superclass.setContainer.call(this, ct);
\r
7273 this.currentRow = 0;
\r
7274 this.currentColumn = 0;
\r
7279 onLayout : function(ct, target){
\r
7280 var cs = ct.items.items, len = cs.length, c, i;
\r
7283 this.table = target.createChild(
\r
7284 Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true);
\r
7286 this.renderAll(ct, target);
\r
7290 getRow : function(index){
\r
7291 var row = this.table.tBodies[0].childNodes[index];
\r
7293 row = document.createElement('tr');
\r
7294 this.table.tBodies[0].appendChild(row);
\r
7300 getNextCell : function(c){
\r
7301 var cell = this.getNextNonSpan(this.currentColumn, this.currentRow);
\r
7302 var curCol = this.currentColumn = cell[0], curRow = this.currentRow = cell[1];
\r
7303 for(var rowIndex = curRow; rowIndex < curRow + (c.rowspan || 1); rowIndex++){
\r
7304 if(!this.cells[rowIndex]){
\r
7305 this.cells[rowIndex] = [];
\r
7307 for(var colIndex = curCol; colIndex < curCol + (c.colspan || 1); colIndex++){
\r
7308 this.cells[rowIndex][colIndex] = true;
\r
7311 var td = document.createElement('td');
\r
7315 var cls = 'x-table-layout-cell';
\r
7317 cls += ' ' + c.cellCls;
\r
7319 td.className = cls;
\r
7321 td.colSpan = c.colspan;
\r
7324 td.rowSpan = c.rowspan;
\r
7326 this.getRow(curRow).appendChild(td);
\r
7331 getNextNonSpan: function(colIndex, rowIndex){
\r
7332 var cols = this.columns;
\r
7333 while((cols && colIndex >= cols) || (this.cells[rowIndex] && this.cells[rowIndex][colIndex])) {
\r
7334 if(cols && colIndex >= cols){
\r
7341 return [colIndex, rowIndex];
\r
7345 renderItem : function(c, position, target){
\r
7346 if(c && !c.rendered){
\r
7347 c.render(this.getNextCell(c));
\r
7348 this.configureItem(c, position);
\r
7349 }else if(c && !this.isValidParent(c, target)){
\r
7350 var container = this.getNextCell(c);
\r
7351 container.insertBefore(c.getPositionEl().dom, null);
\r
7352 c.container = Ext.get(container);
\r
7353 this.configureItem(c, position);
\r
7358 isValidParent : function(c, target){
\r
7359 return c.getPositionEl().up('table', 5).dom.parentNode === (target.dom || target);
\r
7363 * @property activeItem
\r
7368 Ext.Container.LAYOUTS['table'] = Ext.layout.TableLayout;/**
\r
7369 * @class Ext.layout.AbsoluteLayout
\r
7370 * @extends Ext.layout.AnchorLayout
\r
7371 * <p>This is a layout that inherits the anchoring of <b>{@link Ext.layout.AnchorLayout}</b> and adds the
\r
7372 * ability for x/y positioning using the standard x and y component config options.</p>
\r
7373 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
\r
7374 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
\r
7375 * <p>Example usage:</p>
\r
7377 var form = new Ext.form.FormPanel({
\r
7378 title: 'Absolute Layout',
\r
7379 layout:'absolute',
\r
7381 // layout-specific configs go here
\r
7382 extraCls: 'x-abs-layout-item',
\r
7384 baseCls: 'x-plain',
\r
7385 url:'save-form.php',
\r
7386 defaultType: 'textfield',
\r
7396 anchor:'100%' // anchor width by percentage
\r
7406 anchor: '100%' // anchor width by percentage
\r
7410 xtype: 'textarea',
\r
7412 anchor: '100% 100%' // anchor width and height
\r
7417 Ext.layout.AbsoluteLayout = Ext.extend(Ext.layout.AnchorLayout, {
\r
7419 extraCls: 'x-abs-layout-item',
\r
7421 onLayout : function(ct, target){
\r
7422 target.position();
\r
7423 this.paddingLeft = target.getPadding('l');
\r
7424 this.paddingTop = target.getPadding('t');
\r
7426 Ext.layout.AbsoluteLayout.superclass.onLayout.call(this, ct, target);
\r
7430 adjustWidthAnchor : function(value, comp){
\r
7431 return value ? value - comp.getPosition(true)[0] + this.paddingLeft : value;
\r
7435 adjustHeightAnchor : function(value, comp){
\r
7436 return value ? value - comp.getPosition(true)[1] + this.paddingTop : value;
\r
7439 * @property activeItem
\r
7443 Ext.Container.LAYOUTS['absolute'] = Ext.layout.AbsoluteLayout;
7445 * @class Ext.layout.BoxLayout
7446 * @extends Ext.layout.ContainerLayout
7447 * <p>Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.</p>
7449 Ext.layout.BoxLayout = Ext.extend(Ext.layout.ContainerLayout, {
7451 * @cfg {Object} defaultMargins
7452 * <p>If the individual contained items do not have a <tt>margins</tt>
7453 * property specified, the default margins from this property will be
7454 * applied to each item.</p>
7455 * <br><p>This property may be specified as an object containing margins
7456 * to apply in the format:</p><pre><code>
7459 right: (right margin),
7460 bottom: (bottom margin),
7463 * <p>This property may also be specified as a string containing
7464 * space-separated, numeric margin values. The order of the sides associated
7465 * with each value matches the way CSS processes margin values:</p>
7466 * <div class="mdetail-params"><ul>
7467 * <li>If there is only one value, it applies to all sides.</li>
7468 * <li>If there are two values, the top and bottom borders are set to the
7469 * first value and the right and left are set to the second.</li>
7470 * <li>If there are three values, the top is set to the first value, the left
7471 * and right are set to the second, and the bottom is set to the third.</li>
7472 * <li>If there are four values, they apply to the top, right, bottom, and
7473 * left, respectively.</li>
7475 * <p>Defaults to:</p><pre><code>
7476 * {top:0, right:0, bottom:0, left:0}
7479 defaultMargins : {left:0,top:0,right:0,bottom:0},
7481 * @cfg {String} padding
7482 * <p>Sets the padding to be applied to all child items managed by this layout.</p>
7483 * <p>This property must be specified as a string containing
7484 * space-separated, numeric padding values. The order of the sides associated
7485 * with each value matches the way CSS processes padding values:</p>
7486 * <div class="mdetail-params"><ul>
7487 * <li>If there is only one value, it applies to all sides.</li>
7488 * <li>If there are two values, the top and bottom borders are set to the
7489 * first value and the right and left are set to the second.</li>
7490 * <li>If there are three values, the top is set to the first value, the left
7491 * and right are set to the second, and the bottom is set to the third.</li>
7492 * <li>If there are four values, they apply to the top, right, bottom, and
7493 * left, respectively.</li>
7495 * <p>Defaults to: <code>"0"</code></p>
7498 // documented in subclasses
7502 monitorResize : true,
7504 extraCls : 'x-box-item',
7505 targetCls : 'x-box-layout-ct',
7506 innerCls : 'x-box-inner',
7508 constructor : function(config){
7509 Ext.layout.BoxLayout.superclass.constructor.call(this, config);
7510 if(Ext.isString(this.defaultMargins)){
7511 this.defaultMargins = this.parseMargins(this.defaultMargins);
7516 isValidParent : function(c, target){
7517 return c.getPositionEl().dom.parentNode == this.innerCt.dom;
7521 onLayout : function(ct, target){
7522 var cs = ct.items.items, len = cs.length, c, i, last = len-1, cm;
7525 // the innerCt prevents wrapping and shuffling while
7526 // the container is resizing
7527 this.innerCt = target.createChild({cls:this.innerCls});
7528 this.padding = this.parseMargins(this.padding);
7530 this.renderAll(ct, this.innerCt);
7534 renderItem : function(c){
7535 if(Ext.isString(c.margins)){
7536 c.margins = this.parseMargins(c.margins);
7537 }else if(!c.margins){
7538 c.margins = this.defaultMargins;
7540 Ext.layout.BoxLayout.superclass.renderItem.apply(this, arguments);
7544 getTargetSize : function(target){
7545 return (Ext.isIE6 && Ext.isStrict && target.dom == document.body) ? target.getStyleSize() : target.getViewSize(true);
7548 getItems: function(ct){
7550 ct.items.each(function(c){
7560 * @class Ext.layout.VBoxLayout
7561 * @extends Ext.layout.BoxLayout
7562 * <p>A layout that arranges items vertically down a Container. This layout optionally divides available vertical
7563 * space between child items containing a numeric <code>flex</code> configuration.</p>
7564 * This layout may also be used to set the widths of child items by configuring it with the {@link #align} option.
7566 Ext.layout.VBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
7568 * @cfg {String} align
7569 * Controls how the child items of the container are aligned. Acceptable configuration values for this
7571 * <div class="mdetail-params"><ul>
7572 * <li><b><tt>left</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned horizontally
7573 * at the <b>left</b> side of the container</div></li>
7574 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are aligned horizontally at the
7575 * <b>mid-width</b> of the container</div></li>
7576 * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched horizontally to fill
7577 * the width of the container</div></li>
7578 * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched horizontally to
7579 * the size of the largest item.</div></li>
7582 align : 'left', // left, center, stretch, strechmax
7584 * @cfg {String} pack
7585 * Controls how the child items of the container are packed together. Acceptable configuration values
7586 * for this property are:
7587 * <div class="mdetail-params"><ul>
7588 * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
7589 * <b>top</b> side of container</div></li>
7590 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
7591 * <b>mid-height</b> of container</div></li>
7592 * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>bottom</b>
7593 * side of container</div></li>
7597 * @cfg {Number} flex
7598 * This configuation option is to be applied to <b>child <tt>items</tt></b> of the container managed
7599 * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>vertically</b>
7600 * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
7601 * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
7602 * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
7606 onLayout : function(ct, target){
7607 Ext.layout.VBoxLayout.superclass.onLayout.call(this, ct, target);
7609 var cs = this.getItems(ct), cm, ch, margin, cl, diff, aw,
7610 size = target.getViewSize(true),
7612 h = size.height - this.scrollOffset,
7613 l = this.padding.left, t = this.padding.top,
7614 isStart = this.pack == 'start',
7615 stretchWidth = w - (this.padding.left + this.padding.right),
7627 // Do only width calculations and apply those first, as they can affect height
7628 for (i = 0 ; i < csLen; i++) {
7631 margin = cm.top + cm.bottom;
7632 maxWidth = Math.max(maxWidth, c.getWidth() + cm.left + cm.right);
7635 var innerCtWidth = maxWidth + this.padding.left + this.padding.right;
7638 this.innerCt.setSize(w, h);
7642 this.innerCt.setSize(innerCtWidth, h);
7645 this.innerCt.setSize(w = Math.max(w, innerCtWidth), h);
7649 var availableWidth = Math.max(0, w - this.padding.left - this.padding.right);
7651 for (i = 0 ; i < csLen; i++) {
7654 if(this.align == 'stretch'){
7655 c.setWidth((stretchWidth - (cm.left + cm.right)).constrain(
7656 c.minWidth || 0, c.maxWidth || 1000000));
7657 }else if(this.align == 'stretchmax'){
7658 c.setWidth((maxWidth - (cm.left + cm.right)).constrain(
7659 c.minWidth || 0, c.maxWidth || 1000000));
7660 }else if(isStart && c.flex){
7666 // Do height calculations
7667 for (i = 0 ; i < csLen; i++) {
7670 totalFlex += c.flex || 0;
7672 margin = cm.top + cm.bottom;
7673 extraHeight += ch + margin;
7674 flexHeight += margin + (c.flex ? 0 : ch);
7676 extraHeight = h - extraHeight - this.padding.top - this.padding.bottom;
7678 var availHeight = Math.max(0, h - this.padding.top - this.padding.bottom - flexHeight),
7679 leftOver = availHeight;
7680 for (i = 0 ; i < csLen; i++) {
7682 if(isStart && c.flex){
7683 ch = Math.floor(availHeight * (c.flex / totalFlex));
7688 if(this.pack == 'center'){
7689 t += extraHeight ? extraHeight / 2 : 0;
7690 }else if(this.pack == 'end'){
7695 for (i = 0 ; i < csLen; i++) {
7699 aw = availableWidth;
7700 cl = l + cm.left // default left pos
7702 // Adjust left pos for centering
7703 if(this.align == 'center'){
7704 if((diff = availableWidth - (c.getWidth() + cm.left + cm.right)) > 0){
7710 c.setPosition(cl, t);
7711 if(isStart && c.flex){
7712 ch = Math.max(0, heights[idx++] + (leftOver-- > 0 ? 1 : 0));
7717 t += ch + cm.bottom;
7722 Ext.Container.LAYOUTS.vbox = Ext.layout.VBoxLayout;
7725 * @class Ext.layout.HBoxLayout
7726 * @extends Ext.layout.BoxLayout
7727 * <p>A layout that arranges items horizontally across a Container. This layout optionally divides available horizontal
7728 * space between child items containing a numeric <code>flex</code> configuration.</p>
7729 * This layout may also be used to set the heights of child items by configuring it with the {@link #align} option.
7731 Ext.layout.HBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
7733 * @cfg {String} align
7734 * Controls how the child items of the container are aligned. Acceptable configuration values for this
7736 * <div class="mdetail-params"><ul>
7737 * <li><b><tt>top</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned vertically
7738 * at the <b>top</b> of the container</div></li>
7739 * <li><b><tt>middle</tt></b> : <div class="sub-desc">child items are aligned vertically in the
7740 * <b>middle</b> of the container</div></li>
7741 * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched vertically to fill
7742 * the height of the container</div></li>
7743 * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched vertically to
7744 * the height of the largest item.</div></li>
7746 align : 'top', // top, middle, stretch, strechmax
7748 * @cfg {String} pack
7749 * Controls how the child items of the container are packed together. Acceptable configuration values
7750 * for this property are:
7751 * <div class="mdetail-params"><ul>
7752 * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
7753 * <b>left</b> side of container</div></li>
7754 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
7755 * <b>mid-width</b> of container</div></li>
7756 * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>right</b>
7757 * side of container</div></li>
7761 * @cfg {Number} flex
7762 * This configuation option is to be applied to <b>child <tt>items</tt></b> of the container managed
7763 * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>horizontally</b>
7764 * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
7765 * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
7766 * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
7770 onLayout : function(ct, target){
7771 Ext.layout.HBoxLayout.superclass.onLayout.call(this, ct, target);
7773 var cs = this.getItems(ct), cm, cw, margin, ch, diff,
7774 size = target.getViewSize(true),
7775 w = size.width - this.scrollOffset,
7777 l = this.padding.left, t = this.padding.top,
7778 isStart = this.pack == 'start',
7779 isRestore = ['stretch', 'stretchmax'].indexOf(this.align) == -1,
7780 stretchHeight = h - (this.padding.top + this.padding.bottom),
7787 Ext.each(cs, function(c){
7789 totalFlex += c.flex || 0;
7791 margin = cm.left + cm.right;
7792 extraWidth += cw + margin;
7793 flexWidth += margin + (c.flex ? 0 : cw);
7794 maxHeight = Math.max(maxHeight, c.getHeight() + cm.top + cm.bottom);
7796 extraWidth = w - extraWidth - this.padding.left - this.padding.right;
7798 var innerCtHeight = maxHeight + this.padding.top + this.padding.bottom;
7801 this.innerCt.setSize(w, h);
7805 this.innerCt.setSize(w, innerCtHeight);
7808 this.innerCt.setSize(w, h = Math.max(h, innerCtHeight));
7813 var availWidth = Math.max(0, w - this.padding.left - this.padding.right - flexWidth),
7814 leftOver = availWidth,
7818 availableHeight = Math.max(0, h - this.padding.top - this.padding.bottom);
7821 Ext.each(cs, function(c){
7822 if(isStart && c.flex){
7823 cw = Math.floor(availWidth * (c.flex / totalFlex));
7829 if(this.pack == 'center'){
7830 l += extraWidth ? extraWidth / 2 : 0;
7831 }else if(this.pack == 'end'){
7834 Ext.each(cs, function(c){
7837 c.setPosition(l, t + cm.top);
7838 if(isStart && c.flex){
7839 cw = Math.max(0, widths[idx++] + (leftOver-- > 0 ? 1 : 0));
7841 restore.push(c.getHeight());
7843 c.setSize(cw, availableHeight);
7851 Ext.each(cs, function(c){
7854 if(isStart && c.flex){
7855 ch = restore[idx++];
7857 if(this.align == 'stretch'){
7858 c.setHeight((stretchHeight - (cm.top + cm.bottom)).constrain(
7859 c.minHeight || 0, c.maxHeight || 1000000));
7860 }else if(this.align == 'stretchmax'){
7861 c.setHeight((maxHeight - (cm.top + cm.bottom)).constrain(
7862 c.minHeight || 0, c.maxHeight || 1000000));
7864 if(this.align == 'middle'){
7865 diff = availableHeight - (ch + cm.top + cm.bottom);
7866 ch = t + cm.top + (diff/2);
7868 c.setPosition(c.x, ch);
7871 if(isStart && c.flex){
7879 Ext.Container.LAYOUTS.hbox = Ext.layout.HBoxLayout;
7881 * @class Ext.Viewport
\r
7882 * @extends Ext.Container
\r
7883 * <p>A specialized container representing the viewable application area (the browser viewport).</p>
\r
7884 * <p>The Viewport renders itself to the document body, and automatically sizes itself to the size of
\r
7885 * the browser viewport and manages window resizing. There may only be one Viewport created
\r
7886 * in a page. Inner layouts are available by virtue of the fact that all {@link Ext.Panel Panel}s
\r
7887 * added to the Viewport, either through its {@link #items}, or through the items, or the {@link #add}
\r
7888 * method of any of its child Panels may themselves have a layout.</p>
\r
7889 * <p>The Viewport does not provide scrolling, so child Panels within the Viewport should provide
\r
7890 * for scrolling if needed using the {@link #autoScroll} config.</p>
\r
7891 * <p>An example showing a classic application border layout:</p><pre><code>
\r
7892 new Ext.Viewport({
\r
7896 html: '<h1 class="x-panel-header">Page Title</h1>',
\r
7899 margins: '0 0 5 0'
\r
7902 collapsible: true,
\r
7903 title: 'Navigation',
\r
7905 // the west region might typically utilize a {@link Ext.tree.TreePanel TreePanel} or a Panel with {@link Ext.layout.AccordionLayout Accordion layout}
\r
7908 title: 'Title for Panel',
\r
7909 collapsible: true,
\r
7910 html: 'Information goes here',
\r
7916 title: 'Title for the Grid Panel',
\r
7917 collapsible: true,
\r
7921 // remaining grid configuration not shown ...
\r
7922 // notice that the GridPanel is added directly as the region
\r
7923 // it is not "overnested" inside another Panel
\r
7926 xtype: 'tabpanel', // TabPanel itself has no title
\r
7928 title: 'Default Tab',
\r
7929 html: 'The first tab\'s content. Others may be added dynamically'
\r
7935 * Create a new Viewport
\r
7936 * @param {Object} config The config object
\r
7939 Ext.Viewport = Ext.extend(Ext.Container, {
\r
7941 * Privatize config options which, if used, would interfere with the
\r
7942 * correct operation of the Viewport as the sole manager of the
\r
7943 * layout of the document body.
\r
7946 * @cfg {Mixed} applyTo @hide
\r
7949 * @cfg {Boolean} allowDomMove @hide
\r
7952 * @cfg {Boolean} hideParent @hide
\r
7955 * @cfg {Mixed} renderTo @hide
\r
7958 * @cfg {Boolean} hideParent @hide
\r
7961 * @cfg {Number} height @hide
\r
7964 * @cfg {Number} width @hide
\r
7967 * @cfg {Boolean} autoHeight @hide
\r
7970 * @cfg {Boolean} autoWidth @hide
\r
7973 * @cfg {Boolean} deferHeight @hide
\r
7976 * @cfg {Boolean} monitorResize @hide
\r
7979 initComponent : function() {
\r
7980 Ext.Viewport.superclass.initComponent.call(this);
\r
7981 document.getElementsByTagName('html')[0].className += ' x-viewport';
\r
7982 this.el = Ext.getBody();
\r
7983 this.el.setHeight = Ext.emptyFn;
\r
7984 this.el.setWidth = Ext.emptyFn;
\r
7985 this.el.setSize = Ext.emptyFn;
\r
7986 this.el.dom.scroll = 'no';
\r
7987 this.allowDomMove = false;
\r
7988 this.autoWidth = true;
\r
7989 this.autoHeight = true;
\r
7990 Ext.EventManager.onWindowResize(this.fireResize, this);
\r
7991 this.renderTo = this.el;
\r
7994 fireResize : function(w, h){
\r
7995 this.onResize(w, h, w, h);
\r
7998 Ext.reg('viewport', Ext.Viewport);
\r
8001 * @extends Ext.Container
8002 * <p>Panel is a container that has specific functionality and structural components that make
8003 * it the perfect building block for application-oriented user interfaces.</p>
8004 * <p>Panels are, by virtue of their inheritance from {@link Ext.Container}, capable
8005 * of being configured with a {@link Ext.Container#layout layout}, and containing child Components.</p>
8006 * <p>When either specifying child {@link Ext.Component#items items} of a Panel, or dynamically {@link Ext.Container#add adding} Components
8007 * to a Panel, remember to consider how you wish the Panel to arrange those child elements, and whether
8008 * 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
8009 * default, Panels use the {@link Ext.layout.ContainerLayout ContainerLayout} scheme. This simply renders
8010 * child components, appending them one after the other inside the Container, and <b>does not apply any sizing</b>
8012 * <p>A Panel may also contain {@link #bbar bottom} and {@link #tbar top} toolbars, along with separate
8013 * {@link #header}, {@link #footer} and {@link #body} sections (see {@link #frame} for additional
8015 * <p>Panel also provides built-in {@link #collapsible expandable and collapsible behavior}, along with
8016 * a variety of {@link #tools prebuilt tool buttons} that can be wired up to provide other customized
8017 * behavior. Panels can be easily dropped into any {@link Ext.Container Container} or layout, and the
8018 * layout and rendering pipeline is {@link Ext.Container#add completely managed by the framework}.</p>
8020 * @param {Object} config The config object
8023 Ext.Panel = Ext.extend(Ext.Container, {
8025 * The Panel's header {@link Ext.Element Element}. Read-only.
8026 * <p>This Element is used to house the {@link #title} and {@link #tools}</p>
8027 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
8032 * The Panel's body {@link Ext.Element Element} which may be used to contain HTML content.
8033 * The content may be specified in the {@link #html} config, or it may be loaded using the
8034 * {@link autoLoad} config, or through the Panel's {@link #getUpdater Updater}. Read-only.
8035 * <p>If this is used to load visible HTML elements in either way, then
8036 * the Panel may not be used as a Layout for hosting nested Panels.</p>
8037 * <p>If this Panel is intended to be used as the host of a Layout (See {@link #layout}
8038 * then the body Element must not be loaded or changed - it is under the control
8039 * of the Panel's Layout.
8040 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
8045 * The Panel's bwrap {@link Ext.Element Element} used to contain other Panel elements
8046 * (tbar, body, bbar, footer). See {@link #bodyCfg}. Read-only.
8051 * True if this panel is collapsed. Read-only.
8053 * @property collapsed
8056 * @cfg {Object} bodyCfg
8057 * <p>A {@link Ext.DomHelper DomHelper} element specification object may be specified for any
8058 * Panel Element.</p>
8059 * <p>By default, the Default element in the table below will be used for the html markup to
8060 * create a child element with the commensurate Default class name (<code>baseCls</code> will be
8061 * replaced by <code>{@link #baseCls}</code>):</p>
8063 * Panel Default Default Custom Additional Additional
8064 * Element element class element class style
8065 * ======== ========================== ========= ============== ===========
8066 * {@link #header} div {@link #baseCls}+'-header' {@link #headerCfg} headerCssClass headerStyle
8067 * {@link #bwrap} div {@link #baseCls}+'-bwrap' {@link #bwrapCfg} bwrapCssClass bwrapStyle
8068 * + tbar div {@link #baseCls}+'-tbar' {@link #tbarCfg} tbarCssClass tbarStyle
8069 * + {@link #body} div {@link #baseCls}+'-body' {@link #bodyCfg} {@link #bodyCssClass} {@link #bodyStyle}
8070 * + bbar div {@link #baseCls}+'-bbar' {@link #bbarCfg} bbarCssClass bbarStyle
8071 * + {@link #footer} div {@link #baseCls}+'-footer' {@link #footerCfg} footerCssClass footerStyle
8073 * <p>Configuring a Custom element may be used, for example, to force the {@link #body} Element
8074 * to use a different form of markup than is created by default. An example of this might be
8075 * to {@link Ext.Element#createChild create a child} Panel containing a custom content, such as
8076 * a header, or forcing centering of all Panel content by having the body be a <center>
8080 title: 'Message Title',
8081 renderTo: Ext.getBody(),
8082 width: 200, height: 130,
8085 cls: 'x-panel-body', // Default class not applied if Custom element specified
8090 cls: 'x-panel-footer' // same as the Default class
8093 footerCssClass: 'custom-footer', // additional css class, see {@link Ext.element#addClass addClass}
8094 footerStyle: 'background-color:red' // see {@link #bodyStyle}
8097 * <p>The example above also explicitly creates a <code>{@link #footer}</code> with custom markup and
8098 * styling applied.</p>
8101 * @cfg {Object} headerCfg
8102 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
8103 * of this Panel's {@link #header} Element. See <code>{@link #bodyCfg}</code> also.</p>
8106 * @cfg {Object} bwrapCfg
8107 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
8108 * of this Panel's {@link #bwrap} Element. See <code>{@link #bodyCfg}</code> also.</p>
8111 * @cfg {Object} tbarCfg
8112 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
8113 * of this Panel's {@link #tbar} Element. See <code>{@link #bodyCfg}</code> also.</p>
8116 * @cfg {Object} bbarCfg
8117 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
8118 * of this Panel's {@link #bbar} Element. See <code>{@link #bodyCfg}</code> also.</p>
8121 * @cfg {Object} footerCfg
8122 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
8123 * of this Panel's {@link #footer} Element. See <code>{@link #bodyCfg}</code> also.</p>
8126 * @cfg {Boolean} closable
8127 * Panels themselves do not directly support being closed, but some Panel subclasses do (like
8128 * {@link Ext.Window}) or a Panel Class within an {@link Ext.TabPanel}. Specify <code>true</code>
8129 * to enable closing in such situations. Defaults to <code>false</code>.
8132 * The Panel's footer {@link Ext.Element Element}. Read-only.
8133 * <p>This Element is used to house the Panel's <code>{@link #buttons}</code> or <code>{@link #fbar}</code>.</p>
8134 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
8139 * @cfg {Mixed} applyTo
8140 * <p>The id of the node, a DOM node or an existing Element corresponding to a DIV that is already present in
8141 * the document that specifies some panel-specific structural markup. When <code>applyTo</code> is used,
8142 * constituent parts of the panel can be specified by CSS class name within the main element, and the panel
8143 * will automatically create those components from that markup. Any required components not specified in the
8144 * markup will be autogenerated if necessary.</p>
8145 * <p>The following class names are supported (baseCls will be replaced by {@link #baseCls}):</p>
8146 * <ul><li>baseCls + '-header'</li>
8147 * <li>baseCls + '-header-text'</li>
8148 * <li>baseCls + '-bwrap'</li>
8149 * <li>baseCls + '-tbar'</li>
8150 * <li>baseCls + '-body'</li>
8151 * <li>baseCls + '-bbar'</li>
8152 * <li>baseCls + '-footer'</li></ul>
8153 * <p>Using this config, a call to render() is not required. If applyTo is specified, any value passed for
8154 * {@link #renderTo} will be ignored and the target element's parent node will automatically be used as the
8155 * panel's container.</p>
8158 * @cfg {Object/Array} tbar
8159 * <p>The top toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
8160 * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render.
8161 * To access the top toolbar after render, use {@link #getTopToolbar}.</p>
8162 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
8163 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
8164 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
8165 * submission parameters are collected from the DOM tree.</p>
8168 * @cfg {Object/Array} bbar
8169 * <p>The bottom toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
8170 * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render.
8171 * To access the bottom toolbar after render, use {@link #getBottomToolbar}.</p>
8172 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
8173 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
8174 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
8175 * submission parameters are collected from the DOM tree.</p>
8177 /** @cfg {Object/Array} fbar
8178 * <p>A {@link Ext.Toolbar Toolbar} object, a Toolbar config, or an array of
8179 * {@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>
8180 * <p>After render, the <code>fbar</code> property will be an {@link Ext.Toolbar Toolbar} instance.</p>
8181 * <p>If <code>{@link #buttons}</code> are specified, they will supersede the <code>fbar</code> configuration property.</p>
8182 * The Panel's <code>{@link #buttonAlign}</code> configuration affects the layout of these items, for example:
8184 var w = new Ext.Window({
8187 bbar: new Ext.Toolbar({
8194 {@link #buttonAlign}: 'left', // anything but 'center' or 'right' and you can use '-', and '->'
8195 // to control the alignment of fbar items
8203 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
8204 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
8205 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
8206 * submission parameters are collected from the DOM tree.</p>
8209 * @cfg {Boolean} header
8210 * <code>true</code> to create the Panel's header element explicitly, <code>false</code> to skip creating
8211 * it. If a <code>{@link #title}</code> is set the header will be created automatically, otherwise it will not.
8212 * If a <code>{@link #title}</code> is set but <code>header</code> is explicitly set to <code>false</code>, the header
8213 * will not be rendered.
8216 * @cfg {Boolean} footer
8217 * <code>true</code> to create the footer element explicitly, false to skip creating it. The footer
8218 * will be created automatically if <code>{@link #buttons}</code> or a <code>{@link #fbar}</code> have
8219 * been configured. See <code>{@link #bodyCfg}</code> for an example.
8222 * @cfg {String} title
8223 * The title text to be used as innerHTML (html tags are accepted) to display in the panel
8224 * <code>{@link #header}</code> (defaults to ''). When a <code>title</code> is specified the
8225 * <code>{@link #header}</code> element will automatically be created and displayed unless
8226 * {@link #header} is explicitly set to <code>false</code>. If you do not want to specify a
8227 * <code>title</code> at config time, but you may want one later, you must either specify a non-empty
8228 * <code>title</code> (a blank space ' ' will do) or <code>header:true</code> so that the container
8229 * element will get created.
8232 * @cfg {Array} buttons
8233 * <code>buttons</code> will be used as <code>{@link Ext.Container#items items}</code> for the toolbar in
8234 * the footer (<code>{@link #fbar}</code>). Typically the value of this configuration property will be
8235 * an array of {@link Ext.Button}s or {@link Ext.Button} configuration objects.
8236 * If an item is configured with <code>minWidth</code> or the Panel is configured with <code>minButtonWidth</code>,
8237 * that width will be applied to the item.
8240 * @cfg {Object/String/Function} autoLoad
8241 * A valid url spec according to the Updater {@link Ext.Updater#update} method.
8242 * If autoLoad is not null, the panel will attempt to load its contents
8243 * immediately upon render.<p>
8244 * The URL will become the default URL for this panel's {@link #body} element,
8245 * so it may be {@link Ext.Element#refresh refresh}ed at any time.</p>
8248 * @cfg {Boolean} frame
8249 * <code>false</code> by default to render with plain 1px square borders. <code>true</code> to render with
8250 * 9 elements, complete with custom rounded corners (also see {@link Ext.Element#boxWrap}).
8251 * <p>The template generated for each condition is depicted below:</p><pre><code>
8254 <div id="developer-specified-id-goes-here" class="x-panel">
8256 <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:false)</span></div>
8258 <div class="x-panel-bwrap">
8259 <div class="x-panel-body"><p>html value goes here</p></div>
8263 // frame = true (create 9 elements)
8264 <div id="developer-specified-id-goes-here" class="x-panel">
8265 <div class="x-panel-tl"><div class="x-panel-tr"><div class="x-panel-tc">
8266 <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:true)</span></div>
8267 </div></div></div>
8269 <div class="x-panel-bwrap">
8270 <div class="x-panel-ml"><div class="x-panel-mr"><div class="x-panel-mc">
8271 <div class="x-panel-body"><p>html value goes here</p></div>
8272 </div></div></div>
8274 <div class="x-panel-bl"><div class="x-panel-br"><div class="x-panel-bc"/>
8275 </div></div></div>
8280 * @cfg {Boolean} border
8281 * True to display the borders of the panel's body element, false to hide them (defaults to true). By default,
8282 * the border is a 2px wide inset border, but this can be further altered by setting {@link #bodyBorder} to false.
8285 * @cfg {Boolean} bodyBorder
8286 * True to display an interior border on the body element of the panel, false to hide it (defaults to true).
8287 * This only applies when {@link #border} == true. If border == true and bodyBorder == false, the border will display
8288 * as a 1px wide inset border, giving the entire body element an inset appearance.
8291 * @cfg {String/Object/Function} bodyCssClass
8292 * Additional css class selector to be applied to the {@link #body} element in the format expected by
8293 * {@link Ext.Element#addClass} (defaults to null). See {@link #bodyCfg}.
8296 * @cfg {String/Object/Function} bodyStyle
8297 * Custom CSS styles to be applied to the {@link #body} element in the format expected by
8298 * {@link Ext.Element#applyStyles} (defaults to null). See {@link #bodyCfg}.
8301 * @cfg {String} iconCls
8302 * The CSS class selector that specifies a background image to be used as the header icon (defaults to '').
8303 * <p>An example of specifying a custom icon class would be something like:
8305 // specify the property in the config for the class:
8309 // css class that specifies background image to be used as the icon image:
8310 .my-icon { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
8314 * @cfg {Boolean} collapsible
8315 * True to make the panel collapsible and have the expand/collapse toggle button automatically rendered into
8316 * the header tool button area, false to keep the panel statically sized with no button (defaults to false).
8319 * @cfg {Array} tools
8320 * An array of tool button configs to be added to the header tool area. When rendered, each tool is
8321 * stored as an {@link Ext.Element Element} referenced by a public property called <code><b></b>tools.<i><tool-type></i></code>
8322 * <p>Each tool config may contain the following properties:
8323 * <div class="mdetail-params"><ul>
8324 * <li><b>id</b> : String<div class="sub-desc"><b>Required.</b> The type
8325 * of tool to create. By default, this assigns a CSS class of the form <code>x-tool-<i><tool-type></i></code> to the
8326 * resulting tool Element. Ext provides CSS rules, and an icon sprite containing images for the tool types listed below.
8327 * The developer may implement custom tools by supplying alternate CSS rules and background images:
8329 * <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>
8330 * <div class="x-tool x-tool-close" style="float:left; margin-right:5;"> </div><div><code> close</code></div>
8331 * <div class="x-tool x-tool-minimize" style="float:left; margin-right:5;"> </div><div><code> minimize</code></div>
8332 * <div class="x-tool x-tool-maximize" style="float:left; margin-right:5;"> </div><div><code> maximize</code></div>
8333 * <div class="x-tool x-tool-restore" style="float:left; margin-right:5;"> </div><div><code> restore</code></div>
8334 * <div class="x-tool x-tool-gear" style="float:left; margin-right:5;"> </div><div><code> gear</code></div>
8335 * <div class="x-tool x-tool-pin" style="float:left; margin-right:5;"> </div><div><code> pin</code></div>
8336 * <div class="x-tool x-tool-unpin" style="float:left; margin-right:5;"> </div><div><code> unpin</code></div>
8337 * <div class="x-tool x-tool-right" style="float:left; margin-right:5;"> </div><div><code> right</code></div>
8338 * <div class="x-tool x-tool-left" style="float:left; margin-right:5;"> </div><div><code> left</code></div>
8339 * <div class="x-tool x-tool-up" style="float:left; margin-right:5;"> </div><div><code> up</code></div>
8340 * <div class="x-tool x-tool-down" style="float:left; margin-right:5;"> </div><div><code> down</code></div>
8341 * <div class="x-tool x-tool-refresh" style="float:left; margin-right:5;"> </div><div><code> refresh</code></div>
8342 * <div class="x-tool x-tool-minus" style="float:left; margin-right:5;"> </div><div><code> minus</code></div>
8343 * <div class="x-tool x-tool-plus" style="float:left; margin-right:5;"> </div><div><code> plus</code></div>
8344 * <div class="x-tool x-tool-help" style="float:left; margin-right:5;"> </div><div><code> help</code></div>
8345 * <div class="x-tool x-tool-search" style="float:left; margin-right:5;"> </div><div><code> search</code></div>
8346 * <div class="x-tool x-tool-save" style="float:left; margin-right:5;"> </div><div><code> save</code></div>
8347 * <div class="x-tool x-tool-print" style="float:left; margin-right:5;"> </div><div><code> print</code></div>
8349 * <li><b>handler</b> : Function<div class="sub-desc"><b>Required.</b> The function to
8350 * call when clicked. Arguments passed are:<ul>
8351 * <li><b>event</b> : Ext.EventObject<div class="sub-desc">The click event.</div></li>
8352 * <li><b>toolEl</b> : Ext.Element<div class="sub-desc">The tool Element.</div></li>
8353 * <li><b>panel</b> : Ext.Panel<div class="sub-desc">The host Panel</div></li>
8354 * <li><b>tc</b> : Object<div class="sub-desc">The tool configuration object</div></li>
8356 * <li><b>stopEvent</b> : Boolean<div class="sub-desc">Defaults to true. Specify as false to allow click event to propagate.</div></li>
8357 * <li><b>scope</b> : Object<div class="sub-desc">The scope in which to call the handler.</div></li>
8358 * <li><b>qtip</b> : String/Object<div class="sub-desc">A tip string, or
8359 * a config argument to {@link Ext.QuickTip#register}</div></li>
8360 * <li><b>hidden</b> : Boolean<div class="sub-desc">True to initially render hidden.</div></li>
8361 * <li><b>on</b> : Object<div class="sub-desc">A listener config object specifiying
8362 * event listeners in the format of an argument to {@link #addListener}</div></li>
8364 * <p>Note that, apart from the toggle tool which is provided when a panel is collapsible, these
8365 * tools only provide the visual button. Any required functionality must be provided by adding
8366 * handlers that implement the necessary behavior.</p>
8367 * <p>Example usage:</p>
8371 qtip: 'Refresh form Data',
8373 handler: function(event, toolEl, panel){
8380 handler: function(event, toolEl, panel){
8385 * <p>For the custom id of <code>'help'</code> define two relevant css classes with a link to
8386 * a 15x15 image:</p>
8388 .x-tool-help {background-image: url(images/help.png);}
8389 .x-tool-help-over {background-image: url(images/help_over.png);}
8390 // if using an image sprite:
8391 .x-tool-help {background-image: url(images/help.png) no-repeat 0 0;}
8392 .x-tool-help-over {background-position:-15px 0;}
8396 * @cfg {Ext.Template/Ext.XTemplate} toolTemplate
8397 * <p>A Template used to create {@link #tools} in the {@link #header} Element. Defaults to:</p><pre><code>
8398 new Ext.Template('<div class="x-tool x-tool-{id}">&#160;</div>')</code></pre>
8399 * <p>This may may be overridden to provide a custom DOM structure for tools based upon a more
8400 * complex XTemplate. The template's data is a single tool configuration object (Not the entire Array)
8401 * as specified in {@link #tools}. In the following example an <a> tag is used to provide a
8402 * visual indication when hovering over the tool:</p><pre><code>
8403 var win = new Ext.Window({
8406 href: '/MyPdfDoc.pdf'
8408 toolTemplate: new Ext.XTemplate(
8409 '<tpl if="id==\'download\'">',
8410 '<a class="x-tool x-tool-pdf" href="{href}"></a>',
8412 '<tpl if="id!=\'download\'">',
8413 '<div class="x-tool x-tool-{id}">&#160;</div>',
8420 * <p>Note that the CSS class 'x-tool-pdf' should have an associated style rule which provides an
8421 * appropriate background image, something like:</p>
8423 a.x-tool-pdf {background-image: url(../shared/extjs/images/pdf.gif)!important;}
8427 * @cfg {Boolean} hideCollapseTool
8428 * <code>true</code> to hide the expand/collapse toggle button when <code>{@link #collapsible} == true</code>,
8429 * <code>false</code> to display it (defaults to <code>false</code>).
8432 * @cfg {Boolean} titleCollapse
8433 * <code>true</code> to allow expanding and collapsing the panel (when <code>{@link #collapsible} = true</code>)
8434 * by clicking anywhere in the header bar, <code>false</code>) to allow it only by clicking to tool button
8435 * (defaults to <code>false</code>)). If this panel is a child item of a border layout also see the
8436 * {@link Ext.layout.BorderLayout.Region BorderLayout.Region}
8437 * <code>{@link Ext.layout.BorderLayout.Region#floatable floatable}</code> config option.
8441 * @cfg {Mixed} floating
8442 * <p>This property is used to configure the underlying {@link Ext.Layer}. Acceptable values for this
8443 * configuration property are:</p><div class="mdetail-params"><ul>
8444 * <li><b><code>false</code></b> : <b>Default.</b><div class="sub-desc">Display the panel inline where it is
8445 * rendered.</div></li>
8446 * <li><b><code>true</code></b> : <div class="sub-desc">Float the panel (absolute position it with automatic
8447 * shimming and shadow).<ul>
8448 * <div class="sub-desc">Setting floating to true will create an Ext.Layer for this panel and display the
8449 * panel at negative offsets so that it is hidden.</div>
8450 * <div class="sub-desc">Since the panel will be absolute positioned, the position must be set explicitly
8451 * <i>after</i> render (e.g., <code>myPanel.setPosition(100,100);</code>).</div>
8452 * <div class="sub-desc"><b>Note</b>: when floating a panel you should always assign a fixed width,
8453 * otherwise it will be auto width and will expand to fill to the right edge of the viewport.</div>
8455 * <li><b><code>{@link Ext.Layer object}</code></b> : <div class="sub-desc">The specified object will be used
8456 * as the configuration object for the {@link Ext.Layer} that will be created.</div></li>
8460 * @cfg {Boolean/String} shadow
8461 * <code>true</code> (or a valid Ext.Shadow {@link Ext.Shadow#mode} value) to display a shadow behind the
8462 * panel, <code>false</code> to display no shadow (defaults to <code>'sides'</code>). Note that this option
8463 * only applies when <code>{@link #floating} = true</code>.
8466 * @cfg {Number} shadowOffset
8467 * The number of pixels to offset the shadow if displayed (defaults to <code>4</code>). Note that this
8468 * option only applies when <code>{@link #floating} = true</code>.
8471 * @cfg {Boolean} shim
8472 * <code>false</code> to disable the iframe shim in browsers which need one (defaults to <code>true</code>).
8473 * Note that this option only applies when <code>{@link #floating} = true</code>.
8476 * @cfg {Object/Array} keys
8477 * A {@link Ext.KeyMap} config object (in the format expected by {@link Ext.KeyMap#addBinding}
8478 * used to assign custom key handling to this panel (defaults to <code>null</code>).
8481 * @cfg {Boolean/Object} draggable
8482 * <p><code>true</code> to enable dragging of this Panel (defaults to <code>false</code>).</p>
8483 * <p>For custom drag/drop implementations, an <b>Ext.Panel.DD</b> config could also be passed
8484 * in this config instead of <code>true</code>. Ext.Panel.DD is an internal, undocumented class which
8485 * moves a proxy Element around in place of the Panel's element, but provides no other behaviour
8486 * during dragging or on drop. It is a subclass of {@link Ext.dd.DragSource}, so behaviour may be
8487 * added by implementing the interface methods of {@link Ext.dd.DragDrop} e.g.:
8493 renderTo: Ext.getBody(),
8499 // Config option of Ext.Panel.DD class.
8500 // It's a floating Panel, so do not show a placeholder proxy in the original position.
8503 // Called for each mousemove event while dragging the DD object.
8504 onDrag : function(e){
8505 // Record the x,y position of the drag proxy so that we can
8506 // position the Panel at end of drag.
8507 var pel = this.proxy.getEl();
8508 this.x = pel.getLeft(true);
8509 this.y = pel.getTop(true);
8511 // Keep the Shadow aligned if there is one.
8512 var s = this.panel.getEl().shadow;
8514 s.realign(this.x, this.y, pel.getWidth(), pel.getHeight());
8518 // Called on the mouseup event.
8519 endDrag : function(e){
8520 this.panel.setPosition(this.x, this.y);
8527 * @cfg {Boolean} disabled
8528 * Render this panel disabled (default is <code>false</code>). An important note when using the disabled
8529 * config on panels is that IE will often fail to initialize the disabled mask element correectly if
8530 * the panel's layout has not yet completed by the time the Panel is disabled during the render process.
8531 * If you experience this issue, you may need to instead use the {@link #afterlayout} event to initialize
8532 * the disabled state:
8541 single: true // important, as many layouts can occur
8548 * @cfg {Boolean} autoHeight
8549 * <code>true</code> to use height:'auto', <code>false</code> to use fixed height (defaults to <code>false</code>).
8550 * <b>Note</b>: Setting <code>autoHeight: true</code> means that the browser will manage the panel's height
8551 * based on its contents, and that Ext will not manage it at all. If the panel is within a layout that
8552 * manages dimensions (<code>fit</code>, <code>border</code>, etc.) then setting <code>autoHeight: true</code>
8553 * can cause issues with scrolling and will not generally work as expected since the panel will take
8554 * on the height of its contents rather than the height required by the Ext layout.
8559 * @cfg {String} baseCls
8560 * The base CSS class to apply to this panel's element (defaults to <code>'x-panel'</code>).
8561 * <p>Another option available by default is to specify <code>'x-plain'</code> which strips all styling
8562 * except for required attributes for Ext layouts to function (e.g. overflow:hidden).
8563 * See <code>{@link #unstyled}</code> also.</p>
8565 baseCls : 'x-panel',
8567 * @cfg {String} collapsedCls
8568 * A CSS class to add to the panel's element after it has been collapsed (defaults to
8569 * <code>'x-panel-collapsed'</code>).
8571 collapsedCls : 'x-panel-collapsed',
8573 * @cfg {Boolean} maskDisabled
8574 * <code>true</code> to mask the panel when it is {@link #disabled}, <code>false</code> to not mask it (defaults
8575 * to <code>true</code>). Either way, the panel will always tell its contained elements to disable themselves
8576 * when it is disabled, but masking the panel can provide an additional visual cue that the panel is
8579 maskDisabled : true,
8581 * @cfg {Boolean} animCollapse
8582 * <code>true</code> to animate the transition when the panel is collapsed, <code>false</code> to skip the
8583 * animation (defaults to <code>true</code> if the {@link Ext.Fx} class is available, otherwise <code>false</code>).
8585 animCollapse : Ext.enableFx,
8587 * @cfg {Boolean} headerAsText
8588 * <code>true</code> to display the panel <code>{@link #title}</code> in the <code>{@link #header}</code>,
8589 * <code>false</code> to hide it (defaults to <code>true</code>).
8591 headerAsText : true,
8593 * @cfg {String} buttonAlign
8594 * The alignment of any {@link #buttons} added to this panel. Valid values are <code>'right'</code>,
8595 * <code>'left'</code> and <code>'center'</code> (defaults to <code>'right'</code>).
8597 buttonAlign : 'right',
8599 * @cfg {Boolean} collapsed
8600 * <code>true</code> to render the panel collapsed, <code>false</code> to render it expanded (defaults to
8601 * <code>false</code>).
8605 * @cfg {Boolean} collapseFirst
8606 * <code>true</code> to make sure the collapse/expand toggle button always renders first (to the left of)
8607 * any other tools in the panel's title bar, <code>false</code> to render it last (defaults to <code>true</code>).
8609 collapseFirst : true,
8611 * @cfg {Number} minButtonWidth
8612 * Minimum width in pixels of all {@link #buttons} in this panel (defaults to <code>75</code>)
8614 minButtonWidth : 75,
8616 * @cfg {Boolean} unstyled
8617 * Overrides the <code>{@link #baseCls}</code> setting to <code>{@link #baseCls} = 'x-plain'</code> which renders
8618 * the panel unstyled except for required attributes for Ext layouts to function (e.g. overflow:hidden).
8621 * @cfg {String} elements
8622 * A comma-delimited list of panel elements to initialize when the panel is rendered. Normally, this list will be
8623 * generated automatically based on the items added to the panel at config time, but sometimes it might be useful to
8624 * make sure a structural element is rendered even if not specified at config time (for example, you may want
8625 * to add a button or toolbar dynamically after the panel has been rendered). Adding those elements to this
8626 * list will allocate the required placeholders in the panel when it is rendered. Valid values are<div class="mdetail-params"><ul>
8627 * <li><code>header</code></li>
8628 * <li><code>tbar</code> (top bar)</li>
8629 * <li><code>body</code></li>
8630 * <li><code>bbar</code> (bottom bar)</li>
8631 * <li><code>footer</code></li>
8633 * Defaults to '<code>body</code>'.
8637 * @cfg {Boolean} preventBodyReset
8638 * Defaults to <code>false</code>. When set to <code>true</code>, an extra css class <code>'x-panel-normal'</code>
8639 * will be added to the panel's element, effectively applying css styles suggested by the W3C
8640 * (see http://www.w3.org/TR/CSS21/sample.html) to the Panel's <b>body</b> element (not the header,
8643 preventBodyReset : false,
8646 * @cfg {Number/String} padding
8647 * A shortcut for setting a padding style on the body element. The value can either be
8648 * a number to be applied to all sides, or a normal css string describing padding.
8649 * Defaults to <tt>undefined</tt>.
8654 /** @cfg {String} resizeEvent
8655 * The event to listen to for resizing in layouts. Defaults to <tt>'bodyresize'</tt>.
8657 resizeEvent: 'bodyresize',
8659 // protected - these could be used to customize the behavior of the window,
8660 // but changing them would not be useful without further mofifications and
8661 // could lead to unexpected or undesirable results.
8662 toolTarget : 'header',
8663 collapseEl : 'bwrap',
8667 // private, notify box this class will handle heights
8674 collapseDefaults : {
8679 initComponent : function(){
8680 Ext.Panel.superclass.initComponent.call(this);
8685 * Fires after the Panel has been resized.
8686 * @param {Ext.Panel} p the Panel which has been resized.
8687 * @param {Number} width The Panel's new width.
8688 * @param {Number} height The Panel's new height.
8692 * @event titlechange
8693 * Fires after the Panel title has been {@link #title set} or {@link #setTitle changed}.
8694 * @param {Ext.Panel} p the Panel which has had its title changed.
8695 * @param {String} The new title.
8700 * Fires after the Panel icon class has been {@link #iconCls set} or {@link #setIconClass changed}.
8701 * @param {Ext.Panel} p the Panel which has had its {@link #iconCls icon class} changed.
8702 * @param {String} The new icon class.
8703 * @param {String} The old icon class.
8708 * Fires after the Panel has been collapsed.
8709 * @param {Ext.Panel} p the Panel that has been collapsed.
8714 * Fires after the Panel has been expanded.
8715 * @param {Ext.Panel} p The Panel that has been expanded.
8719 * @event beforecollapse
8720 * Fires before the Panel is collapsed. A handler can return false to cancel the collapse.
8721 * @param {Ext.Panel} p the Panel being collapsed.
8722 * @param {Boolean} animate True if the collapse is animated, else false.
8726 * @event beforeexpand
8727 * Fires before the Panel is expanded. A handler can return false to cancel the expand.
8728 * @param {Ext.Panel} p The Panel being expanded.
8729 * @param {Boolean} animate True if the expand is animated, else false.
8733 * @event beforeclose
8734 * Fires before the Panel is closed. Note that Panels do not directly support being closed, but some
8735 * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel. This event only
8736 * applies to such subclasses.
8737 * A handler can return false to cancel the close.
8738 * @param {Ext.Panel} p The Panel being closed.
8743 * Fires after the Panel is closed. Note that Panels do not directly support being closed, but some
8744 * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel.
8745 * @param {Ext.Panel} p The Panel that has been closed.
8750 * Fires after the Panel has been visually activated.
8751 * Note that Panels do not directly support being activated, but some Panel subclasses
8752 * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
8753 * activate and deactivate events under the control of the TabPanel.
8754 * @param {Ext.Panel} p The Panel that has been activated.
8759 * Fires after the Panel has been visually deactivated.
8760 * Note that Panels do not directly support being deactivated, but some Panel subclasses
8761 * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
8762 * activate and deactivate events under the control of the TabPanel.
8763 * @param {Ext.Panel} p The Panel that has been deactivated.
8769 this.baseCls = 'x-plain';
8776 this.elements += ',tbar';
8777 this.topToolbar = this.createToolbar(this.tbar);
8782 this.elements += ',bbar';
8783 this.bottomToolbar = this.createToolbar(this.bbar);
8787 if(this.header === true){
8788 this.elements += ',header';
8790 }else if(this.headerCfg || (this.title && this.header !== false)){
8791 this.elements += ',header';
8794 if(this.footerCfg || this.footer === true){
8795 this.elements += ',footer';
8800 this.fbar = this.buttons;
8801 delete this.buttons;
8804 this.createFbar(this.fbar);
8807 this.on('render', this.doAutoLoad, this, {delay:10});
8812 createFbar : function(fbar){
8813 var min = this.minButtonWidth;
8814 this.elements += ',footer';
8815 this.fbar = this.createToolbar(fbar, {
8816 buttonAlign: this.buttonAlign,
8817 toolbarCls: 'x-panel-fbar',
8818 enableOverflow: false,
8819 defaults: function(c){
8821 minWidth: c.minWidth || min
8825 //@compat addButton and buttons could possibly be removed
8828 * This Panel's Array of buttons as created from the <code>{@link #buttons}</code>
8829 * config property. Read only.
8833 this.fbar.items.each(function(c){
8834 c.minWidth = c.minWidth || this.minButtonWidth;
8836 this.buttons = this.fbar.items.items;
8840 createToolbar: function(tb, options){
8842 // Convert array to proper toolbar config
8843 if(Ext.isArray(tb)){
8848 result = tb.events ? Ext.apply(tb, options) : this.createComponent(Ext.apply({}, tb, options), 'toolbar');
8849 result.ownerCt = this;
8850 result.bufferResize = false;
8851 this.toolbars.push(result);
8856 createElement : function(name, pnode){
8858 pnode.appendChild(this[name].dom);
8862 if(name === 'bwrap' || this.elements.indexOf(name) != -1){
8863 if(this[name+'Cfg']){
8864 this[name] = Ext.fly(pnode).createChild(this[name+'Cfg']);
8866 var el = document.createElement('div');
8867 el.className = this[name+'Cls'];
8868 this[name] = Ext.get(pnode.appendChild(el));
8870 if(this[name+'CssClass']){
8871 this[name].addClass(this[name+'CssClass']);
8873 if(this[name+'Style']){
8874 this[name].applyStyles(this[name+'Style']);
8880 onRender : function(ct, position){
8881 Ext.Panel.superclass.onRender.call(this, ct, position);
8882 this.createClasses();
8890 if(this.collapsible && !this.hideCollapseTool){
8891 this.tools = this.tools ? this.tools.slice(0) : [];
8892 this.tools[this.collapseFirst?'unshift':'push']({
8894 handler : this.toggleCollapse,
8901 this.elements += (this.header !== false) ? ',header' : '';
8905 el.addClass(this.baseCls);
8906 if(d.firstChild){ // existing markup
8907 this.header = el.down('.'+this.headerCls);
8908 this.bwrap = el.down('.'+this.bwrapCls);
8909 var cp = this.bwrap ? this.bwrap : el;
8910 this.tbar = cp.down('.'+this.tbarCls);
8911 this.body = cp.down('.'+this.bodyCls);
8912 this.bbar = cp.down('.'+this.bbarCls);
8913 this.footer = cp.down('.'+this.footerCls);
8914 this.fromMarkup = true;
8916 if (this.preventBodyReset === true) {
8917 el.addClass('x-panel-reset');
8920 el.addClass(this.cls);
8924 this.elements += ',footer';
8927 // This block allows for maximum flexibility and performance when using existing markup
8929 // framing requires special markup
8931 el.insertHtml('afterBegin', String.format(Ext.Element.boxMarkup, this.baseCls));
8933 this.createElement('header', d.firstChild.firstChild.firstChild);
8934 this.createElement('bwrap', d);
8936 // append the mid and bottom frame to the bwrap
8937 bw = this.bwrap.dom;
8938 var ml = d.childNodes[1], bl = d.childNodes[2];
8942 var mc = bw.firstChild.firstChild.firstChild;
8943 this.createElement('tbar', mc);
8944 this.createElement('body', mc);
8945 this.createElement('bbar', mc);
8946 this.createElement('footer', bw.lastChild.firstChild.firstChild);
8949 this.bwrap.dom.lastChild.className += ' x-panel-nofooter';
8952 * Store a reference to this element so:
8953 * a) We aren't looking it up all the time
8954 * b) The last element is reported incorrectly when using a loadmask
8956 this.ft = Ext.get(this.bwrap.dom.lastChild);
8957 this.mc = Ext.get(mc);
8959 this.createElement('header', d);
8960 this.createElement('bwrap', d);
8962 // append the mid and bottom frame to the bwrap
8963 bw = this.bwrap.dom;
8964 this.createElement('tbar', bw);
8965 this.createElement('body', bw);
8966 this.createElement('bbar', bw);
8967 this.createElement('footer', bw);
8970 this.body.addClass(this.bodyCls + '-noheader');
8972 this.tbar.addClass(this.tbarCls + '-noheader');
8977 if(Ext.isDefined(this.padding)){
8978 this.body.setStyle('padding', this.body.addUnits(this.padding));
8981 if(this.border === false){
8982 this.el.addClass(this.baseCls + '-noborder');
8983 this.body.addClass(this.bodyCls + '-noborder');
8985 this.header.addClass(this.headerCls + '-noborder');
8988 this.footer.addClass(this.footerCls + '-noborder');
8991 this.tbar.addClass(this.tbarCls + '-noborder');
8994 this.bbar.addClass(this.bbarCls + '-noborder');
8998 if(this.bodyBorder === false){
8999 this.body.addClass(this.bodyCls + '-noborder');
9002 this.bwrap.enableDisplayMode('block');
9005 this.header.unselectable();
9007 // for tools, we need to wrap any existing header markup
9008 if(this.headerAsText){
9009 this.header.dom.innerHTML =
9010 '<span class="' + this.headerTextCls + '">'+this.header.dom.innerHTML+'</span>';
9013 this.setIconClass(this.iconCls);
9019 this.makeFloating(this.floating);
9022 if(this.collapsible && this.titleCollapse && this.header){
9023 this.mon(this.header, 'click', this.toggleCollapse, this);
9024 this.header.setStyle('cursor', 'pointer');
9027 this.addTool.apply(this, ts);
9030 this.footer.addClass('x-panel-btns');
9031 this.fbar.render(this.footer);
9032 this.footer.createChild({cls:'x-clear'});
9035 if(this.tbar && this.topToolbar){
9036 this.topToolbar.render(this.tbar);
9038 if(this.bbar && this.bottomToolbar){
9039 this.bottomToolbar.render(this.bbar);
9045 * Sets the CSS class that provides the icon image for this panel. This method will replace any existing
9046 * icon class if one has already been set and fire the {@link #iconchange} event after completion.
9047 * @param {String} cls The new CSS class name
9049 setIconClass : function(cls){
9050 var old = this.iconCls;
9052 if(this.rendered && this.header){
9054 this.header.addClass('x-panel-icon');
9055 this.header.replaceClass(old, this.iconCls);
9057 var hd = this.header,
9058 img = hd.child('img.x-panel-inline-icon');
9060 Ext.fly(img).replaceClass(old, this.iconCls);
9062 Ext.DomHelper.insertBefore(hd.dom.firstChild, {
9063 tag:'img', src: Ext.BLANK_IMAGE_URL, cls:'x-panel-inline-icon '+this.iconCls
9068 this.fireEvent('iconchange', this, cls, old);
9072 makeFloating : function(cfg){
9073 this.floating = true;
9074 this.el = new Ext.Layer(Ext.apply({}, cfg, {
9075 shadow: Ext.isDefined(this.shadow) ? this.shadow : 'sides',
9076 shadowOffset: this.shadowOffset,
9078 shim: this.shim === false ? false : undefined
9083 * Returns the {@link Ext.Toolbar toolbar} from the top (<code>{@link #tbar}</code>) section of the panel.
9084 * @return {Ext.Toolbar} The toolbar
9086 getTopToolbar : function(){
9087 return this.topToolbar;
9091 * Returns the {@link Ext.Toolbar toolbar} from the bottom (<code>{@link #bbar}</code>) section of the panel.
9092 * @return {Ext.Toolbar} The toolbar
9094 getBottomToolbar : function(){
9095 return this.bottomToolbar;
9099 * Adds a button to this panel. Note that this method must be called prior to rendering. The preferred
9100 * approach is to add buttons via the {@link #buttons} config.
9101 * @param {String/Object} config A valid {@link Ext.Button} config. A string will become the text for a default
9102 * button config, an object will be treated as a button config object.
9103 * @param {Function} handler The function to be called on button {@link Ext.Button#click}
9104 * @param {Object} scope The scope (<code>this</code> reference) in which the button handler function is executed. Defaults to the Button.
9105 * @return {Ext.Button} The button that was added
9107 addButton : function(config, handler, scope){
9109 this.createFbar([]);
9112 if(Ext.isString(config)){
9113 config = {text: config};
9115 config = Ext.apply({
9120 return this.fbar.add(config);
9124 addTool : function(){
9129 Ext.each(arguments, function(arg){
9130 this.tools.push(arg)
9134 // nowhere to render tools!
9135 if(!this[this.toolTarget]){
9138 if(!this.toolTemplate){
9139 // initialize the global tool template on first use
9140 var tt = new Ext.Template(
9141 '<div class="x-tool x-tool-{id}"> </div>'
9143 tt.disableFormats = true;
9145 Ext.Panel.prototype.toolTemplate = tt;
9147 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9149 if(!this.tools[tc.id]){
9150 var overCls = 'x-tool-'+tc.id+'-over';
9151 var t = this.toolTemplate.insertFirst((tc.align !== 'left') ? this[this.toolTarget] : this[this.toolTarget].child('span'), tc, true);
9152 this.tools[tc.id] = t;
9153 t.enableDisplayMode('block');
9154 this.mon(t, 'click', this.createToolHandler(t, tc, overCls, this));
9162 if(Ext.isObject(tc.qtip)){
9163 Ext.QuickTips.register(Ext.apply({
9167 t.dom.qtip = tc.qtip;
9170 t.addClassOnOver(overCls);
9175 onLayout : function(shallow, force){
9176 if(this.hasLayout && this.toolbars.length > 0){
9177 Ext.each(this.toolbars, function(tb){
9178 tb.doLayout(undefined, force);
9184 syncHeight : function(){
9185 var h = this.toolbarHeight,
9187 lsh = this.lastSize.height,
9190 if(this.autoHeight || !Ext.isDefined(lsh) || lsh == 'auto'){
9195 if(h != this.getToolbarHeight()){
9196 h = Math.max(0, this.adjustBodyHeight(lsh - this.getFrameHeight()));
9199 this.toolbarHeight = this.getToolbarHeight();
9200 this.onBodyResize(sz.width, sz.height);
9205 onShow : function(){
9207 return this.el.show();
9209 Ext.Panel.superclass.onShow.call(this);
9213 onHide : function(){
9215 return this.el.hide();
9217 Ext.Panel.superclass.onHide.call(this);
9221 createToolHandler : function(t, tc, overCls, panel){
9223 t.removeClass(overCls);
9224 if(tc.stopEvent !== false){
9228 tc.handler.call(tc.scope || t, e, t, panel, tc);
9234 afterRender : function(){
9235 if(this.floating && !this.hidden){
9239 this.setTitle(this.title);
9242 this.collapsed = false;
9243 this.collapse(false);
9245 Ext.Panel.superclass.afterRender.call(this); // do sizing calcs last
9250 getKeyMap : function(){
9252 this.keyMap = new Ext.KeyMap(this.el, this.keys);
9258 initEvents : function(){
9263 this.initDraggable();
9265 if(this.toolbars.length > 0){
9266 Ext.each(this.toolbars, function(tb){
9270 afterlayout: this.syncHeight,
9271 remove: this.syncHeight
9282 initDraggable : function(){
9284 * <p>If this Panel is configured {@link #draggable}, this property will contain
9285 * an instance of {@link Ext.dd.DragSource} which handles dragging the Panel.</p>
9286 * The developer must provide implementations of the abstract methods of {@link Ext.dd.DragSource}
9287 * in order to supply behaviour for each stage of the drag/drop process. See {@link #draggable}.
9288 * @type Ext.dd.DragSource.
9291 this.dd = new Ext.Panel.DD(this, Ext.isBoolean(this.draggable) ? null : this.draggable);
9295 beforeEffect : function(anim){
9297 this.el.beforeAction();
9300 this.el.addClass('x-panel-animated');
9305 afterEffect : function(anim){
9308 this.el.removeClass('x-panel-animated');
9312 // private - wraps up an animation param with internal callbacks
9313 createEffect : function(a, cb, scope){
9321 }else if(!a.callback){
9323 }else { // wrap it up
9324 o.callback = function(){
9326 Ext.callback(a.callback, a.scope);
9329 return Ext.applyIf(o, a);
9333 * Collapses the panel body so that it becomes hidden. Fires the {@link #beforecollapse} event which will
9334 * cancel the collapse action if it returns false.
9335 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
9336 * {@link #animCollapse} panel config)
9337 * @return {Ext.Panel} this
9339 collapse : function(animate){
9340 if(this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforecollapse', this, animate) === false){
9343 var doAnim = animate === true || (animate !== false && this.animCollapse);
9344 this.beforeEffect(doAnim);
9345 this.onCollapse(doAnim, animate);
9350 onCollapse : function(doAnim, animArg){
9352 this[this.collapseEl].slideOut(this.slideAnchor,
9353 Ext.apply(this.createEffect(animArg||true, this.afterCollapse, this),
9354 this.collapseDefaults));
9356 this[this.collapseEl].hide();
9357 this.afterCollapse(false);
9362 afterCollapse : function(anim){
9363 this.collapsed = true;
9364 this.el.addClass(this.collapsedCls);
9365 this.afterEffect(anim);
9366 this.fireEvent('collapse', this);
9370 * Expands the panel body so that it becomes visible. Fires the {@link #beforeexpand} event which will
9371 * cancel the expand action if it returns false.
9372 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
9373 * {@link #animCollapse} panel config)
9374 * @return {Ext.Panel} this
9376 expand : function(animate){
9377 if(!this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforeexpand', this, animate) === false){
9380 var doAnim = animate === true || (animate !== false && this.animCollapse);
9381 this.el.removeClass(this.collapsedCls);
9382 this.beforeEffect(doAnim);
9383 this.onExpand(doAnim, animate);
9388 onExpand : function(doAnim, animArg){
9390 this[this.collapseEl].slideIn(this.slideAnchor,
9391 Ext.apply(this.createEffect(animArg||true, this.afterExpand, this),
9392 this.expandDefaults));
9394 this[this.collapseEl].show();
9395 this.afterExpand(false);
9400 afterExpand : function(anim){
9401 this.collapsed = false;
9402 this.afterEffect(anim);
9403 if(Ext.isDefined(this.deferLayout)){
9404 this.doLayout(true);
9406 this.fireEvent('expand', this);
9410 * Shortcut for performing an {@link #expand} or {@link #collapse} based on the current state of the panel.
9411 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
9412 * {@link #animCollapse} panel config)
9413 * @return {Ext.Panel} this
9415 toggleCollapse : function(animate){
9416 this[this.collapsed ? 'expand' : 'collapse'](animate);
9421 onDisable : function(){
9422 if(this.rendered && this.maskDisabled){
9425 Ext.Panel.superclass.onDisable.call(this);
9429 onEnable : function(){
9430 if(this.rendered && this.maskDisabled){
9433 Ext.Panel.superclass.onEnable.call(this);
9437 onResize : function(w, h){
9438 if(Ext.isDefined(w) || Ext.isDefined(h)){
9439 if(!this.collapsed){
9440 // First, set the the Panel's body width.
9441 // If we have auto-widthed it, get the resulting full offset width so we can size the Toolbars to match
9442 // The Toolbars must not buffer this resize operation because we need to know their heights.
9444 if(Ext.isNumber(w)){
9445 this.body.setWidth(w = this.adjustBodyWidth(w - this.getFrameWidth()));
9446 } else if (w == 'auto') {
9447 w = this.body.setWidth('auto').dom.offsetWidth;
9449 w = this.body.dom.offsetWidth;
9453 this.tbar.setWidth(w);
9454 if(this.topToolbar){
9455 this.topToolbar.setSize(w);
9459 this.bbar.setWidth(w);
9460 if(this.bottomToolbar){
9461 this.bottomToolbar.setSize(w);
9462 // The bbar does not move on resize without this.
9464 this.bbar.setStyle('position', 'static');
9465 this.bbar.setStyle('position', '');
9470 this.footer.setWidth(w);
9472 this.fbar.setSize(Ext.isIE ? (w - this.footer.getFrameWidth('lr')) : 'auto');
9476 // At this point, the Toolbars must be layed out for getFrameHeight to find a result.
9477 if(Ext.isNumber(h)){
9478 h = Math.max(0, this.adjustBodyHeight(h - this.getFrameHeight()));
9479 this.body.setHeight(h);
9480 }else if(h == 'auto'){
9481 this.body.setHeight(h);
9484 if(this.disabled && this.el._mask){
9485 this.el._mask.setSize(this.el.dom.clientWidth, this.el.getHeight());
9488 this.queuedBodySize = {width: w, height: h};
9489 if(!this.queuedExpand && this.allowQueuedExpand !== false){
9490 this.queuedExpand = true;
9491 this.on('expand', function(){
9492 delete this.queuedExpand;
9493 this.onResize(this.queuedBodySize.width, this.queuedBodySize.height);
9494 }, this, {single:true});
9497 this.onBodyResize(w, h);
9500 Ext.Panel.superclass.onResize.call(this);
9504 onBodyResize: function(w, h){
9505 this.fireEvent('bodyresize', this, w, h);
9509 getToolbarHeight: function(){
9512 Ext.each(this.toolbars, function(tb){
9513 h += tb.getHeight();
9520 adjustBodyHeight : function(h){
9525 adjustBodyWidth : function(w){
9530 onPosition : function(){
9535 * Returns the width in pixels of the framing elements of this panel (not including the body width). To
9536 * retrieve the body width see {@link #getInnerWidth}.
9537 * @return {Number} The frame width
9539 getFrameWidth : function(){
9540 var w = this.el.getFrameWidth('lr') + this.bwrap.getFrameWidth('lr');
9543 var l = this.bwrap.dom.firstChild;
9544 w += (Ext.fly(l).getFrameWidth('l') + Ext.fly(l.firstChild).getFrameWidth('r'));
9545 w += this.mc.getFrameWidth('lr');
9551 * Returns the height in pixels of the framing elements of this panel (including any top and bottom bars and
9552 * header and footer elements, but not including the body height). To retrieve the body height see {@link #getInnerHeight}.
9553 * @return {Number} The frame height
9555 getFrameHeight : function(){
9556 var h = this.el.getFrameWidth('tb') + this.bwrap.getFrameWidth('tb');
9557 h += (this.tbar ? this.tbar.getHeight() : 0) +
9558 (this.bbar ? this.bbar.getHeight() : 0);
9561 h += this.el.dom.firstChild.offsetHeight + this.ft.dom.offsetHeight + this.mc.getFrameWidth('tb');
9563 h += (this.header ? this.header.getHeight() : 0) +
9564 (this.footer ? this.footer.getHeight() : 0);
9570 * Returns the width in pixels of the body element (not including the width of any framing elements).
9571 * For the frame width see {@link #getFrameWidth}.
9572 * @return {Number} The body width
9574 getInnerWidth : function(){
9575 return this.getSize().width - this.getFrameWidth();
9579 * Returns the height in pixels of the body element (not including the height of any framing elements).
9580 * For the frame height see {@link #getFrameHeight}.
9581 * @return {Number} The body height
9583 getInnerHeight : function(){
9584 return this.getSize().height - this.getFrameHeight();
9588 syncShadow : function(){
9595 getLayoutTarget : function(){
9600 getContentTarget : function(){
9605 * <p>Sets the title text for the panel and optionally the {@link #iconCls icon class}.</p>
9606 * <p>In order to be able to set the title, a header element must have been created
9607 * for the Panel. This is triggered either by configuring the Panel with a non-blank <code>{@link #title}</code>,
9608 * or configuring it with <code><b>{@link #header}: true</b></code>.</p>
9609 * @param {String} title The title text to set
9610 * @param {String} iconCls (optional) {@link #iconCls iconCls} A user-defined CSS class that provides the icon image for this panel
9612 setTitle : function(title, iconCls){
9614 if(this.header && this.headerAsText){
9615 this.header.child('span').update(title);
9618 this.setIconClass(iconCls);
9620 this.fireEvent('titlechange', this, title);
9625 * Get the {@link Ext.Updater} for this panel. Enables you to perform Ajax updates of this panel's body.
9626 * @return {Ext.Updater} The Updater
9628 getUpdater : function(){
9629 return this.body.getUpdater();
9633 * Loads this content panel immediately with content returned from an XHR call.
9634 * @param {Object/String/Function} config A config object containing any of the following options:
9637 url: 'your-url.php',
9638 params: {param1: 'foo', param2: 'bar'}, // or a URL encoded string
9639 callback: yourFunction,
9640 scope: yourObject, // optional scope for the callback
9648 * The only required property is url. The optional properties nocache, text and scripts
9649 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their
9650 * associated property on this panel Updater instance.
9651 * @return {Ext.Panel} this
9654 var um = this.body.getUpdater();
9655 um.update.apply(um, arguments);
9660 beforeDestroy : function(){
9661 Ext.Panel.superclass.beforeDestroy.call(this);
9663 this.header.removeAllListeners();
9666 for(var k in this.tools){
9667 Ext.destroy(this.tools[k]);
9670 if(Ext.isArray(this.buttons)){
9671 while(this.buttons.length) {
9672 Ext.destroy(this.buttons[0]);
9702 createClasses : function(){
9703 this.headerCls = this.baseCls + '-header';
9704 this.headerTextCls = this.baseCls + '-header-text';
9705 this.bwrapCls = this.baseCls + '-bwrap';
9706 this.tbarCls = this.baseCls + '-tbar';
9707 this.bodyCls = this.baseCls + '-body';
9708 this.bbarCls = this.baseCls + '-bbar';
9709 this.footerCls = this.baseCls + '-footer';
9713 createGhost : function(cls, useShim, appendTo){
9714 var el = document.createElement('div');
9715 el.className = 'x-panel-ghost ' + (cls ? cls : '');
9717 el.appendChild(this.el.dom.firstChild.cloneNode(true));
9719 Ext.fly(el.appendChild(document.createElement('ul'))).setHeight(this.bwrap.getHeight());
9720 el.style.width = this.el.dom.offsetWidth + 'px';;
9722 this.container.dom.appendChild(el);
9724 Ext.getDom(appendTo).appendChild(el);
9726 if(useShim !== false && this.el.useShim !== false){
9727 var layer = new Ext.Layer({shadow:false, useDisplay:true, constrain:false}, el);
9731 return new Ext.Element(el);
9736 doAutoLoad : function(){
9737 var u = this.body.getUpdater();
9739 u.setRenderer(this.renderer);
9741 u.update(Ext.isObject(this.autoLoad) ? this.autoLoad : {url: this.autoLoad});
9745 * Retrieve a tool by id.
9746 * @param {String} id
9747 * @return {Object} tool
9749 getTool : function(id) {
9750 return this.tools[id];
9754 * @cfg {String} autoEl @hide
9757 Ext.reg('panel', Ext.Panel);
9760 * @extends Ext.Component
9761 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
9763 * Create a new Editor
9764 * @param {Object} config The config object
9767 Ext.Editor = function(field, config){
9769 this.field = Ext.create(field.field, 'textfield');
9770 config = Ext.apply({}, field); // copy so we don't disturb original config
9771 delete config.field;
9775 Ext.Editor.superclass.constructor.call(this, config);
9778 Ext.extend(Ext.Editor, Ext.Component, {
9780 * @cfg {Ext.form.Field} field
9781 * The Field object (or descendant) or config object for field
9784 * @cfg {Boolean} allowBlur
9785 * True to {@link #completeEdit complete the editing process} if in edit mode when the
9786 * field is blurred. Defaults to <tt>false</tt>.
9789 * @cfg {Boolean/String} autoSize
9790 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
9791 * or "height" to adopt the height only, "none" to always use the field dimensions. (defaults to false)
9794 * @cfg {Boolean} revertInvalid
9795 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
9796 * validation fails (defaults to true)
9799 * @cfg {Boolean} ignoreNoChange
9800 * True to skip the edit completion process (no save, no events fired) if the user completes an edit and
9801 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
9802 * will never be ignored.
9805 * @cfg {Boolean} hideEl
9806 * False to keep the bound element visible while the editor is displayed (defaults to true)
9809 * @cfg {Mixed} value
9810 * The data value of the underlying field (defaults to "")
9814 * @cfg {String} alignment
9815 * The position to align to (see {@link Ext.Element#alignTo} for more details, defaults to "c-c?").
9819 * @cfg {Array} offsets
9820 * The offsets to use when aligning (see {@link Ext.Element#alignTo} for more details. Defaults to <tt>[0, 0]</tt>.
9824 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
9825 * for bottom-right shadow (defaults to "frame")
9829 * @cfg {Boolean} constrain True to constrain the editor to the viewport
9833 * @cfg {Boolean} swallowKeys Handle the keydown/keypress events so they don't propagate (defaults to true)
9837 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed. Defaults to <tt>true</tt>.
9839 completeOnEnter : true,
9841 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed. Defaults to <tt>true</tt>.
9845 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
9849 initComponent : function(){
9850 Ext.Editor.superclass.initComponent.call(this);
9853 * @event beforestartedit
9854 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
9855 * false from the handler of this event.
9856 * @param {Editor} this
9857 * @param {Ext.Element} boundEl The underlying element bound to this editor
9858 * @param {Mixed} value The field value being set
9863 * Fires when this editor is displayed
9864 * @param {Ext.Element} boundEl The underlying element bound to this editor
9865 * @param {Mixed} value The starting field value
9869 * @event beforecomplete
9870 * Fires after a change has been made to the field, but before the change is reflected in the underlying
9871 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
9872 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
9873 * event will not fire since no edit actually occurred.
9874 * @param {Editor} this
9875 * @param {Mixed} value The current field value
9876 * @param {Mixed} startValue The original field value
9881 * Fires after editing is complete and any changed value has been written to the underlying field.
9882 * @param {Editor} this
9883 * @param {Mixed} value The current field value
9884 * @param {Mixed} startValue The original field value
9889 * Fires after editing has been canceled and the editor's value has been reset.
9890 * @param {Editor} this
9891 * @param {Mixed} value The user-entered field value that was discarded
9892 * @param {Mixed} startValue The original field value that was set back into the editor after cancel
9897 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
9898 * {@link Ext.EventObject#getKey} to determine which key was pressed.
9899 * @param {Ext.form.Field} this
9900 * @param {Ext.EventObject} e The event object
9907 onRender : function(ct, position){
9908 this.el = new Ext.Layer({
9909 shadow: this.shadow,
9913 shadowOffset: this.shadowOffset || 4,
9915 constrain: this.constrain
9918 this.el.setZIndex(this.zIndex);
9920 this.el.setStyle("overflow", Ext.isGecko ? "auto" : "hidden");
9921 if(this.field.msgTarget != 'title'){
9922 this.field.msgTarget = 'qtip';
9924 this.field.inEditor = true;
9925 this.mon(this.field, {
9928 specialkey: this.onSpecialKey
9930 if(this.field.grow){
9931 this.mon(this.field, "autosize", this.el.sync, this.el, {delay:1});
9933 this.field.render(this.el).show();
9934 this.field.getEl().dom.name = '';
9935 if(this.swallowKeys){
9936 this.field.el.swallowEvent([
9937 'keypress', // *** Opera
9938 'keydown' // *** all other browsers
9944 onSpecialKey : function(field, e){
9945 var key = e.getKey(),
9946 complete = this.completeOnEnter && key == e.ENTER,
9947 cancel = this.cancelOnEsc && key == e.ESC;
9948 if(complete || cancel){
9951 this.completeEdit();
9955 if(field.triggerBlur){
9956 field.triggerBlur();
9959 this.fireEvent('specialkey', field, e);
9963 * Starts the editing process and shows the editor.
9964 * @param {Mixed} el The element to edit
9965 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
9966 * to the innerHTML of el.
9968 startEdit : function(el, value){
9970 this.completeEdit();
9972 this.boundEl = Ext.get(el);
9973 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
9975 this.render(this.parentEl || document.body);
9977 if(this.fireEvent("beforestartedit", this, this.boundEl, v) !== false){
9978 this.startValue = v;
9980 this.field.setValue(v);
9982 this.editing = true;
9988 doAutoSize : function(){
9990 var sz = this.boundEl.getSize(),
9991 fs = this.field.getSize();
9993 switch(this.autoSize){
9995 this.setSize(sz.width, fs.height);
9998 this.setSize(fs.width, sz.height);
10001 this.setSize(fs.width, fs.height);
10004 this.setSize(sz.width, sz.height);
10010 * Sets the height and width of this editor.
10011 * @param {Number} width The new width
10012 * @param {Number} height The new height
10014 setSize : function(w, h){
10015 delete this.field.lastSize;
10016 this.field.setSize(w, h);
10018 if(Ext.isGecko2 || Ext.isOpera){
10019 // prevent layer scrollbars
10020 this.el.setSize(w, h);
10027 * Realigns the editor to the bound field based on the current alignment config value.
10028 * @param {Boolean} autoSize (optional) True to size the field to the dimensions of the bound element.
10030 realign : function(autoSize){
10031 if(autoSize === true){
10034 this.el.alignTo(this.boundEl, this.alignment, this.offsets);
10038 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
10039 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
10041 completeEdit : function(remainVisible){
10045 var v = this.getValue();
10046 if(!this.field.isValid()){
10047 if(this.revertInvalid !== false){
10048 this.cancelEdit(remainVisible);
10052 if(String(v) === String(this.startValue) && this.ignoreNoChange){
10053 this.hideEdit(remainVisible);
10056 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
10057 v = this.getValue();
10058 if(this.updateEl && this.boundEl){
10059 this.boundEl.update(v);
10061 this.hideEdit(remainVisible);
10062 this.fireEvent("complete", this, v, this.startValue);
10067 onShow : function(){
10069 if(this.hideEl !== false){
10070 this.boundEl.hide();
10072 this.field.show().focus(false, true);
10073 this.fireEvent("startedit", this.boundEl, this.startValue);
10077 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
10078 * reverted to the original starting value.
10079 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
10080 * cancel (defaults to false)
10082 cancelEdit : function(remainVisible){
10084 var v = this.getValue();
10085 this.setValue(this.startValue);
10086 this.hideEdit(remainVisible);
10087 this.fireEvent("canceledit", this, v, this.startValue);
10092 hideEdit: function(remainVisible){
10093 if(remainVisible !== true){
10094 this.editing = false;
10100 onBlur : function(){
10101 if(this.allowBlur !== true && this.editing){
10102 this.completeEdit();
10107 onHide : function(){
10109 this.completeEdit();
10113 if(this.field.collapse){
10114 this.field.collapse();
10117 if(this.hideEl !== false){
10118 this.boundEl.show();
10123 * Sets the data value of the editor
10124 * @param {Mixed} value Any valid value supported by the underlying field
10126 setValue : function(v){
10127 this.field.setValue(v);
10131 * Gets the data value of the editor
10132 * @return {Mixed} The data value
10134 getValue : function(){
10135 return this.field.getValue();
10138 beforeDestroy : function(){
10139 Ext.destroyMembers(this, 'field');
10141 delete this.parentEl;
10142 delete this.boundEl;
10145 Ext.reg('editor', Ext.Editor);
10147 * @class Ext.ColorPalette
10148 * @extends Ext.Component
10149 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
10150 * Here's an example of typical usage:
10152 var cp = new Ext.ColorPalette({value:'993300'}); // initial selected color
10153 cp.render('my-div');
10155 cp.on('select', function(palette, selColor){
10156 // do something with selColor
10160 * Create a new ColorPalette
10161 * @param {Object} config The config object
10162 * @xtype colorpalette
10164 Ext.ColorPalette = Ext.extend(Ext.Component, {
10166 * @cfg {String} tpl An existing XTemplate instance to be used in place of the default template for rendering the component.
10169 * @cfg {String} itemCls
10170 * The CSS class to apply to the containing element (defaults to 'x-color-palette')
10172 itemCls : 'x-color-palette',
10174 * @cfg {String} value
10175 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
10176 * the hex codes are case-sensitive.
10180 * @cfg {String} clickEvent
10181 * The DOM event that will cause a color to be selected. This can be any valid event name (dblclick, contextmenu).
10182 * Defaults to <tt>'click'</tt>.
10184 clickEvent :'click',
10186 ctype : 'Ext.ColorPalette',
10189 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the {@link #select} event
10191 allowReselect : false,
10194 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
10195 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
10196 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
10197 * of colors with the width setting until the box is symmetrical.</p>
10198 * <p>You can override individual colors if needed:</p>
10200 var cp = new Ext.ColorPalette();
10201 cp.colors[0] = 'FF0000'; // change the first box to red
10204 Or you can provide a custom array of your own for complete control:
10206 var cp = new Ext.ColorPalette();
10207 cp.colors = ['000000', '993300', '333300'];
10212 '000000', '993300', '333300', '003300', '003366', '000080', '333399', '333333',
10213 '800000', 'FF6600', '808000', '008000', '008080', '0000FF', '666699', '808080',
10214 'FF0000', 'FF9900', '99CC00', '339966', '33CCCC', '3366FF', '800080', '969696',
10215 'FF00FF', 'FFCC00', 'FFFF00', '00FF00', '00FFFF', '00CCFF', '993366', 'C0C0C0',
10216 'FF99CC', 'FFCC99', 'FFFF99', 'CCFFCC', 'CCFFFF', '99CCFF', 'CC99FF', 'FFFFFF'
10220 * @cfg {Function} handler
10221 * Optional. A function that will handle the select event of this palette.
10222 * The handler is passed the following parameters:<div class="mdetail-params"><ul>
10223 * <li><code>palette</code> : ColorPalette<div class="sub-desc">The {@link #palette Ext.ColorPalette}.</div></li>
10224 * <li><code>color</code> : String<div class="sub-desc">The 6-digit color hex code (without the # symbol).</div></li>
10228 * @cfg {Object} scope
10229 * The scope (<tt><b>this</b></tt> reference) in which the <code>{@link #handler}</code>
10230 * function will be called. Defaults to this ColorPalette instance.
10234 initComponent : function(){
10235 Ext.ColorPalette.superclass.initComponent.call(this);
10239 * Fires when a color is selected
10240 * @param {ColorPalette} this
10241 * @param {String} color The 6-digit color hex code (without the # symbol)
10247 this.on('select', this.handler, this.scope, true);
10252 onRender : function(container, position){
10257 Ext.ColorPalette.superclass.onRender.call(this, container, position);
10258 var t = this.tpl || new Ext.XTemplate(
10259 '<tpl for="."><a href="#" class="color-{.}" hidefocus="on"><em><span style="background:#{.}" unselectable="on"> </span></em></a></tpl>'
10261 t.overwrite(this.el, this.colors);
10262 this.mon(this.el, this.clickEvent, this.handleClick, this, {delegate: 'a'});
10263 if(this.clickEvent != 'click'){
10264 this.mon(this.el, 'click', Ext.emptyFn, this, {delegate: 'a', preventDefault: true});
10269 afterRender : function(){
10270 Ext.ColorPalette.superclass.afterRender.call(this);
10272 var s = this.value;
10279 handleClick : function(e, t){
10280 e.preventDefault();
10281 if(!this.disabled){
10282 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
10283 this.select(c.toUpperCase());
10288 * Selects the specified color in the palette (fires the {@link #select} event)
10289 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
10291 select : function(color){
10292 color = color.replace('#', '');
10293 if(color != this.value || this.allowReselect){
10296 el.child('a.color-'+this.value).removeClass('x-color-palette-sel');
10298 el.child('a.color-'+color).addClass('x-color-palette-sel');
10299 this.value = color;
10300 this.fireEvent('select', this, color);
10305 * @cfg {String} autoEl @hide
10308 Ext.reg('colorpalette', Ext.ColorPalette);
10310 * @class Ext.DatePicker
10311 * @extends Ext.Component
10312 * <p>A popup date picker. This class is used by the {@link Ext.form.DateField DateField} class
10313 * to allow browsing and selection of valid dates.</p>
10314 * <p>All the string values documented below may be overridden by including an Ext locale file in
10317 * Create a new DatePicker
10318 * @param {Object} config The config object
10319 * @xtype datepicker
10321 Ext.DatePicker = Ext.extend(Ext.BoxComponent, {
10323 * @cfg {String} todayText
10324 * The text to display on the button that selects the current date (defaults to <code>'Today'</code>)
10326 todayText : 'Today',
10328 * @cfg {String} okText
10329 * The text to display on the ok button (defaults to <code>' OK '</code> to give the user extra clicking room)
10331 okText : ' OK ',
10333 * @cfg {String} cancelText
10334 * The text to display on the cancel button (defaults to <code>'Cancel'</code>)
10336 cancelText : 'Cancel',
10338 * @cfg {Function} handler
10339 * Optional. A function that will handle the select event of this picker.
10340 * The handler is passed the following parameters:<div class="mdetail-params"><ul>
10341 * <li><code>picker</code> : DatePicker<div class="sub-desc">This DatePicker.</div></li>
10342 * <li><code>date</code> : Date<div class="sub-desc">The selected date.</div></li>
10346 * @cfg {Object} scope
10347 * The scope (<code><b>this</b></code> reference) in which the <code>{@link #handler}</code>
10348 * function will be called. Defaults to this DatePicker instance.
10351 * @cfg {String} todayTip
10352 * A string used to format the message for displaying in a tooltip over the button that
10353 * selects the current date. Defaults to <code>'{0} (Spacebar)'</code> where
10354 * the <code>{0}</code> token is replaced by today's date.
10356 todayTip : '{0} (Spacebar)',
10358 * @cfg {String} minText
10359 * The error text to display if the minDate validation fails (defaults to <code>'This date is before the minimum date'</code>)
10361 minText : 'This date is before the minimum date',
10363 * @cfg {String} maxText
10364 * The error text to display if the maxDate validation fails (defaults to <code>'This date is after the maximum date'</code>)
10366 maxText : 'This date is after the maximum date',
10368 * @cfg {String} format
10369 * The default date format string which can be overriden for localization support. The format must be
10370 * valid according to {@link Date#parseDate} (defaults to <code>'m/d/y'</code>).
10374 * @cfg {String} disabledDaysText
10375 * The tooltip to display when the date falls on a disabled day (defaults to <code>'Disabled'</code>)
10377 disabledDaysText : 'Disabled',
10379 * @cfg {String} disabledDatesText
10380 * The tooltip text to display when the date falls on a disabled date (defaults to <code>'Disabled'</code>)
10382 disabledDatesText : 'Disabled',
10384 * @cfg {Array} monthNames
10385 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10387 monthNames : Date.monthNames,
10389 * @cfg {Array} dayNames
10390 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10392 dayNames : Date.dayNames,
10394 * @cfg {String} nextText
10395 * The next month navigation button tooltip (defaults to <code>'Next Month (Control+Right)'</code>)
10397 nextText : 'Next Month (Control+Right)',
10399 * @cfg {String} prevText
10400 * The previous month navigation button tooltip (defaults to <code>'Previous Month (Control+Left)'</code>)
10402 prevText : 'Previous Month (Control+Left)',
10404 * @cfg {String} monthYearText
10405 * The header month selector tooltip (defaults to <code>'Choose a month (Control+Up/Down to move years)'</code>)
10407 monthYearText : 'Choose a month (Control+Up/Down to move years)',
10409 * @cfg {Number} startDay
10410 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10414 * @cfg {Boolean} showToday
10415 * False to hide the footer area containing the Today button and disable the keyboard handler for spacebar
10416 * that selects the current date (defaults to <code>true</code>).
10420 * @cfg {Date} minDate
10421 * Minimum allowable date (JavaScript date object, defaults to null)
10424 * @cfg {Date} maxDate
10425 * Maximum allowable date (JavaScript date object, defaults to null)
10428 * @cfg {Array} disabledDays
10429 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10432 * @cfg {RegExp} disabledDatesRE
10433 * JavaScript regular expression used to disable a pattern of dates (defaults to null). The {@link #disabledDates}
10434 * config will generate this regex internally, but if you specify disabledDatesRE it will take precedence over the
10435 * disabledDates value.
10438 * @cfg {Array} disabledDates
10439 * An array of 'dates' to disable, as strings. These strings will be used to build a dynamic regular
10440 * expression so they are very powerful. Some examples:
10442 * <li>['03/08/2003', '09/16/2003'] would disable those exact dates</li>
10443 * <li>['03/08', '09/16'] would disable those days for every year</li>
10444 * <li>['^03/08'] would only match the beginning (useful if you are using short years)</li>
10445 * <li>['03/../2006'] would disable every day in March 2006</li>
10446 * <li>['^03'] would disable every day in every March</li>
10448 * Note that the format of the dates included in the array should exactly match the {@link #format} config.
10449 * In order to support regular expressions, if you are using a date format that has '.' in it, you will have to
10450 * escape the dot when restricting dates. For example: ['03\\.08\\.03'].
10454 // Set by other components to stop the picker focus being updated when the value changes.
10455 focusOnSelect: true,
10458 initComponent : function(){
10459 Ext.DatePicker.superclass.initComponent.call(this);
10461 this.value = this.value ?
10462 this.value.clearTime(true) : new Date().clearTime();
10467 * Fires when a date is selected
10468 * @param {DatePicker} this DatePicker
10469 * @param {Date} date The selected date
10475 this.on('select', this.handler, this.scope || this);
10478 this.initDisabledDays();
10482 initDisabledDays : function(){
10483 if(!this.disabledDatesRE && this.disabledDates){
10484 var dd = this.disabledDates,
10485 len = dd.length - 1,
10488 Ext.each(dd, function(d, i){
10489 re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i];
10494 this.disabledDatesRE = new RegExp(re + ')');
10499 * Replaces any existing disabled dates with new values and refreshes the DatePicker.
10500 * @param {Array/RegExp} disabledDates An array of date strings (see the {@link #disabledDates} config
10501 * for details on supported values), or a JavaScript regular expression used to disable a pattern of dates.
10503 setDisabledDates : function(dd){
10504 if(Ext.isArray(dd)){
10505 this.disabledDates = dd;
10506 this.disabledDatesRE = null;
10508 this.disabledDatesRE = dd;
10510 this.initDisabledDays();
10511 this.update(this.value, true);
10515 * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.
10516 * @param {Array} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config
10517 * for details on supported values.
10519 setDisabledDays : function(dd){
10520 this.disabledDays = dd;
10521 this.update(this.value, true);
10525 * Replaces any existing {@link #minDate} with the new value and refreshes the DatePicker.
10526 * @param {Date} value The minimum date that can be selected
10528 setMinDate : function(dt){
10530 this.update(this.value, true);
10534 * Replaces any existing {@link #maxDate} with the new value and refreshes the DatePicker.
10535 * @param {Date} value The maximum date that can be selected
10537 setMaxDate : function(dt){
10539 this.update(this.value, true);
10543 * Sets the value of the date field
10544 * @param {Date} value The date to set
10546 setValue : function(value){
10547 this.value = value.clearTime(true);
10548 this.update(this.value);
10552 * Gets the current selected value of the date field
10553 * @return {Date} The selected date
10555 getValue : function(){
10560 focus : function(){
10561 this.update(this.activeDate);
10565 onEnable: function(initial){
10566 Ext.DatePicker.superclass.onEnable.call(this);
10567 this.doDisabled(false);
10568 this.update(initial ? this.value : this.activeDate);
10576 onDisable : function(){
10577 Ext.DatePicker.superclass.onDisable.call(this);
10578 this.doDisabled(true);
10579 if(Ext.isIE && !Ext.isIE8){
10580 /* Really strange problem in IE6/7, when disabled, have to explicitly
10581 * repaint each of the nodes to get them to display correctly, simply
10582 * calling repaint on the main element doesn't appear to be enough.
10584 Ext.each([].concat(this.textNodes, this.el.query('th span')), function(el){
10585 Ext.fly(el).repaint();
10591 doDisabled : function(disabled){
10592 this.keyNav.setDisabled(disabled);
10593 this.prevRepeater.setDisabled(disabled);
10594 this.nextRepeater.setDisabled(disabled);
10595 if(this.showToday){
10596 this.todayKeyListener.setDisabled(disabled);
10597 this.todayBtn.setDisabled(disabled);
10602 onRender : function(container, position){
10604 '<table cellspacing="0">',
10605 '<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>',
10606 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'],
10607 dn = this.dayNames,
10609 for(i = 0; i < 7; i++){
10610 var d = this.startDay+i;
10614 m.push('<th><span>', dn[d].substr(0,1), '</span></th>');
10616 m[m.length] = '</tr></thead><tbody><tr>';
10617 for(i = 0; i < 42; i++) {
10618 if(i % 7 === 0 && i !== 0){
10619 m[m.length] = '</tr><tr>';
10621 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10623 m.push('</tr></tbody></table></td></tr>',
10624 this.showToday ? '<tr><td colspan="3" class="x-date-bottom" align="center"></td></tr>' : '',
10625 '</table><div class="x-date-mp"></div>');
10627 var el = document.createElement('div');
10628 el.className = 'x-date-picker';
10629 el.innerHTML = m.join('');
10631 container.dom.insertBefore(el, position);
10633 this.el = Ext.get(el);
10634 this.eventEl = Ext.get(el.firstChild);
10636 this.prevRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-left a'), {
10637 handler: this.showPrevMonth,
10639 preventDefault:true,
10643 this.nextRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-right a'), {
10644 handler: this.showNextMonth,
10646 preventDefault:true,
10650 this.monthPicker = this.el.down('div.x-date-mp');
10651 this.monthPicker.enableDisplayMode('block');
10653 this.keyNav = new Ext.KeyNav(this.eventEl, {
10654 'left' : function(e){
10656 this.showPrevMonth();
10658 this.update(this.activeDate.add('d', -1));
10662 'right' : function(e){
10664 this.showNextMonth();
10666 this.update(this.activeDate.add('d', 1));
10670 'up' : function(e){
10672 this.showNextYear();
10674 this.update(this.activeDate.add('d', -7));
10678 'down' : function(e){
10680 this.showPrevYear();
10682 this.update(this.activeDate.add('d', 7));
10686 'pageUp' : function(e){
10687 this.showNextMonth();
10690 'pageDown' : function(e){
10691 this.showPrevMonth();
10694 'enter' : function(e){
10695 e.stopPropagation();
10702 this.el.unselectable();
10704 this.cells = this.el.select('table.x-date-inner tbody td');
10705 this.textNodes = this.el.query('table.x-date-inner tbody span');
10707 this.mbtn = new Ext.Button({
10709 tooltip: this.monthYearText,
10710 renderTo: this.el.child('td.x-date-middle', true)
10712 this.mbtn.el.child('em').addClass('x-btn-arrow');
10714 if(this.showToday){
10715 this.todayKeyListener = this.eventEl.addKeyListener(Ext.EventObject.SPACE, this.selectToday, this);
10716 var today = (new Date()).dateFormat(this.format);
10717 this.todayBtn = new Ext.Button({
10718 renderTo: this.el.child('td.x-date-bottom', true),
10719 text: String.format(this.todayText, today),
10720 tooltip: String.format(this.todayTip, today),
10721 handler: this.selectToday,
10725 this.mon(this.eventEl, 'mousewheel', this.handleMouseWheel, this);
10726 this.mon(this.eventEl, 'click', this.handleDateClick, this, {delegate: 'a.x-date-date'});
10727 this.mon(this.mbtn, 'click', this.showMonthPicker, this);
10728 this.onEnable(true);
10732 createMonthPicker : function(){
10733 if(!this.monthPicker.dom.firstChild){
10734 var buf = ['<table border="0" cellspacing="0">'];
10735 for(var i = 0; i < 6; i++){
10737 '<tr><td class="x-date-mp-month"><a href="#">', Date.getShortMonthName(i), '</a></td>',
10738 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', Date.getShortMonthName(i + 6), '</a></td>',
10740 '<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>' :
10741 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10745 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10747 '</button><button type="button" class="x-date-mp-cancel">',
10749 '</button></td></tr>',
10752 this.monthPicker.update(buf.join(''));
10754 this.mon(this.monthPicker, 'click', this.onMonthClick, this);
10755 this.mon(this.monthPicker, 'dblclick', this.onMonthDblClick, this);
10757 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10758 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10760 this.mpMonths.each(function(m, a, i){
10763 m.dom.xmonth = 5 + Math.round(i * 0.5);
10765 m.dom.xmonth = Math.round((i-1) * 0.5);
10772 showMonthPicker : function(){
10773 if(!this.disabled){
10774 this.createMonthPicker();
10775 var size = this.el.getSize();
10776 this.monthPicker.setSize(size);
10777 this.monthPicker.child('table').setSize(size);
10779 this.mpSelMonth = (this.activeDate || this.value).getMonth();
10780 this.updateMPMonth(this.mpSelMonth);
10781 this.mpSelYear = (this.activeDate || this.value).getFullYear();
10782 this.updateMPYear(this.mpSelYear);
10784 this.monthPicker.slideIn('t', {duration:0.2});
10789 updateMPYear : function(y){
10791 var ys = this.mpYears.elements;
10792 for(var i = 1; i <= 10; i++){
10793 var td = ys[i-1], y2;
10795 y2 = y + Math.round(i * 0.5);
10796 td.firstChild.innerHTML = y2;
10799 y2 = y - (5-Math.round(i * 0.5));
10800 td.firstChild.innerHTML = y2;
10803 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10808 updateMPMonth : function(sm){
10809 this.mpMonths.each(function(m, a, i){
10810 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10815 selectMPMonth : function(m){
10820 onMonthClick : function(e, t){
10822 var el = new Ext.Element(t), pn;
10823 if(el.is('button.x-date-mp-cancel')){
10824 this.hideMonthPicker();
10826 else if(el.is('button.x-date-mp-ok')){
10827 var d = new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate());
10828 if(d.getMonth() != this.mpSelMonth){
10829 // 'fix' the JS rolling date conversion if needed
10830 d = new Date(this.mpSelYear, this.mpSelMonth, 1).getLastDateOfMonth();
10833 this.hideMonthPicker();
10835 else if((pn = el.up('td.x-date-mp-month', 2))){
10836 this.mpMonths.removeClass('x-date-mp-sel');
10837 pn.addClass('x-date-mp-sel');
10838 this.mpSelMonth = pn.dom.xmonth;
10840 else if((pn = el.up('td.x-date-mp-year', 2))){
10841 this.mpYears.removeClass('x-date-mp-sel');
10842 pn.addClass('x-date-mp-sel');
10843 this.mpSelYear = pn.dom.xyear;
10845 else if(el.is('a.x-date-mp-prev')){
10846 this.updateMPYear(this.mpyear-10);
10848 else if(el.is('a.x-date-mp-next')){
10849 this.updateMPYear(this.mpyear+10);
10854 onMonthDblClick : function(e, t){
10856 var el = new Ext.Element(t), pn;
10857 if((pn = el.up('td.x-date-mp-month', 2))){
10858 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10859 this.hideMonthPicker();
10861 else if((pn = el.up('td.x-date-mp-year', 2))){
10862 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10863 this.hideMonthPicker();
10868 hideMonthPicker : function(disableAnim){
10869 if(this.monthPicker){
10870 if(disableAnim === true){
10871 this.monthPicker.hide();
10873 this.monthPicker.slideOut('t', {duration:0.2});
10879 showPrevMonth : function(e){
10880 this.update(this.activeDate.add('mo', -1));
10884 showNextMonth : function(e){
10885 this.update(this.activeDate.add('mo', 1));
10889 showPrevYear : function(){
10890 this.update(this.activeDate.add('y', -1));
10894 showNextYear : function(){
10895 this.update(this.activeDate.add('y', 1));
10899 handleMouseWheel : function(e){
10901 if(!this.disabled){
10902 var delta = e.getWheelDelta();
10904 this.showPrevMonth();
10905 } else if(delta < 0){
10906 this.showNextMonth();
10912 handleDateClick : function(e, t){
10914 if(!this.disabled && t.dateValue && !Ext.fly(t.parentNode).hasClass('x-date-disabled')){
10915 this.cancelFocus = this.focusOnSelect === false;
10916 this.setValue(new Date(t.dateValue));
10917 delete this.cancelFocus;
10918 this.fireEvent('select', this, this.value);
10923 selectToday : function(){
10924 if(this.todayBtn && !this.todayBtn.disabled){
10925 this.setValue(new Date().clearTime());
10926 this.fireEvent('select', this, this.value);
10931 update : function(date, forceRefresh){
10933 var vd = this.activeDate, vis = this.isVisible();
10934 this.activeDate = date;
10935 if(!forceRefresh && vd && this.el){
10936 var t = date.getTime();
10937 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10938 this.cells.removeClass('x-date-selected');
10939 this.cells.each(function(c){
10940 if(c.dom.firstChild.dateValue == t){
10941 c.addClass('x-date-selected');
10942 if(vis && !this.cancelFocus){
10943 Ext.fly(c.dom.firstChild).focus(50);
10951 var days = date.getDaysInMonth(),
10952 firstOfMonth = date.getFirstDateOfMonth(),
10953 startingPos = firstOfMonth.getDay()-this.startDay;
10955 if(startingPos < 0){
10958 days += startingPos;
10960 var pm = date.add('mo', -1),
10961 prevStart = pm.getDaysInMonth()-startingPos,
10962 cells = this.cells.elements,
10963 textEls = this.textNodes,
10964 // convert everything to numbers so it's fast
10966 d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime(),
10967 today = new Date().clearTime().getTime(),
10968 sel = date.clearTime(true).getTime(),
10969 min = this.minDate ? this.minDate.clearTime(true) : Number.NEGATIVE_INFINITY,
10970 max = this.maxDate ? this.maxDate.clearTime(true) : Number.POSITIVE_INFINITY,
10971 ddMatch = this.disabledDatesRE,
10972 ddText = this.disabledDatesText,
10973 ddays = this.disabledDays ? this.disabledDays.join('') : false,
10974 ddaysText = this.disabledDaysText,
10975 format = this.format;
10977 if(this.showToday){
10978 var td = new Date().clearTime(),
10979 disable = (td < min || td > max ||
10980 (ddMatch && format && ddMatch.test(td.dateFormat(format))) ||
10981 (ddays && ddays.indexOf(td.getDay()) != -1));
10983 if(!this.disabled){
10984 this.todayBtn.setDisabled(disable);
10985 this.todayKeyListener[disable ? 'disable' : 'enable']();
10989 var setCellClass = function(cal, cell){
10991 var t = d.getTime();
10992 cell.firstChild.dateValue = t;
10994 cell.className += ' x-date-today';
10995 cell.title = cal.todayText;
10998 cell.className += ' x-date-selected';
11000 Ext.fly(cell.firstChild).focus(50);
11005 cell.className = ' x-date-disabled';
11006 cell.title = cal.minText;
11010 cell.className = ' x-date-disabled';
11011 cell.title = cal.maxText;
11015 if(ddays.indexOf(d.getDay()) != -1){
11016 cell.title = ddaysText;
11017 cell.className = ' x-date-disabled';
11020 if(ddMatch && format){
11021 var fvalue = d.dateFormat(format);
11022 if(ddMatch.test(fvalue)){
11023 cell.title = ddText.replace('%0', fvalue);
11024 cell.className = ' x-date-disabled';
11030 for(; i < startingPos; i++) {
11031 textEls[i].innerHTML = (++prevStart);
11032 d.setDate(d.getDate()+1);
11033 cells[i].className = 'x-date-prevday';
11034 setCellClass(this, cells[i]);
11036 for(; i < days; i++){
11037 var intDay = i - startingPos + 1;
11038 textEls[i].innerHTML = (intDay);
11039 d.setDate(d.getDate()+1);
11040 cells[i].className = 'x-date-active';
11041 setCellClass(this, cells[i]);
11044 for(; i < 42; i++) {
11045 textEls[i].innerHTML = (++extraDays);
11046 d.setDate(d.getDate()+1);
11047 cells[i].className = 'x-date-nextday';
11048 setCellClass(this, cells[i]);
11051 this.mbtn.setText(this.monthNames[date.getMonth()] + ' ' + date.getFullYear());
11053 if(!this.internalRender){
11054 var main = this.el.dom.firstChild,
11055 w = main.offsetWidth;
11056 this.el.setWidth(w + this.el.getBorderWidth('lr'));
11057 Ext.fly(main).setWidth(w);
11058 this.internalRender = true;
11059 // opera does not respect the auto grow header center column
11060 // then, after it gets a width opera refuses to recalculate
11061 // without a second pass
11062 if(Ext.isOpera && !this.secondPass){
11063 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + 'px';
11064 this.secondPass = true;
11065 this.update.defer(10, this, [date]);
11072 beforeDestroy : function() {
11084 delete this.textNodes;
11085 delete this.cells.elements;
11090 * @cfg {String} autoEl @hide
11094 Ext.reg('datepicker', Ext.DatePicker);
11096 * @class Ext.LoadMask
11097 * A simple utility class for generically masking elements while loading data. If the {@link #store}
11098 * config option is specified, the masking will be automatically synchronized with the store's loading
11099 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
11100 * element's Updater load indicator and will be destroyed after the initial load.
11101 * <p>Example usage:</p>
11104 var myMask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait..."});
11108 * Create a new LoadMask
11109 * @param {Mixed} el The element or DOM node, or its id
11110 * @param {Object} config The config object
11112 Ext.LoadMask = function(el, config){
11113 this.el = Ext.get(el);
11114 Ext.apply(this, config);
11118 beforeload: this.onBeforeLoad,
11120 exception: this.onLoad
11122 this.removeMask = Ext.value(this.removeMask, false);
11124 var um = this.el.getUpdater();
11125 um.showLoadIndicator = false; // disable the default indicator
11128 beforeupdate: this.onBeforeLoad,
11129 update: this.onLoad,
11130 failure: this.onLoad
11132 this.removeMask = Ext.value(this.removeMask, true);
11136 Ext.LoadMask.prototype = {
11138 * @cfg {Ext.data.Store} store
11139 * Optional Store to which the mask is bound. The mask is displayed when a load request is issued, and
11140 * hidden on either load sucess, or load fail.
11143 * @cfg {Boolean} removeMask
11144 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
11145 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
11148 * @cfg {String} msg
11149 * The text to display in a centered loading message box (defaults to 'Loading...')
11151 msg : 'Loading...',
11153 * @cfg {String} msgCls
11154 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
11156 msgCls : 'x-mask-loading',
11159 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
11165 * Disables the mask to prevent it from being displayed
11167 disable : function(){
11168 this.disabled = true;
11172 * Enables the mask so that it can be displayed
11174 enable : function(){
11175 this.disabled = false;
11179 onLoad : function(){
11180 this.el.unmask(this.removeMask);
11184 onBeforeLoad : function(){
11185 if(!this.disabled){
11186 this.el.mask(this.msg, this.msgCls);
11191 * Show this LoadMask over the configured Element.
11194 this.onBeforeLoad();
11198 * Hide this LoadMask.
11205 destroy : function(){
11207 this.store.un('beforeload', this.onBeforeLoad, this);
11208 this.store.un('load', this.onLoad, this);
11209 this.store.un('exception', this.onLoad, this);
11211 var um = this.el.getUpdater();
11212 um.un('beforeupdate', this.onBeforeLoad, this);
11213 um.un('update', this.onLoad, this);
11214 um.un('failure', this.onLoad, this);
11218 * @class Ext.Slider
\r
11219 * @extends Ext.BoxComponent
\r
11220 * Slider which supports vertical or horizontal orientation, keyboard adjustments,
\r
11221 * configurable snapping, axis clicking and animation. Can be added as an item to
\r
11222 * any container. Example usage:
\r
11225 renderTo: Ext.getBody(),
\r
11234 Ext.Slider = Ext.extend(Ext.BoxComponent, {
\r
11236 * @cfg {Number} value The value to initialize the slider with. Defaults to minValue.
\r
11239 * @cfg {Boolean} vertical Orient the Slider vertically rather than horizontally, defaults to false.
\r
11243 * @cfg {Number} minValue The minimum value for the Slider. Defaults to 0.
\r
11247 * @cfg {Number} maxValue The maximum value for the Slider. Defaults to 100.
\r
11251 * @cfg {Number/Boolean} decimalPrecision.
\r
11252 * <p>The number of decimal places to which to round the Slider's value. Defaults to 0.</p>
\r
11253 * <p>To disable rounding, configure as <tt><b>false</b></tt>.</p>
\r
11255 decimalPrecision: 0,
\r
11257 * @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.
\r
11261 * @cfg {Number} increment How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'.
\r
11265 clickRange: [5,15],
\r
11267 * @cfg {Boolean} clickToChange Determines whether or not clicking on the Slider axis will change the slider. Defaults to true
\r
11269 clickToChange : true,
\r
11271 * @cfg {Boolean} animate Turn on or off animation. Defaults to true
\r
11276 * True while the thumb is in a drag operation
\r
11281 // private override
\r
11282 initComponent : function(){
\r
11283 if(!Ext.isDefined(this.value)){
\r
11284 this.value = this.minValue;
\r
11286 Ext.Slider.superclass.initComponent.call(this);
\r
11287 this.keyIncrement = Math.max(this.increment, this.keyIncrement);
\r
11290 * @event beforechange
\r
11291 * Fires before the slider value is changed. By returning false from an event handler,
\r
11292 * you can cancel the event and prevent the slider from changing.
\r
11293 * @param {Ext.Slider} slider The slider
\r
11294 * @param {Number} newValue The new value which the slider is being changed to.
\r
11295 * @param {Number} oldValue The old value which the slider was previously.
\r
11300 * Fires when the slider value is changed.
\r
11301 * @param {Ext.Slider} slider The slider
\r
11302 * @param {Number} newValue The new value which the slider has been changed to.
\r
11306 * @event changecomplete
\r
11307 * Fires when the slider value is changed by the user and any drag operations have completed.
\r
11308 * @param {Ext.Slider} slider The slider
\r
11309 * @param {Number} newValue The new value which the slider has been changed to.
\r
11311 'changecomplete',
\r
11313 * @event dragstart
\r
11314 * Fires after a drag operation has started.
\r
11315 * @param {Ext.Slider} slider The slider
\r
11316 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
\r
11321 * Fires continuously during the drag operation while the mouse is moving.
\r
11322 * @param {Ext.Slider} slider The slider
\r
11323 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
\r
11328 * Fires after the drag operation has completed.
\r
11329 * @param {Ext.Slider} slider The slider
\r
11330 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
\r
11335 if(this.vertical){
\r
11336 Ext.apply(this, Ext.Slider.Vertical);
\r
11340 // private override
\r
11341 onRender : function(){
\r
11343 cls: 'x-slider ' + (this.vertical ? 'x-slider-vert' : 'x-slider-horz'),
\r
11344 cn:{cls:'x-slider-end',cn:{cls:'x-slider-inner',cn:[{cls:'x-slider-thumb'},{tag:'a', cls:'x-slider-focus', href:"#", tabIndex: '-1', hidefocus:'on'}]}}
\r
11346 Ext.Slider.superclass.onRender.apply(this, arguments);
\r
11347 this.endEl = this.el.first();
\r
11348 this.innerEl = this.endEl.first();
\r
11349 this.thumb = this.innerEl.first();
\r
11350 this.halfThumb = (this.vertical ? this.thumb.getHeight() : this.thumb.getWidth())/2;
\r
11351 this.focusEl = this.thumb.next();
\r
11352 this.initEvents();
\r
11355 // private override
\r
11356 initEvents : function(){
\r
11357 this.thumb.addClassOnOver('x-slider-thumb-over');
\r
11358 this.mon(this.el, {
\r
11360 mousedown: this.onMouseDown,
\r
11361 keydown: this.onKeyDown
\r
11364 this.focusEl.swallowEvent("click", true);
\r
11366 this.tracker = new Ext.dd.DragTracker({
\r
11367 onBeforeStart: this.onBeforeDragStart.createDelegate(this),
\r
11368 onStart: this.onDragStart.createDelegate(this),
\r
11369 onDrag: this.onDrag.createDelegate(this),
\r
11370 onEnd: this.onDragEnd.createDelegate(this),
\r
11374 this.tracker.initEl(this.thumb);
\r
11377 // private override
\r
11378 onMouseDown : function(e){
\r
11379 if(this.disabled){
\r
11382 if(this.clickToChange && e.target != this.thumb.dom){
\r
11383 var local = this.innerEl.translatePoints(e.getXY());
\r
11384 this.onClickChange(local);
\r
11390 onClickChange : function(local){
\r
11391 if(local.top > this.clickRange[0] && local.top < this.clickRange[1]){
\r
11392 this.setValue(Ext.util.Format.round(this.reverseValue(local.left), this.decimalPrecision), undefined, true);
\r
11397 onKeyDown : function(e){
\r
11398 if(this.disabled){e.preventDefault();return;}
\r
11399 var k = e.getKey();
\r
11405 this.setValue(this.maxValue, undefined, true);
\r
11407 this.setValue(this.value+this.keyIncrement, undefined, true);
\r
11414 this.setValue(this.minValue, undefined, true);
\r
11416 this.setValue(this.value-this.keyIncrement, undefined, true);
\r
11420 e.preventDefault();
\r
11425 doSnap : function(value){
\r
11426 if(!(this.increment && value)){
\r
11429 var newValue = value,
\r
11430 inc = this.increment,
\r
11436 }else if(m * 2 < -inc){
\r
11440 return newValue.constrain(this.minValue, this.maxValue);
\r
11444 afterRender : function(){
\r
11445 Ext.Slider.superclass.afterRender.apply(this, arguments);
\r
11446 if(this.value !== undefined){
\r
11447 var v = this.normalizeValue(this.value);
\r
11448 if(v !== this.value){
\r
11449 delete this.value;
\r
11450 this.setValue(v, false);
\r
11452 this.moveThumb(this.translateValue(v), false);
\r
11458 getRatio : function(){
\r
11459 var w = this.innerEl.getWidth(),
\r
11460 v = this.maxValue - this.minValue;
\r
11461 return v == 0 ? w : (w/v);
\r
11465 normalizeValue : function(v){
\r
11466 v = this.doSnap(v);
\r
11467 v = Ext.util.Format.round(v, this.decimalPrecision);
\r
11468 v = v.constrain(this.minValue, this.maxValue);
\r
11473 * Programmatically sets the value of the Slider. Ensures that the value is constrained within
\r
11474 * the minValue and maxValue.
\r
11475 * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
\r
11476 * @param {Boolean} animate Turn on or off animation, defaults to true
\r
11478 setValue : function(v, animate, changeComplete){
\r
11479 v = this.normalizeValue(v);
\r
11480 if(v !== this.value && this.fireEvent('beforechange', this, v, this.value) !== false){
\r
11482 this.moveThumb(this.translateValue(v), animate !== false);
\r
11483 this.fireEvent('change', this, v);
\r
11484 if(changeComplete){
\r
11485 this.fireEvent('changecomplete', this, v);
\r
11491 translateValue : function(v){
\r
11492 var ratio = this.getRatio();
\r
11493 return (v * ratio) - (this.minValue * ratio) - this.halfThumb;
\r
11496 reverseValue : function(pos){
\r
11497 var ratio = this.getRatio();
\r
11498 return (pos + this.halfThumb + (this.minValue * ratio)) / ratio;
\r
11502 moveThumb: function(v, animate){
\r
11503 if(!animate || this.animate === false){
\r
11504 this.thumb.setLeft(v);
\r
11506 this.thumb.shift({left: v, stopFx: true, duration:.35});
\r
11511 focus : function(){
\r
11512 this.focusEl.focus(10);
\r
11516 onBeforeDragStart : function(e){
\r
11517 return !this.disabled;
\r
11521 onDragStart: function(e){
\r
11522 this.thumb.addClass('x-slider-thumb-drag');
\r
11523 this.dragging = true;
\r
11524 this.dragStartValue = this.value;
\r
11525 this.fireEvent('dragstart', this, e);
\r
11529 onDrag: function(e){
\r
11530 var pos = this.innerEl.translatePoints(this.tracker.getXY());
\r
11531 this.setValue(Ext.util.Format.round(this.reverseValue(pos.left), this.decimalPrecision), false);
\r
11532 this.fireEvent('drag', this, e);
\r
11536 onDragEnd: function(e){
\r
11537 this.thumb.removeClass('x-slider-thumb-drag');
\r
11538 this.dragging = false;
\r
11539 this.fireEvent('dragend', this, e);
\r
11540 if(this.dragStartValue != this.value){
\r
11541 this.fireEvent('changecomplete', this, this.value);
\r
11546 onResize : function(w, h){
\r
11547 this.innerEl.setWidth(w - (this.el.getPadding('l') + this.endEl.getPadding('r')));
\r
11548 this.syncThumb();
\r
11552 onDisable: function(){
\r
11553 Ext.Slider.superclass.onDisable.call(this);
\r
11554 this.thumb.addClass(this.disabledClass);
\r
11556 //IE breaks when using overflow visible and opacity other than 1.
\r
11557 //Create a place holder for the thumb and display it.
\r
11558 var xy = this.thumb.getXY();
\r
11559 this.thumb.hide();
\r
11560 this.innerEl.addClass(this.disabledClass).dom.disabled = true;
\r
11561 if (!this.thumbHolder){
\r
11562 this.thumbHolder = this.endEl.createChild({cls: 'x-slider-thumb ' + this.disabledClass});
\r
11564 this.thumbHolder.show().setXY(xy);
\r
11569 onEnable: function(){
\r
11570 Ext.Slider.superclass.onEnable.call(this);
\r
11571 this.thumb.removeClass(this.disabledClass);
\r
11573 this.innerEl.removeClass(this.disabledClass).dom.disabled = false;
\r
11574 if(this.thumbHolder){
\r
11575 this.thumbHolder.hide();
\r
11577 this.thumb.show();
\r
11578 this.syncThumb();
\r
11583 * Synchronizes the thumb position to the proper proportion of the total component width based
\r
11584 * on the current slider {@link #value}. This will be called automatically when the Slider
\r
11585 * is resized by a layout, but if it is rendered auto width, this method can be called from
\r
11586 * another resize handler to sync the Slider if necessary.
\r
11588 syncThumb : function(){
\r
11589 if(this.rendered){
\r
11590 this.moveThumb(this.translateValue(this.value));
\r
11595 * Returns the current value of the slider
\r
11596 * @return {Number} The current value of the slider
\r
11598 getValue : function(){
\r
11599 return this.value;
\r
11603 beforeDestroy : function(){
\r
11604 Ext.destroyMembers(this, 'endEl', 'innerEl', 'thumb', 'halfThumb', 'focusEl', 'tracker', 'thumbHolder');
\r
11605 Ext.Slider.superclass.beforeDestroy.call(this);
\r
11608 Ext.reg('slider', Ext.Slider);
\r
11610 // private class to support vertical sliders
\r
11611 Ext.Slider.Vertical = {
\r
11612 onResize : function(w, h){
\r
11613 this.innerEl.setHeight(h - (this.el.getPadding('t') + this.endEl.getPadding('b')));
\r
11614 this.syncThumb();
\r
11617 getRatio : function(){
\r
11618 var h = this.innerEl.getHeight(),
\r
11619 v = this.maxValue - this.minValue;
\r
11623 moveThumb: function(v, animate){
\r
11624 if(!animate || this.animate === false){
\r
11625 this.thumb.setBottom(v);
\r
11627 this.thumb.shift({bottom: v, stopFx: true, duration:.35});
\r
11631 onDrag: function(e){
\r
11632 var pos = this.innerEl.translatePoints(this.tracker.getXY()),
\r
11633 bottom = this.innerEl.getHeight()-pos.top;
\r
11634 this.setValue(this.minValue + Ext.util.Format.round(bottom/this.getRatio(), this.decimalPrecision), false);
\r
11635 this.fireEvent('drag', this, e);
\r
11638 onClickChange : function(local){
\r
11639 if(local.left > this.clickRange[0] && local.left < this.clickRange[1]){
\r
11640 var bottom = this.innerEl.getHeight() - local.top;
\r
11641 this.setValue(this.minValue + Ext.util.Format.round(bottom/this.getRatio(), this.decimalPrecision), undefined, true);
\r
11645 * @class Ext.ProgressBar
\r
11646 * @extends Ext.BoxComponent
\r
11647 * <p>An updateable progress bar component. The progress bar supports two different modes: manual and automatic.</p>
\r
11648 * <p>In manual mode, you are responsible for showing, updating (via {@link #updateProgress}) and clearing the
\r
11649 * progress bar as needed from your own code. This method is most appropriate when you want to show progress
\r
11650 * throughout an operation that has predictable points of interest at which you can update the control.</p>
\r
11651 * <p>In automatic mode, you simply call {@link #wait} and let the progress bar run indefinitely, only clearing it
\r
11652 * once the operation is complete. You can optionally have the progress bar wait for a specific amount of time
\r
11653 * and then clear itself. Automatic mode is most appropriate for timed operations or asynchronous operations in
\r
11654 * which you have no need for indicating intermediate progress.</p>
\r
11655 * @cfg {Float} value A floating point value between 0 and 1 (e.g., .5, defaults to 0)
\r
11656 * @cfg {String} text The progress bar text (defaults to '')
\r
11657 * @cfg {Mixed} textEl The element to render the progress text to (defaults to the progress
\r
11658 * bar's internal text element)
\r
11659 * @cfg {String} id The progress bar element's id (defaults to an auto-generated id)
\r
11660 * @xtype progress
\r
11662 Ext.ProgressBar = Ext.extend(Ext.BoxComponent, {
\r
11664 * @cfg {String} baseCls
\r
11665 * The base CSS class to apply to the progress bar's wrapper element (defaults to 'x-progress')
\r
11667 baseCls : 'x-progress',
\r
11670 * @cfg {Boolean} animate
\r
11671 * True to animate the progress bar during transitions (defaults to false)
\r
11676 waitTimer : null,
\r
11679 initComponent : function(){
\r
11680 Ext.ProgressBar.superclass.initComponent.call(this);
\r
11684 * Fires after each update interval
\r
11685 * @param {Ext.ProgressBar} this
\r
11686 * @param {Number} The current progress value
\r
11687 * @param {String} The current progress text
\r
11694 onRender : function(ct, position){
\r
11695 var tpl = new Ext.Template(
\r
11696 '<div class="{cls}-wrap">',
\r
11697 '<div class="{cls}-inner">',
\r
11698 '<div class="{cls}-bar">',
\r
11699 '<div class="{cls}-text">',
\r
11700 '<div> </div>',
\r
11703 '<div class="{cls}-text {cls}-text-back">',
\r
11704 '<div> </div>',
\r
11710 this.el = position ? tpl.insertBefore(position, {cls: this.baseCls}, true)
\r
11711 : tpl.append(ct, {cls: this.baseCls}, true);
\r
11714 this.el.dom.id = this.id;
\r
11716 var inner = this.el.dom.firstChild;
\r
11717 this.progressBar = Ext.get(inner.firstChild);
\r
11720 //use an external text el
\r
11721 this.textEl = Ext.get(this.textEl);
\r
11722 delete this.textTopEl;
\r
11724 //setup our internal layered text els
\r
11725 this.textTopEl = Ext.get(this.progressBar.dom.firstChild);
\r
11726 var textBackEl = Ext.get(inner.childNodes[1]);
\r
11727 this.textTopEl.setStyle("z-index", 99).addClass('x-hidden');
\r
11728 this.textEl = new Ext.CompositeElement([this.textTopEl.dom.firstChild, textBackEl.dom.firstChild]);
\r
11729 this.textEl.setWidth(inner.offsetWidth);
\r
11731 this.progressBar.setHeight(inner.offsetHeight);
\r
11735 afterRender : function(){
\r
11736 Ext.ProgressBar.superclass.afterRender.call(this);
\r
11738 this.updateProgress(this.value, this.text);
\r
11740 this.updateText(this.text);
\r
11745 * Updates the progress bar value, and optionally its text. If the text argument is not specified,
\r
11746 * any existing text value will be unchanged. To blank out existing text, pass ''. Note that even
\r
11747 * if the progress bar value exceeds 1, it will never automatically reset -- you are responsible for
\r
11748 * determining when the progress is complete and calling {@link #reset} to clear and/or hide the control.
\r
11749 * @param {Float} value (optional) A floating point value between 0 and 1 (e.g., .5, defaults to 0)
\r
11750 * @param {String} text (optional) The string to display in the progress text element (defaults to '')
\r
11751 * @param {Boolean} animate (optional) Whether to animate the transition of the progress bar. If this value is
\r
11752 * not specified, the default for the class is used (default to false)
\r
11753 * @return {Ext.ProgressBar} this
\r
11755 updateProgress : function(value, text, animate){
\r
11756 this.value = value || 0;
\r
11758 this.updateText(text);
\r
11760 if(this.rendered){
\r
11761 var w = Math.floor(value*this.el.dom.firstChild.offsetWidth);
\r
11762 this.progressBar.setWidth(w, animate === true || (animate !== false && this.animate));
\r
11763 if(this.textTopEl){
\r
11764 //textTopEl should be the same width as the bar so overflow will clip as the bar moves
\r
11765 this.textTopEl.removeClass('x-hidden').setWidth(w);
\r
11768 this.fireEvent('update', this, value, text);
\r
11773 * Initiates an auto-updating progress bar. A duration can be specified, in which case the progress
\r
11774 * bar will automatically reset after a fixed amount of time and optionally call a callback function
\r
11775 * if specified. If no duration is passed in, then the progress bar will run indefinitely and must
\r
11776 * be manually cleared by calling {@link #reset}. The wait method accepts a config object with
\r
11777 * the following properties:
\r
11779 Property Type Description
\r
11780 ---------- ------------ ----------------------------------------------------------------------
\r
11781 duration Number The length of time in milliseconds that the progress bar should
\r
11782 run before resetting itself (defaults to undefined, in which case it
\r
11783 will run indefinitely until reset is called)
\r
11784 interval Number The length of time in milliseconds between each progress update
\r
11785 (defaults to 1000 ms)
\r
11786 animate Boolean Whether to animate the transition of the progress bar. If this value is
\r
11787 not specified, the default for the class is used.
\r
11788 increment Number The number of progress update segments to display within the progress
\r
11789 bar (defaults to 10). If the bar reaches the end and is still
\r
11790 updating, it will automatically wrap back to the beginning.
\r
11791 text String Optional text to display in the progress bar element (defaults to '').
\r
11792 fn Function A callback function to execute after the progress bar finishes auto-
\r
11793 updating. The function will be called with no arguments. This function
\r
11794 will be ignored if duration is not specified since in that case the
\r
11795 progress bar can only be stopped programmatically, so any required function
\r
11796 should be called by the same code after it resets the progress bar.
\r
11797 scope Object The scope that is passed to the callback function (only applies when
\r
11798 duration and fn are both passed).
\r
11803 var p = new Ext.ProgressBar({
\r
11804 renderTo: 'my-el'
\r
11807 //Wait for 5 seconds, then update the status el (progress bar will auto-reset)
\r
11809 interval: 100, //bar will move fast!
\r
11812 text: 'Updating...',
\r
11815 Ext.fly('status').update('Done!');
\r
11819 //Or update indefinitely until some async action completes, then reset manually
\r
11821 myAction.on('complete', function(){
\r
11823 Ext.fly('status').update('Done!');
\r
11826 * @param {Object} config (optional) Configuration options
\r
11827 * @return {Ext.ProgressBar} this
\r
11829 wait : function(o){
\r
11830 if(!this.waitTimer){
\r
11831 var scope = this;
\r
11833 this.updateText(o.text);
\r
11834 this.waitTimer = Ext.TaskMgr.start({
\r
11835 run: function(i){
\r
11836 var inc = o.increment || 10;
\r
11838 this.updateProgress(((((i+inc)%inc)+1)*(100/inc))*0.01, null, o.animate);
\r
11840 interval: o.interval || 1000,
\r
11841 duration: o.duration,
\r
11842 onStop: function(){
\r
11844 o.fn.apply(o.scope || this);
\r
11855 * Returns true if the progress bar is currently in a {@link #wait} operation
\r
11856 * @return {Boolean} True if waiting, else false
\r
11858 isWaiting : function(){
\r
11859 return this.waitTimer !== null;
\r
11863 * Updates the progress bar text. If specified, textEl will be updated, otherwise the progress
\r
11864 * bar itself will display the updated text.
\r
11865 * @param {String} text (optional) The string to display in the progress text element (defaults to '')
\r
11866 * @return {Ext.ProgressBar} this
\r
11868 updateText : function(text){
\r
11869 this.text = text || ' ';
\r
11870 if(this.rendered){
\r
11871 this.textEl.update(this.text);
\r
11877 * Synchronizes the inner bar width to the proper proportion of the total componet width based
\r
11878 * on the current progress {@link #value}. This will be called automatically when the ProgressBar
\r
11879 * is resized by a layout, but if it is rendered auto width, this method can be called from
\r
11880 * another resize handler to sync the ProgressBar if necessary.
\r
11882 syncProgressBar : function(){
\r
11884 this.updateProgress(this.value, this.text);
\r
11890 * Sets the size of the progress bar.
\r
11891 * @param {Number} width The new width in pixels
\r
11892 * @param {Number} height The new height in pixels
\r
11893 * @return {Ext.ProgressBar} this
\r
11895 setSize : function(w, h){
\r
11896 Ext.ProgressBar.superclass.setSize.call(this, w, h);
\r
11897 if(this.textTopEl){
\r
11898 var inner = this.el.dom.firstChild;
\r
11899 this.textEl.setSize(inner.offsetWidth, inner.offsetHeight);
\r
11901 this.syncProgressBar();
\r
11906 * Resets the progress bar value to 0 and text to empty string. If hide = true, the progress
\r
11907 * bar will also be hidden (using the {@link #hideMode} property internally).
\r
11908 * @param {Boolean} hide (optional) True to hide the progress bar (defaults to false)
\r
11909 * @return {Ext.ProgressBar} this
\r
11911 reset : function(hide){
\r
11912 this.updateProgress(0);
\r
11913 if(this.textTopEl){
\r
11914 this.textTopEl.addClass('x-hidden');
\r
11916 if(this.waitTimer){
\r
11917 this.waitTimer.onStop = null; //prevent recursion
\r
11918 Ext.TaskMgr.stop(this.waitTimer);
\r
11919 this.waitTimer = null;
\r
11921 if(hide === true){
\r
11927 onDestroy: function(){
\r
11928 if(this.rendered){
\r
11929 if(this.textEl.isComposite){
\r
11930 this.textEl.clear();
\r
11932 Ext.destroyMembers(this, 'textEl', 'progressBar', 'textTopEl');
\r
11934 Ext.ProgressBar.superclass.onDestroy.call(this);
\r
11937 Ext.reg('progress', Ext.ProgressBar);