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 specified component is added to ComponentMgr
57 * @param {String} id The component {@link Ext.Component#id id}
58 * @param {Function} fn The callback function
59 * @param {Object} scope The scope of the callback
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 return new ptypes[config.ptype || defaultType](config);
142 * Shorthand for {@link Ext.ComponentMgr#registerType}
143 * @param {String} xtype The {@link Ext.component#xtype mnemonic string} by which the Component class
145 * @param {Constructor} cls The new Component class.
149 Ext.reg = Ext.ComponentMgr.registerType; // this will be called a lot internally, shorthand to keep the bytes down
151 * Shorthand for {@link Ext.ComponentMgr#registerPlugin}
152 * @param {String} ptype The {@link Ext.component#ptype mnemonic string} by which the Plugin class
154 * @param {Constructor} cls The new Plugin class.
158 Ext.preg = Ext.ComponentMgr.registerPlugin;
160 * Shorthand for {@link Ext.ComponentMgr#create}
161 * Creates a new Component from the specified config object using the
162 * config object's {@link Ext.component#xtype xtype} to determine the class to instantiate.
163 * @param {Object} config A configuration object for the Component you wish to create.
164 * @param {Constructor} defaultType The constructor to provide the default Component type if
165 * the config object does not contain a <code>xtype</code>. (Optional if the config contains a <code>xtype</code>).
166 * @return {Ext.Component} The newly instantiated Component.
170 Ext.create = Ext.ComponentMgr.create;/**
171 * @class Ext.Component
172 * @extends Ext.util.Observable
173 * <p>Base class for all Ext components. All subclasses of Component may participate in the automated
174 * Ext component lifecycle of creation, rendering and destruction which is provided by the {@link Ext.Container Container} class.
175 * Components may be added to a Container through the {@link Ext.Container#items items} config option at the time the Container is created,
176 * or they may be added dynamically via the {@link Ext.Container#add add} method.</p>
177 * <p>The Component base class has built-in support for basic hide/show and enable/disable behavior.</p>
178 * <p>All Components are registered with the {@link Ext.ComponentMgr} on construction so that they can be referenced at any time via
179 * {@link Ext#getCmp}, passing the {@link #id}.</p>
180 * <p>All user-developed visual widgets that are required to participate in automated lifecycle and size management should subclass Component (or
181 * {@link Ext.BoxComponent} if managed box model handling is required, ie height and width management).</p>
182 * <p>See the <a href="http://extjs.com/learn/Tutorial:Creating_new_UI_controls">Creating new UI controls</a> tutorial for details on how
183 * and to either extend or augment ExtJs base classes to create custom Components.</p>
184 * <p>Every component has a specific xtype, which is its Ext-specific type name, along with methods for checking the
185 * xtype like {@link #getXType} and {@link #isXType}. This is the list of all valid xtypes:</p>
188 ------------- ------------------
189 box {@link Ext.BoxComponent}
190 button {@link Ext.Button}
191 buttongroup {@link Ext.ButtonGroup}
192 colorpalette {@link Ext.ColorPalette}
193 component {@link Ext.Component}
194 container {@link Ext.Container}
195 cycle {@link Ext.CycleButton}
196 dataview {@link Ext.DataView}
197 datepicker {@link Ext.DatePicker}
198 editor {@link Ext.Editor}
199 editorgrid {@link Ext.grid.EditorGridPanel}
200 flash {@link Ext.FlashComponent}
201 grid {@link Ext.grid.GridPanel}
202 listview {@link Ext.ListView}
203 panel {@link Ext.Panel}
204 progress {@link Ext.ProgressBar}
205 propertygrid {@link Ext.grid.PropertyGrid}
206 slider {@link Ext.Slider}
207 spacer {@link Ext.Spacer}
208 splitbutton {@link Ext.SplitButton}
209 tabpanel {@link Ext.TabPanel}
210 treepanel {@link Ext.tree.TreePanel}
211 viewport {@link Ext.ViewPort}
212 window {@link Ext.Window}
215 ---------------------------------------
216 paging {@link Ext.PagingToolbar}
217 toolbar {@link Ext.Toolbar}
218 tbbutton {@link Ext.Toolbar.Button} (deprecated; use button)
219 tbfill {@link Ext.Toolbar.Fill}
220 tbitem {@link Ext.Toolbar.Item}
221 tbseparator {@link Ext.Toolbar.Separator}
222 tbspacer {@link Ext.Toolbar.Spacer}
223 tbsplit {@link Ext.Toolbar.SplitButton} (deprecated; use splitbutton)
224 tbtext {@link Ext.Toolbar.TextItem}
227 ---------------------------------------
228 menu {@link Ext.menu.Menu}
229 colormenu {@link Ext.menu.ColorMenu}
230 datemenu {@link Ext.menu.DateMenu}
231 menubaseitem {@link Ext.menu.BaseItem}
232 menucheckitem {@link Ext.menu.CheckItem}
233 menuitem {@link Ext.menu.Item}
234 menuseparator {@link Ext.menu.Separator}
235 menutextitem {@link Ext.menu.TextItem}
238 ---------------------------------------
239 form {@link Ext.FormPanel}
240 checkbox {@link Ext.form.Checkbox}
241 checkboxgroup {@link Ext.form.CheckboxGroup}
242 combo {@link Ext.form.ComboBox}
243 datefield {@link Ext.form.DateField}
244 displayfield {@link Ext.form.DisplayField}
245 field {@link Ext.form.Field}
246 fieldset {@link Ext.form.FieldSet}
247 hidden {@link Ext.form.Hidden}
248 htmleditor {@link Ext.form.HtmlEditor}
249 label {@link Ext.form.Label}
250 numberfield {@link Ext.form.NumberField}
251 radio {@link Ext.form.Radio}
252 radiogroup {@link Ext.form.RadioGroup}
253 textarea {@link Ext.form.TextArea}
254 textfield {@link Ext.form.TextField}
255 timefield {@link Ext.form.TimeField}
256 trigger {@link Ext.form.TriggerField}
259 ---------------------------------------
260 chart {@link Ext.chart.Chart}
261 barchart {@link Ext.chart.BarChart}
262 cartesianchart {@link Ext.chart.CartesianChart}
263 columnchart {@link Ext.chart.ColumnChart}
264 linechart {@link Ext.chart.LineChart}
265 piechart {@link Ext.chart.PieChart}
268 ---------------------------------------
269 arraystore {@link Ext.data.ArrayStore}
270 directstore {@link Ext.data.DirectStore}
271 groupingstore {@link Ext.data.GroupingStore}
272 jsonstore {@link Ext.data.JsonStore}
273 simplestore {@link Ext.data.SimpleStore} (deprecated; use arraystore)
274 store {@link Ext.data.Store}
275 xmlstore {@link Ext.data.XmlStore}
278 * @param {Ext.Element/String/Object} config The configuration options may be specified as either:
279 * <div class="mdetail-params"><ul>
280 * <li><b>an element</b> :
281 * <p class="sub-desc">it is set as the internal element and its id used as the component id</p></li>
282 * <li><b>a string</b> :
283 * <p class="sub-desc">it is assumed to be the id of an existing element and is used as the component id</p></li>
284 * <li><b>anything else</b> :
285 * <p class="sub-desc">it is assumed to be a standard config object and is applied to the component</p></li>
288 Ext.Component = function(config){
289 config = config || {};
290 if(config.initialConfig){
291 if(config.isAction){ // actions
292 this.baseAction = config;
294 config = config.initialConfig; // component cloning / action set up
295 }else if(config.tagName || config.dom || Ext.isString(config)){ // element object
296 config = {applyTo: config, id: config.id || config};
300 * This Component's initial configuration specification. Read-only.
302 * @property initialConfig
304 this.initialConfig = config;
306 Ext.apply(this, config);
310 * Fires after the component is disabled.
311 * @param {Ext.Component} this
316 * Fires after the component is enabled.
317 * @param {Ext.Component} this
322 * Fires before the component is shown by calling the {@link #show} method.
323 * Return false from an event handler to stop the show.
324 * @param {Ext.Component} this
329 * Fires after the component is shown when calling the {@link #show} method.
330 * @param {Ext.Component} this
335 * Fires before the component is hidden by calling the {@link #hide} method.
336 * Return false from an event handler to stop the hide.
337 * @param {Ext.Component} this
342 * Fires after the component is hidden.
343 * Fires after the component is hidden when calling the {@link #hide} method.
344 * @param {Ext.Component} this
348 * @event beforerender
349 * Fires before the component is {@link #rendered}. Return false from an
350 * event handler to stop the {@link #render}.
351 * @param {Ext.Component} this
356 * Fires after the component markup is {@link #rendered}.
357 * @param {Ext.Component} this
362 * <p>Fires after the component rendering is finished.</p>
363 * <p>The afterrender event is fired after this Component has been {@link #rendered}, been postprocesed
364 * by any afterRender method defined for the Component, and, if {@link #stateful}, after state
365 * has been restored.</p>
366 * @param {Ext.Component} this
370 * @event beforedestroy
371 * Fires before the component is {@link #destroy}ed. Return false from an event handler to stop the {@link #destroy}.
372 * @param {Ext.Component} this
377 * Fires after the component is {@link #destroy}ed.
378 * @param {Ext.Component} this
382 * @event beforestaterestore
383 * Fires before the state of the component is restored. Return false from an event handler to stop the restore.
384 * @param {Ext.Component} this
385 * @param {Object} state The hash of state values returned from the StateProvider. If this
386 * event is not vetoed, then the state object is passed to <b><tt>applyState</tt></b>. By default,
387 * that simply copies property values into this Component. The method maybe overriden to
388 * provide custom state restoration.
390 'beforestaterestore',
392 * @event staterestore
393 * Fires after the state of the component is restored.
394 * @param {Ext.Component} this
395 * @param {Object} state The hash of state values returned from the StateProvider. This is passed
396 * to <b><tt>applyState</tt></b>. By default, that simply copies property values into this
397 * Component. The method maybe overriden to provide custom state restoration.
401 * @event beforestatesave
402 * Fires before the state of the component is saved to the configured state provider. Return false to stop the save.
403 * @param {Ext.Component} this
404 * @param {Object} state The hash of state values. This is determined by calling
405 * <b><tt>getState()</tt></b> on the Component. This method must be provided by the
406 * developer to return whetever representation of state is required, by default, Ext.Component
407 * has a null implementation.
412 * Fires after the state of the component is saved to the configured state provider.
413 * @param {Ext.Component} this
414 * @param {Object} state The hash of state values. This is determined by calling
415 * <b><tt>getState()</tt></b> on the Component. This method must be provided by the
416 * developer to return whetever representation of state is required, by default, Ext.Component
417 * has a null implementation.
422 Ext.ComponentMgr.register(this);
423 Ext.Component.superclass.constructor.call(this);
426 this.baseAction.addComponent(this);
429 this.initComponent();
432 if(Ext.isArray(this.plugins)){
433 for(var i = 0, len = this.plugins.length; i < len; i++){
434 this.plugins[i] = this.initPlugin(this.plugins[i]);
437 this.plugins = this.initPlugin(this.plugins);
441 if(this.stateful !== false){
442 this.initState(config);
446 this.applyToMarkup(this.applyTo);
448 }else if(this.renderTo){
449 this.render(this.renderTo);
450 delete this.renderTo;
455 Ext.Component.AUTO_ID = 1000;
457 Ext.extend(Ext.Component, Ext.util.Observable, {
458 // Configs below are used for all Components when rendered by FormLayout.
460 * @cfg {String} fieldLabel <p>The label text to display next to this Component (defaults to '').</p>
461 * <br><p><b>Note</b>: this config is only used when this Component is rendered by a Container which
462 * has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout manager (e.g.
463 * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>).</p><br>
464 * <p>Also see <tt>{@link #hideLabel}</tt> and
465 * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</p>
466 * Example use:<pre><code>
469 renderTo: Ext.getBody(),
478 * @cfg {String} labelStyle <p>A CSS style specification string to apply directly to this field's
479 * label. Defaults to the container's labelStyle value if set (e.g.,
480 * <tt>{@link Ext.layout.FormLayout#labelStyle}</tt> , or '').</p>
481 * <br><p><b>Note</b>: see the note for <code>{@link #clearCls}</code>.</p><br>
482 * <p>Also see <code>{@link #hideLabel}</code> and
483 * <code>{@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</code></p>
484 * Example use:<pre><code>
487 renderTo: Ext.getBody(),
491 labelStyle: 'font-weight:bold;'
497 * @cfg {String} labelSeparator <p>The separator to display after the text of each
498 * <tt>{@link #fieldLabel}</tt>. This property may be configured at various levels.
499 * The order of precedence is:
500 * <div class="mdetail-params"><ul>
501 * <li>field / component level</li>
502 * <li>container level</li>
503 * <li>{@link Ext.layout.FormLayout#labelSeparator layout level} (defaults to colon <tt>':'</tt>)</li>
505 * To display no separator for this field's label specify empty string ''.</p>
506 * <br><p><b>Note</b>: see the note for <tt>{@link #clearCls}</tt>.</p><br>
507 * <p>Also see <tt>{@link #hideLabel}</tt> and
508 * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</p>
509 * Example use:<pre><code>
512 renderTo: Ext.getBody(),
514 labelSeparator: '~' // layout config has lowest priority (defaults to ':')
516 {@link Ext.layout.FormLayout#labelSeparator labelSeparator}: '>>', // config at container level
519 fieldLabel: 'Field 1',
520 labelSeparator: '...' // field/component level config supersedes others
523 fieldLabel: 'Field 2' // labelSeparator will be '='
529 * @cfg {Boolean} hideLabel <p><tt>true</tt> to completely hide the label element
530 * ({@link #fieldLabel label} and {@link #labelSeparator separator}). Defaults to <tt>false</tt>.
531 * By default, even if you do not specify a <tt>{@link #fieldLabel}</tt> the space will still be
532 * reserved so that the field will line up with other fields that do have labels.
533 * Setting this to <tt>true</tt> will cause the field to not reserve that space.</p>
534 * <br><p><b>Note</b>: see the note for <tt>{@link #clearCls}</tt>.</p><br>
535 * Example use:<pre><code>
538 renderTo: Ext.getBody(),
547 * @cfg {String} clearCls <p>The CSS class used to to apply to the special clearing div rendered
548 * directly after each form field wrapper to provide field clearing (defaults to
549 * <tt>'x-form-clear-left'</tt>).</p>
550 * <br><p><b>Note</b>: this config is only used when this Component is rendered by a Container
551 * which has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout
552 * manager (e.g. {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>) and either a
553 * <tt>{@link #fieldLabel}</tt> is specified or <tt>isFormField=true</tt> is specified.</p><br>
554 * <p>See {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl} also.</p>
557 * @cfg {String} itemCls
558 * <p><b>Note</b>: this config is only used when this Component is rendered by a Container which
559 * has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout manager (e.g.
560 * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>).</p><br>
561 * <p>An additional CSS class to apply to the div wrapping the form item
562 * element of this field. If supplied, <tt>itemCls</tt> at the <b>field</b> level will override
563 * the default <tt>itemCls</tt> supplied at the <b>container</b> level. The value specified for
564 * <tt>itemCls</tt> will be added to the default class (<tt>'x-form-item'</tt>).</p>
565 * <p>Since it is applied to the item wrapper (see
566 * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}), it allows
567 * you to write standard CSS rules that can apply to the field, the label (if specified), or
568 * any other element within the markup for the field.</p>
569 * <br><p><b>Note</b>: see the note for <tt>{@link #fieldLabel}</tt>.</p><br>
570 * Example use:<pre><code>
571 // Apply a style to the field's label:
573 .required .x-form-item-label {font-weight:bold;color:red;}
578 renderTo: Ext.getBody(),
582 itemCls: 'required' //this label will be styled
585 fieldLabel: 'Favorite Color'
591 // Configs below are used for all Components when rendered by AnchorLayout.
593 * @cfg {String} anchor <p><b>Note</b>: this config is only used when this Component is rendered
594 * by a Container which has been configured to use an <b>{@link Ext.layout.AnchorLayout AnchorLayout}</b>
595 * based layout manager, for example:<div class="mdetail-params"><ul>
596 * <li>{@link Ext.form.FormPanel}</li>
597 * <li>specifying <code>layout: 'anchor' // or 'form', or 'absolute'</code></li>
599 * <p>See {@link Ext.layout.AnchorLayout}.{@link Ext.layout.AnchorLayout#anchor anchor} also.</p>
604 * <p>The <b>unique</b> id of this component (defaults to an {@link #getId auto-assigned id}).
605 * You should assign an id if you need to be able to access the component later and you do
606 * not have an object reference available (e.g., using {@link Ext}.{@link Ext#getCmp getCmp}).</p>
607 * <p>Note that this id will also be used as the element id for the containing HTML element
608 * that is rendered to the page for this component. This allows you to write id-based CSS
609 * rules to style the specific instance of this component uniquely, and also to select
610 * sub-elements using this component's id as the parent.</p>
611 * <p><b>Note</b>: to avoid complications imposed by a unique <tt>id</tt> also see
612 * <code>{@link #itemId}</code> and <code>{@link #ref}</code>.</p>
613 * <p><b>Note</b>: to access the container of an item see <code>{@link #ownerCt}</code>.</p>
616 * @cfg {String} itemId
617 * <p>An <tt>itemId</tt> can be used as an alternative way to get a reference to a component
618 * when no object reference is available. Instead of using an <code>{@link #id}</code> with
619 * {@link Ext}.{@link Ext#getCmp getCmp}, use <code>itemId</code> with
620 * {@link Ext.Container}.{@link Ext.Container#getComponent getComponent} which will retrieve
621 * <code>itemId</code>'s or <tt>{@link #id}</tt>'s. Since <code>itemId</code>'s are an index to the
622 * container's internal MixedCollection, the <code>itemId</code> is scoped locally to the container --
623 * avoiding potential conflicts with {@link Ext.ComponentMgr} which requires a <b>unique</b>
624 * <code>{@link #id}</code>.</p>
626 var c = new Ext.Panel({ //
627 {@link Ext.BoxComponent#height height}: 300,
628 {@link #renderTo}: document.body,
629 {@link Ext.Container#layout layout}: 'auto',
630 {@link Ext.Container#items items}: [
633 {@link Ext.Panel#title title}: 'Panel 1',
634 {@link Ext.BoxComponent#height height}: 150
638 {@link Ext.Panel#title title}: 'Panel 2',
639 {@link Ext.BoxComponent#height height}: 150
643 p1 = c.{@link Ext.Container#getComponent getComponent}('p1'); // not the same as {@link Ext#getCmp Ext.getCmp()}
644 p2 = p1.{@link #ownerCt}.{@link Ext.Container#getComponent getComponent}('p2'); // reference via a sibling
646 * <p>Also see <tt>{@link #id}</tt> and <code>{@link #ref}</code>.</p>
647 * <p><b>Note</b>: to access the container of an item see <tt>{@link #ownerCt}</tt>.</p>
650 * @cfg {String} xtype
651 * The registered <tt>xtype</tt> to create. This config option is not used when passing
652 * a config object into a constructor. This config option is used only when
653 * lazy instantiation is being used, and a child item of a Container is being
654 * specified not as a fully instantiated Component, but as a <i>Component config
655 * object</i>. The <tt>xtype</tt> will be looked up at render time up to determine what
656 * type of child Component to create.<br><br>
657 * The predefined xtypes are listed {@link Ext.Component here}.
659 * If you subclass Components to create your own Components, you may register
660 * them using {@link Ext.ComponentMgr#registerType} in order to be able to
661 * take advantage of lazy instantiation and rendering.
664 * @cfg {String} ptype
665 * The registered <tt>ptype</tt> to create. This config option is not used when passing
666 * a config object into a constructor. This config option is used only when
667 * lazy instantiation is being used, and a Plugin is being
668 * specified not as a fully instantiated Component, but as a <i>Component config
669 * object</i>. The <tt>ptype</tt> will be looked up at render time up to determine what
670 * type of Plugin to create.<br><br>
671 * If you create your own Plugins, you may register them using
672 * {@link Ext.ComponentMgr#registerPlugin} in order to be able to
673 * take advantage of lazy instantiation and rendering.
677 * An optional extra CSS class that will be added to this component's Element (defaults to ''). This can be
678 * useful for adding customized styles to the component or any of its children using standard CSS rules.
681 * @cfg {String} overCls
682 * An optional extra CSS class that will be added to this component's Element when the mouse moves
683 * over the Element, and removed when the mouse moves out. (defaults to ''). This can be
684 * useful for adding customized 'active' or 'hover' styles to the component or any of its children using standard CSS rules.
687 * @cfg {String} style
688 * A custom style specification to be applied to this component's Element. Should be a valid argument to
689 * {@link Ext.Element#applyStyles}.
693 renderTo: Ext.getBody(),
694 width: 400, height: 300,
715 * @cfg {String} ctCls
716 * <p>An optional extra CSS class that will be added to this component's container. This can be useful for
717 * adding customized styles to the container or any of its children using standard CSS rules. See
718 * {@link Ext.layout.ContainerLayout}.{@link Ext.layout.ContainerLayout#extraCls extraCls} also.</p>
719 * <p><b>Note</b>: <tt>ctCls</tt> defaults to <tt>''</tt> except for the following class
720 * which assigns a value by default:
721 * <div class="mdetail-params"><ul>
722 * <li>{@link Ext.layout.Box Box Layout} : <tt>'x-box-layout-ct'</tt></li>
724 * To configure the above Class with an extra CSS class append to the default. For example,
725 * for BoxLayout (Hbox and Vbox):<pre><code>
726 * ctCls: 'x-box-layout-ct custom-class'
731 * @cfg {Boolean} disabled
732 * Render this component disabled (default is false).
736 * @cfg {Boolean} hidden
737 * Render this component hidden (default is false). If <tt>true</tt>, the
738 * {@link #hide} method will be called internally.
742 * @cfg {Object/Array} plugins
743 * An object or array of objects that will provide custom functionality for this component. The only
744 * requirement for a valid plugin is that it contain an init method that accepts a reference of type Ext.Component.
745 * When a component is created, if any plugins are available, the component will call the init method on each
746 * plugin, passing a reference to itself. Each plugin can then call methods or respond to events on the
747 * component as needed to provide its functionality.
750 * @cfg {Mixed} applyTo
751 * <p>Specify the id of the element, a DOM element or an existing Element corresponding to a DIV
752 * that is already present in the document that specifies some structural markup for this
753 * component.</p><div><ul>
754 * <li><b>Description</b> : <ul>
755 * <div class="sub-desc">When <tt>applyTo</tt> is used, constituent parts of the component can also be specified
756 * by id or CSS class name within the main element, and the component being created may attempt
757 * to create its subcomponents from that markup if applicable.</div>
759 * <li><b>Notes</b> : <ul>
760 * <div class="sub-desc">When using this config, a call to render() is not required.</div>
761 * <div class="sub-desc">If applyTo is specified, any value passed for {@link #renderTo} will be ignored and the target
762 * element's parent node will automatically be used as the component's container.</div>
767 * @cfg {Mixed} renderTo
768 * <p>Specify the id of the element, a DOM element or an existing Element that this component
769 * will be rendered into.</p><div><ul>
770 * <li><b>Notes</b> : <ul>
771 * <div class="sub-desc">Do <u>not</u> use this option if the Component is to be a child item of
772 * a {@link Ext.Container Container}. It is the responsibility of the
773 * {@link Ext.Container Container}'s {@link Ext.Container#layout layout manager}
774 * to render and manage its child items.</div>
775 * <div class="sub-desc">When using this config, a call to render() is not required.</div>
778 * <p>See <tt>{@link #render}</tt> also.</p>
781 * @cfg {Boolean} stateful
782 * <p>A flag which causes the Component to attempt to restore the state of
783 * internal properties from a saved state on startup. The component must have
784 * either a <code>{@link #stateId}</code> or <code>{@link #id}</code> assigned
785 * for state to be managed. Auto-generated ids are not guaranteed to be stable
786 * across page loads and cannot be relied upon to save and restore the same
787 * state for a component.<p>
788 * <p>For state saving to work, the state manager's provider must have been
789 * set to an implementation of {@link Ext.state.Provider} which overrides the
790 * {@link Ext.state.Provider#set set} and {@link Ext.state.Provider#get get}
791 * methods to save and recall name/value pairs. A built-in implementation,
792 * {@link Ext.state.CookieProvider} is available.</p>
793 * <p>To set the state provider for the current page:</p>
795 Ext.state.Manager.setProvider(new Ext.state.CookieProvider({
796 expires: new Date(new Date().getTime()+(1000*60*60*24*7)), //7 days from now
799 * <p>A stateful Component attempts to save state when one of the events
800 * listed in the <code>{@link #stateEvents}</code> configuration fires.</p>
801 * <p>To save state, a stateful Component first serializes its state by
802 * calling <b><code>getState</code></b>. By default, this function does
803 * nothing. The developer must provide an implementation which returns an
804 * object hash which represents the Component's restorable state.</p>
805 * <p>The value yielded by getState is passed to {@link Ext.state.Manager#set}
806 * which uses the configured {@link Ext.state.Provider} to save the object
807 * keyed by the Component's <code>{@link stateId}</code>, or, if that is not
808 * specified, its <code>{@link #id}</code>.</p>
809 * <p>During construction, a stateful Component attempts to <i>restore</i>
810 * its state by calling {@link Ext.state.Manager#get} passing the
811 * <code>{@link #stateId}</code>, or, if that is not specified, the
812 * <code>{@link #id}</code>.</p>
813 * <p>The resulting object is passed to <b><code>applyState</code></b>.
814 * The default implementation of <code>applyState</code> simply copies
815 * properties into the object, but a developer may override this to support
816 * more behaviour.</p>
817 * <p>You can perform extra processing on state save and restore by attaching
818 * handlers to the {@link #beforestaterestore}, {@link #staterestore},
819 * {@link #beforestatesave} and {@link #statesave} events.</p>
822 * @cfg {String} stateId
823 * The unique id for this component to use for state management purposes
824 * (defaults to the component id if one was set, otherwise null if the
825 * component is using a generated id).
826 * <p>See <code>{@link #stateful}</code> for an explanation of saving and
827 * restoring Component state.</p>
830 * @cfg {Array} stateEvents
831 * <p>An array of events that, when fired, should trigger this component to
832 * save its state (defaults to none). <code>stateEvents</code> may be any type
833 * of event supported by this component, including browser or custom events
834 * (e.g., <tt>['click', 'customerchange']</tt>).</p>
835 * <p>See <code>{@link #stateful}</code> for an explanation of saving and
836 * restoring Component state.</p>
839 * @cfg {Mixed} autoEl
840 * <p>A tag name or {@link Ext.DomHelper DomHelper} spec used to create the {@link #getEl Element} which will
841 * encapsulate this Component.</p>
842 * <p>You do not normally need to specify this. For the base classes {@link Ext.Component}, {@link Ext.BoxComponent},
843 * and {@link Ext.Container}, this defaults to <b><tt>'div'</tt></b>. The more complex Ext classes use a more complex
844 * DOM structure created by their own onRender methods.</p>
845 * <p>This is intended to allow the developer to create application-specific utility Components encapsulated by
846 * different DOM elements. Example usage:</p><pre><code>
851 src: 'http://www.example.com/example.jpg'
857 html: 'autoEl is cool!'
862 cls: 'ux-unordered-list',
866 html: 'First list item'
874 * @cfg {String} disabledClass
875 * CSS class added to the component when it is disabled (defaults to 'x-item-disabled').
877 disabledClass : 'x-item-disabled',
879 * @cfg {Boolean} allowDomMove
880 * Whether the component can move the Dom node when rendering (defaults to true).
884 * @cfg {Boolean} autoShow
885 * True if the component should check for hidden classes (e.g. 'x-hidden' or 'x-hide-display') and remove
886 * them on render (defaults to false).
890 * @cfg {String} hideMode
891 * <p>How this component should be hidden. Supported values are <tt>'visibility'</tt>
892 * (css visibility), <tt>'offsets'</tt> (negative offset position) and <tt>'display'</tt>
894 * <br><p><b>Note</b>: the default of <tt>'display'</tt> is generally preferred
895 * since items are automatically laid out when they are first shown (no sizing
896 * is done while hidden).</p>
898 hideMode : 'display',
900 * @cfg {Boolean} hideParent
901 * True to hide and show the component's container when hide/show is called on the component, false to hide
902 * and show the component itself (defaults to false). For example, this can be used as a shortcut for a hide
903 * button on a window by setting hide:true on the button when adding it to its parent container.
907 * <p>The {@link Ext.Element} which encapsulates this Component. Read-only.</p>
908 * <p>This will <i>usually</i> be a <DIV> element created by the class's onRender method, but
909 * that may be overridden using the <code>{@link #autoEl}</code> config.</p>
910 * <br><p><b>Note</b>: this element will not be available until this Component has been rendered.</p><br>
911 * <p>To add listeners for <b>DOM events</b> to this Component (as opposed to listeners
912 * for this Component's own Observable events), see the {@link Ext.util.Observable#listeners listeners}
913 * config for a suggestion, or use a render listener directly:</p><pre><code>
915 title: 'The Clickable Panel',
917 render: function(p) {
918 // Append the Panel to the click handler's argument list.
919 p.getEl().on('click', handlePanelClick.createDelegate(null, [p], true));
921 single: true // Remove the listener after first invocation
925 * <p>See also <tt>{@link #getEl getEl}</p>
930 * This Component's owner {@link Ext.Container Container} (defaults to undefined, and is set automatically when
931 * this Component is added to a Container). Read-only.
932 * <p><b>Note</b>: to access items within the Container see <tt>{@link #itemId}</tt>.</p>
933 * @type Ext.Container
937 * True if this component is hidden. Read-only.
942 * True if this component is disabled. Read-only.
947 * True if this component has been rendered. Read-only.
954 ctype : 'Ext.Component',
960 getActionEl : function(){
961 return this[this.actionMode];
964 initPlugin : function(p){
965 if(p.ptype && !Ext.isFunction(p.init)){
966 p = Ext.ComponentMgr.createPlugin(p);
967 }else if(Ext.isString(p)){
968 p = Ext.ComponentMgr.createPlugin({
977 * Function to be implemented by Component subclasses to be part of standard component initialization flow (it is empty by default).
979 // Traditional constructor:
980 Ext.Foo = function(config){
981 // call superclass constructor:
982 Ext.Foo.superclass.constructor.call(this, config);
988 Ext.extend(Ext.Foo, Ext.Bar, {
992 // initComponent replaces the constructor:
993 Ext.Foo = Ext.extend(Ext.Bar, {
994 initComponent : function(){
995 // call superclass initComponent
996 Ext.Container.superclass.initComponent.call(this);
1005 initComponent : Ext.emptyFn,
1008 * <p>Render this Component into the passed HTML element.</p>
1009 * <p><b>If you are using a {@link Ext.Container Container} object to house this Component, then
1010 * do not use the render method.</b></p>
1011 * <p>A Container's child Components are rendered by that Container's
1012 * {@link Ext.Container#layout layout} manager when the Container is first rendered.</p>
1013 * <p>Certain layout managers allow dynamic addition of child components. Those that do
1014 * include {@link Ext.layout.CardLayout}, {@link Ext.layout.AnchorLayout},
1015 * {@link Ext.layout.FormLayout}, {@link Ext.layout.TableLayout}.</p>
1016 * <p>If the Container is already rendered when a new child Component is added, you may need to call
1017 * the Container's {@link Ext.Container#doLayout doLayout} to refresh the view which causes any
1018 * unrendered child Components to be rendered. This is required so that you can add multiple
1019 * child components if needed while only refreshing the layout once.</p>
1020 * <p>When creating complex UIs, it is important to remember that sizing and positioning
1021 * of child items is the responsibility of the Container's {@link Ext.Container#layout layout} manager.
1022 * If you expect child items to be sized in response to user interactions, you must
1023 * configure the Container with a layout manager which creates and manages the type of layout you
1025 * <p><b>Omitting the Container's {@link Ext.Container#layout layout} config means that a basic
1026 * layout manager is used which does nothing but render child components sequentially into the
1027 * Container. No sizing or positioning will be performed in this situation.</b></p>
1028 * @param {Element/HTMLElement/String} container (optional) The element this Component should be
1029 * rendered into. If it is being created from existing markup, this should be omitted.
1030 * @param {String/Number} position (optional) The element ID or DOM node index within the container <b>before</b>
1031 * which this component will be inserted (defaults to appending to the end of the container)
1033 render : function(container, position){
1034 if(!this.rendered && this.fireEvent('beforerender', this) !== false){
1035 if(!container && this.el){
1036 this.el = Ext.get(this.el);
1037 container = this.el.dom.parentNode;
1038 this.allowDomMove = false;
1040 this.container = Ext.get(container);
1042 this.container.addClass(this.ctCls);
1044 this.rendered = true;
1045 if(position !== undefined){
1046 if(Ext.isNumber(position)){
1047 position = this.container.dom.childNodes[position];
1049 position = Ext.getDom(position);
1052 this.onRender(this.container, position || null);
1054 this.el.removeClass(['x-hidden','x-hide-' + this.hideMode]);
1057 this.el.addClass(this.cls);
1061 this.el.applyStyles(this.style);
1065 this.el.addClassOnOver(this.overCls);
1067 this.fireEvent('render', this);
1068 this.afterRender(this.container);
1070 // call this so we don't fire initial hide events.
1074 // pass silent so the event doesn't fire the first time.
1078 if(this.stateful !== false){
1079 this.initStateEvents();
1082 this.fireEvent('afterrender', this);
1087 initRef : function(){
1090 * <p>A path specification, relative to the Component's {@link #ownerCt} specifying into which
1091 * ancestor Container to place a named reference to this Component.</p>
1092 * <p>The ancestor axis can be traversed by using '/' characters in the path.
1093 * For example, to put a reference to a Toolbar Button into <i>the Panel which owns the Toolbar</i>:</p><pre><code>
1094 var myGrid = new Ext.grid.EditorGridPanel({
1095 title: 'My EditorGridPanel',
1097 colModel: myColModel,
1100 handler: saveChanges,
1102 ref: '../saveButton'
1105 afteredit: function() {
1106 // The button reference is in the GridPanel
1107 myGrid.saveButton.enable();
1112 * <p>In the code above, if the ref had been <code>'saveButton'</code> the reference would
1113 * have been placed into the Toolbar. Each '/' in the ref moves up one level from the
1114 * Component's {@link #ownerCt}.</p>
1117 var levels = this.ref.split('/');
1118 var last = levels.length, i = 0;
1126 t[levels[--i]] = this;
1131 initState : function(config){
1132 if(Ext.state.Manager){
1133 var id = this.getStateId();
1135 var state = Ext.state.Manager.get(id);
1137 if(this.fireEvent('beforestaterestore', this, state) !== false){
1138 this.applyState(state);
1139 this.fireEvent('staterestore', this, state);
1147 getStateId : function(){
1148 return this.stateId || ((this.id.indexOf('ext-comp-') == 0 || this.id.indexOf('ext-gen') == 0) ? null : this.id);
1152 initStateEvents : function(){
1153 if(this.stateEvents){
1154 for(var i = 0, e; e = this.stateEvents[i]; i++){
1155 this.on(e, this.saveState, this, {delay:100});
1161 applyState : function(state){
1163 Ext.apply(this, state);
1168 getState : function(){
1173 saveState : function(){
1174 if(Ext.state.Manager && this.stateful !== false){
1175 var id = this.getStateId();
1177 var state = this.getState();
1178 if(this.fireEvent('beforestatesave', this, state) !== false){
1179 Ext.state.Manager.set(id, state);
1180 this.fireEvent('statesave', this, state);
1187 * Apply this component to existing markup that is valid. With this function, no call to render() is required.
1188 * @param {String/HTMLElement} el
1190 applyToMarkup : function(el){
1191 this.allowDomMove = false;
1192 this.el = Ext.get(el);
1193 this.render(this.el.dom.parentNode);
1197 * Adds a CSS class to the component's underlying element.
1198 * @param {string} cls The CSS class name to add
1199 * @return {Ext.Component} this
1201 addClass : function(cls){
1203 this.el.addClass(cls);
1205 this.cls = this.cls ? this.cls + ' ' + cls : cls;
1211 * Removes a CSS class from the component's underlying element.
1212 * @param {string} cls The CSS class name to remove
1213 * @return {Ext.Component} this
1215 removeClass : function(cls){
1217 this.el.removeClass(cls);
1219 this.cls = this.cls.split(' ').remove(cls).join(' ');
1225 // default function is not really useful
1226 onRender : function(ct, position){
1227 if(!this.el && this.autoEl){
1228 if(Ext.isString(this.autoEl)){
1229 this.el = document.createElement(this.autoEl);
1231 var div = document.createElement('div');
1232 Ext.DomHelper.overwrite(div, this.autoEl);
1233 this.el = div.firstChild;
1236 this.el.id = this.getId();
1240 this.el = Ext.get(this.el);
1241 if(this.allowDomMove !== false){
1242 ct.dom.insertBefore(this.el.dom, position);
1248 getAutoCreate : function(){
1249 var cfg = Ext.isObject(this.autoCreate) ?
1250 this.autoCreate : Ext.apply({}, this.defaultAutoCreate);
1251 if(this.id && !cfg.id){
1258 afterRender : Ext.emptyFn,
1261 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
1262 * removing the component from its {@link Ext.Container} (if applicable) and unregistering it from
1263 * {@link Ext.ComponentMgr}. Destruction is generally handled automatically by the framework and this method
1264 * should usually not need to be called directly.
1267 destroy : function(){
1268 if(!this.isDestroyed){
1269 if(this.fireEvent('beforedestroy', this) !== false){
1270 this.beforeDestroy();
1272 this.el.removeAllListeners();
1274 if(this.actionMode == 'container' || this.removeMode == 'container'){
1275 this.container.remove();
1279 Ext.ComponentMgr.unregister(this);
1280 this.fireEvent('destroy', this);
1281 this.purgeListeners();
1282 this.isDestroyed = true;
1288 beforeDestroy : Ext.emptyFn,
1291 onDestroy : Ext.emptyFn,
1294 * <p>Returns the {@link Ext.Element} which encapsulates this Component.</p>
1295 * <p>This will <i>usually</i> be a <DIV> element created by the class's onRender method, but
1296 * that may be overridden using the {@link #autoEl} config.</p>
1297 * <br><p><b>Note</b>: this element will not be available until this Component has been rendered.</p><br>
1298 * <p>To add listeners for <b>DOM events</b> to this Component (as opposed to listeners
1299 * for this Component's own Observable events), see the {@link #listeners} config for a suggestion,
1300 * or use a render listener directly:</p><pre><code>
1302 title: 'The Clickable Panel',
1304 render: function(p) {
1305 // Append the Panel to the click handler's argument list.
1306 p.getEl().on('click', handlePanelClick.createDelegate(null, [p], true));
1308 single: true // Remove the listener after first invocation
1312 * @return {Ext.Element} The Element which encapsulates this Component.
1319 * Returns the <code>id</code> of this component or automatically generates and
1320 * returns an <code>id</code> if an <code>id</code> is not defined yet:<pre><code>
1321 * 'ext-comp-' + (++Ext.Component.AUTO_ID)
1323 * @return {String} id
1326 return this.id || (this.id = 'ext-comp-' + (++Ext.Component.AUTO_ID));
1330 * Returns the <code>{@link #itemId}</code> of this component. If an
1331 * <code>{@link #itemId}</code> was not assigned through configuration the
1332 * <code>id</code> is returned using <code>{@link #getId}</code>.
1335 getItemId : function(){
1336 return this.itemId || this.getId();
1340 * Try to focus this component.
1341 * @param {Boolean} selectText (optional) If applicable, true to also select the text in this component
1342 * @param {Boolean/Number} delay (optional) Delay the focus this number of milliseconds (true for 10 milliseconds)
1343 * @return {Ext.Component} this
1345 focus : function(selectText, delay){
1347 this.focus.defer(Ext.isNumber(delay) ? delay : 10, this, [selectText, false]);
1352 if(selectText === true){
1353 this.el.dom.select();
1368 * Disable this component and fire the 'disable' event.
1369 * @return {Ext.Component} this
1371 disable : function(/* private */ silent){
1375 this.disabled = true;
1376 if(silent !== true){
1377 this.fireEvent('disable', this);
1383 onDisable : function(){
1384 this.getActionEl().addClass(this.disabledClass);
1385 this.el.dom.disabled = true;
1389 * Enable this component and fire the 'enable' event.
1390 * @return {Ext.Component} this
1392 enable : function(){
1396 this.disabled = false;
1397 this.fireEvent('enable', this);
1402 onEnable : function(){
1403 this.getActionEl().removeClass(this.disabledClass);
1404 this.el.dom.disabled = false;
1408 * Convenience function for setting disabled/enabled by boolean.
1409 * @param {Boolean} disabled
1410 * @return {Ext.Component} this
1412 setDisabled : function(disabled){
1413 return this[disabled ? 'disable' : 'enable']();
1417 * Show this component. Listen to the '{@link #beforeshow}' event and return
1418 * <tt>false</tt> to cancel showing the component. Fires the '{@link #show}'
1419 * event after showing the component.
1420 * @return {Ext.Component} this
1423 if(this.fireEvent('beforeshow', this) !== false){
1424 this.hidden = false;
1425 if(this.autoRender){
1426 this.render(Ext.isBoolean(this.autoRender) ? Ext.getBody() : this.autoRender);
1431 this.fireEvent('show', this);
1437 onShow : function(){
1438 this.getVisibilityEl().removeClass('x-hide-' + this.hideMode);
1442 * Hide this component. Listen to the '{@link #beforehide}' event and return
1443 * <tt>false</tt> to cancel hiding the component. Fires the '{@link #hide}'
1444 * event after hiding the component. Note this method is called internally if
1445 * the component is configured to be <code>{@link #hidden}</code>.
1446 * @return {Ext.Component} this
1449 if(this.fireEvent('beforehide', this) !== false){
1451 this.fireEvent('hide', this);
1465 onHide : function(){
1466 this.getVisibilityEl().addClass('x-hide-' + this.hideMode);
1470 getVisibilityEl : function(){
1471 return this.hideParent ? this.container : this.getActionEl();
1475 * Convenience function to hide or show this component by boolean.
1476 * @param {Boolean} visible True to show, false to hide
1477 * @return {Ext.Component} this
1479 setVisible : function(visible){
1480 return this[visible ? 'show' : 'hide']();
1484 * Returns true if this component is visible.
1485 * @return {Boolean} True if this component is visible, false otherwise.
1487 isVisible : function(){
1488 return this.rendered && this.getVisibilityEl().isVisible();
1492 * Clone the current component using the original config values passed into this instance by default.
1493 * @param {Object} overrides A new config containing any properties to override in the cloned version.
1494 * An id property can be passed on this object, otherwise one will be generated to avoid duplicates.
1495 * @return {Ext.Component} clone The cloned copy of this component
1497 cloneConfig : function(overrides){
1498 overrides = overrides || {};
1499 var id = overrides.id || Ext.id();
1500 var cfg = Ext.applyIf(overrides, this.initialConfig);
1501 cfg.id = id; // prevent dup id
1502 return new this.constructor(cfg);
1506 * Gets the xtype for this component as registered with {@link Ext.ComponentMgr}. For a list of all
1507 * available xtypes, see the {@link Ext.Component} header. Example usage:
1509 var t = new Ext.form.TextField();
1510 alert(t.getXType()); // alerts 'textfield'
1512 * @return {String} The xtype
1514 getXType : function(){
1515 return this.constructor.xtype;
1519 * <p>Tests whether or not this Component is of a specific xtype. This can test whether this Component is descended
1520 * from the xtype (default) or whether it is directly of the xtype specified (shallow = true).</p>
1521 * <p><b>If using your own subclasses, be aware that a Component must register its own xtype
1522 * to participate in determination of inherited xtypes.</b></p>
1523 * <p>For a list of all available xtypes, see the {@link Ext.Component} header.</p>
1524 * <p>Example usage:</p>
1526 var t = new Ext.form.TextField();
1527 var isText = t.isXType('textfield'); // true
1528 var isBoxSubclass = t.isXType('box'); // true, descended from BoxComponent
1529 var isBoxInstance = t.isXType('box', true); // false, not a direct BoxComponent instance
1531 * @param {String} xtype The xtype to check for this Component
1532 * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
1533 * the default), or true to check whether this Component is directly of the specified xtype.
1534 * @return {Boolean} True if this component descends from the specified xtype, false otherwise.
1536 isXType : function(xtype, shallow){
1537 //assume a string by default
1538 if (Ext.isFunction(xtype)){
1539 xtype = xtype.xtype; //handle being passed the class, e.g. Ext.Component
1540 }else if (Ext.isObject(xtype)){
1541 xtype = xtype.constructor.xtype; //handle being passed an instance
1544 return !shallow ? ('/' + this.getXTypes() + '/').indexOf('/' + xtype + '/') != -1 : this.constructor.xtype == xtype;
1548 * <p>Returns this Component's xtype hierarchy as a slash-delimited string. For a list of all
1549 * available xtypes, see the {@link Ext.Component} header.</p>
1550 * <p><b>If using your own subclasses, be aware that a Component must register its own xtype
1551 * to participate in determination of inherited xtypes.</b></p>
1552 * <p>Example usage:</p>
1554 var t = new Ext.form.TextField();
1555 alert(t.getXTypes()); // alerts 'component/box/field/textfield'
1557 * @return {String} The xtype hierarchy string
1559 getXTypes : function(){
1560 var tc = this.constructor;
1562 var c = [], sc = this;
1563 while(sc && sc.constructor.xtype){
1564 c.unshift(sc.constructor.xtype);
1565 sc = sc.constructor.superclass;
1568 tc.xtypes = c.join('/');
1574 * Find a container above this component at any level by a custom function. If the passed function returns
1575 * true, the container will be returned.
1576 * @param {Function} fn The custom function to call with the arguments (container, this component).
1577 * @return {Ext.Container} The first Container for which the custom function returns true
1579 findParentBy : function(fn) {
1580 for (var p = this.ownerCt; (p != null) && !fn(p, this); p = p.ownerCt);
1585 * Find a container above this component at any level by xtype or class
1586 * @param {String/Class} xtype The xtype string for a component, or the class of the component directly
1587 * @return {Ext.Container} The first Container which matches the given xtype or class
1589 findParentByType : function(xtype) {
1590 return Ext.isFunction(xtype) ?
1591 this.findParentBy(function(p){
1592 return p.constructor === xtype;
1594 this.findParentBy(function(p){
1595 return p.constructor.xtype === xtype;
1599 getDomPositionEl : function(){
1600 return this.getPositionEl ? this.getPositionEl() : this.getEl();
1604 purgeListeners : function(){
1605 Ext.Component.superclass.purgeListeners.call(this);
1607 this.on('beforedestroy', this.clearMons, this, {single: true});
1612 clearMons : function(){
1613 Ext.each(this.mons, function(m){
1614 m.item.un(m.ename, m.fn, m.scope);
1620 createMons: function(){
1623 this.on('beforedestroy', this.clearMons, this, {single: true});
1627 // internal function for auto removal of assigned event handlers on destruction
1628 mon : function(item, ename, fn, scope, opt){
1630 if(Ext.isObject(ename)){
1631 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
1638 if(Ext.isFunction(o[e])){
1641 item: item, ename: e, fn: o[e], scope: o.scope
1643 item.on(e, o[e], o.scope, o);
1645 // individual options
1647 item: item, ename: e, fn: o[e], scope: o.scope
1656 item: item, ename: ename, fn: fn, scope: scope
1658 item.on(ename, fn, scope, opt);
1661 // protected, opposite of mon
1662 mun : function(item, ename, fn, scope){
1665 for(var i = 0, len = this.mons.length; i < len; ++i){
1667 if(item === mon.item && ename == mon.ename && fn === mon.fn && scope === mon.scope){
1668 this.mons.splice(i, 1);
1669 item.un(ename, fn, scope);
1678 * Returns the next component in the owning container
1679 * @return Ext.Component
1681 nextSibling : function(){
1683 var index = this.ownerCt.items.indexOf(this);
1684 if(index != -1 && index+1 < this.ownerCt.items.getCount()){
1685 return this.ownerCt.items.itemAt(index+1);
1692 * Returns the previous component in the owning container
1693 * @return Ext.Component
1695 previousSibling : function(){
1697 var index = this.ownerCt.items.indexOf(this);
1699 return this.ownerCt.items.itemAt(index-1);
1706 * Provides the link for Observable's fireEvent method to bubble up the ownership hierarchy.
1707 * @return {Ext.Container} the Container which owns this Component.
1709 getBubbleTarget : function(){
1710 return this.ownerCt;
1714 Ext.reg('component', Ext.Component);
1716 * @class Ext.Action
\r
1717 * <p>An Action is a piece of reusable functionality that can be abstracted out of any particular component so that it
\r
1718 * can be usefully shared among multiple components. Actions let you share handlers, configuration options and UI
\r
1719 * updates across any components that support the Action interface (primarily {@link Ext.Toolbar}, {@link Ext.Button}
\r
1720 * and {@link Ext.menu.Menu} components).</p>
\r
1721 * <p>Aside from supporting the config object interface, any component that needs to use Actions must also support
\r
1722 * the following method list, as these will be called as needed by the Action class: setText(string), setIconCls(string),
\r
1723 * setDisabled(boolean), setVisible(boolean) and setHandler(function).</p>
\r
1724 * Example usage:<br>
\r
1726 // Define the shared action. Each component below will have the same
\r
1727 // display text and icon, and will display the same message on click.
\r
1728 var action = new Ext.Action({
\r
1729 {@link #text}: 'Do something',
\r
1730 {@link #handler}: function(){
\r
1731 Ext.Msg.alert('Click', 'You did something.');
\r
1733 {@link #iconCls}: 'do-something',
\r
1734 {@link #itemId}: 'myAction'
\r
1737 var panel = new Ext.Panel({
\r
1742 // Add the action directly to a toolbar as a menu button
\r
1745 text: 'Action Menu',
\r
1746 // Add the action to a menu as a text item
\r
1751 // Add the action to the panel body as a standard button
\r
1752 new Ext.Button(action)
\r
1754 renderTo: Ext.getBody()
\r
1757 // Change the text for all components using the action
\r
1758 action.setText('Something else');
\r
1760 // Reference an action through a container using the itemId
\r
1761 var btn = panel.getComponent('myAction');
\r
1762 var aRef = btn.baseAction;
\r
1763 aRef.setText('New text');
\r
1766 * @param {Object} config The configuration options
\r
1768 Ext.Action = function(config){
\r
1769 this.initialConfig = config;
\r
1770 this.itemId = config.itemId = (config.itemId || config.id || Ext.id());
\r
1774 Ext.Action.prototype = {
\r
1776 * @cfg {String} text The text to set for all components using this action (defaults to '').
\r
1779 * @cfg {String} iconCls
\r
1780 * The CSS class selector that specifies a background image to be used as the header icon for
\r
1781 * all components using this action (defaults to '').
\r
1782 * <p>An example of specifying a custom icon class would be something like:
\r
1784 // specify the property in the config for the class:
\r
1786 iconCls: 'do-something'
\r
1788 // css class that specifies background image to be used as the icon image:
\r
1789 .do-something { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
\r
1793 * @cfg {Boolean} disabled True to disable all components using this action, false to enable them (defaults to false).
\r
1796 * @cfg {Boolean} hidden True to hide all components using this action, false to show them (defaults to false).
\r
1799 * @cfg {Function} handler The function that will be invoked by each component tied to this action
\r
1800 * when the component's primary event is triggered (defaults to undefined).
\r
1803 * @cfg {String} itemId
\r
1804 * See {@link Ext.Component}.{@link Ext.Component#itemId itemId}.
\r
1807 * @cfg {Object} scope The scope in which the {@link #handler} function will execute.
\r
1814 * Sets the text to be displayed by all components using this action.
\r
1815 * @param {String} text The text to display
\r
1817 setText : function(text){
\r
1818 this.initialConfig.text = text;
\r
1819 this.callEach('setText', [text]);
\r
1823 * Gets the text currently displayed by all components using this action.
\r
1825 getText : function(){
\r
1826 return this.initialConfig.text;
\r
1830 * Sets the icon CSS class for all components using this action. The class should supply
\r
1831 * a background image that will be used as the icon image.
\r
1832 * @param {String} cls The CSS class supplying the icon image
\r
1834 setIconClass : function(cls){
\r
1835 this.initialConfig.iconCls = cls;
\r
1836 this.callEach('setIconClass', [cls]);
\r
1840 * Gets the icon CSS class currently used by all components using this action.
\r
1842 getIconClass : function(){
\r
1843 return this.initialConfig.iconCls;
\r
1847 * Sets the disabled state of all components using this action. Shortcut method
\r
1848 * for {@link #enable} and {@link #disable}.
\r
1849 * @param {Boolean} disabled True to disable the component, false to enable it
\r
1851 setDisabled : function(v){
\r
1852 this.initialConfig.disabled = v;
\r
1853 this.callEach('setDisabled', [v]);
\r
1857 * Enables all components using this action.
\r
1859 enable : function(){
\r
1860 this.setDisabled(false);
\r
1864 * Disables all components using this action.
\r
1866 disable : function(){
\r
1867 this.setDisabled(true);
\r
1871 * Returns true if the components using this action are currently disabled, else returns false.
\r
1873 isDisabled : function(){
\r
1874 return this.initialConfig.disabled;
\r
1878 * Sets the hidden state of all components using this action. Shortcut method
\r
1879 * for <code>{@link #hide}</code> and <code>{@link #show}</code>.
\r
1880 * @param {Boolean} hidden True to hide the component, false to show it
\r
1882 setHidden : function(v){
\r
1883 this.initialConfig.hidden = v;
\r
1884 this.callEach('setVisible', [!v]);
\r
1888 * Shows all components using this action.
\r
1890 show : function(){
\r
1891 this.setHidden(false);
\r
1895 * Hides all components using this action.
\r
1897 hide : function(){
\r
1898 this.setHidden(true);
\r
1902 * Returns true if the components using this action are currently hidden, else returns false.
\r
1904 isHidden : function(){
\r
1905 return this.initialConfig.hidden;
\r
1909 * Sets the function that will be called by each component using this action when its primary event is triggered.
\r
1910 * @param {Function} fn The function that will be invoked by the action's components. The function
\r
1911 * will be called with no arguments.
\r
1912 * @param {Object} scope The scope in which the function will execute
\r
1914 setHandler : function(fn, scope){
\r
1915 this.initialConfig.handler = fn;
\r
1916 this.initialConfig.scope = scope;
\r
1917 this.callEach('setHandler', [fn, scope]);
\r
1921 * Executes the specified function once for each component currently tied to this action. The function passed
\r
1922 * in should accept a single argument that will be an object that supports the basic Action config/method interface.
\r
1923 * @param {Function} fn The function to execute for each component
\r
1924 * @param {Object} scope The scope in which the function will execute
\r
1926 each : function(fn, scope){
\r
1927 Ext.each(this.items, fn, scope);
\r
1931 callEach : function(fnName, args){
\r
1932 var cs = this.items;
\r
1933 for(var i = 0, len = cs.length; i < len; i++){
\r
1934 cs[i][fnName].apply(cs[i], args);
\r
1939 addComponent : function(comp){
\r
1940 this.items.push(comp);
\r
1941 comp.on('destroy', this.removeComponent, this);
\r
1945 removeComponent : function(comp){
\r
1946 this.items.remove(comp);
\r
1950 * Executes this action manually using the handler function specified in the original config object
\r
1951 * or the handler function set with <code>{@link #setHandler}</code>. Any arguments passed to this
\r
1952 * function will be passed on to the handler function.
\r
1953 * @param {Mixed} arg1 (optional) Variable number of arguments passed to the handler function
\r
1954 * @param {Mixed} arg2 (optional)
\r
1955 * @param {Mixed} etc... (optional)
\r
1957 execute : function(){
\r
1958 this.initialConfig.handler.apply(this.initialConfig.scope || window, arguments);
\r
1963 * @extends Ext.Element
1964 * An extended {@link Ext.Element} object that supports a shadow and shim, constrain to viewport and
1965 * automatic maintaining of shadow/shim positions.
1966 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
1967 * @cfg {String/Boolean} shadow True to automatically create an {@link Ext.Shadow}, or a string indicating the
1968 * shadow's display {@link Ext.Shadow#mode}. False to disable the shadow. (defaults to false)
1969 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: 'div', cls: 'x-layer'}).
1970 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
1971 * @cfg {String} cls CSS class to add to the element
1972 * @cfg {Number} zindex Starting z-index (defaults to 11000)
1973 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 4)
1974 * @cfg {Boolean} useDisplay
1975 * Defaults to use css offsets to hide the Layer. Specify <tt>true</tt>
1976 * to use css style <tt>'display:none;'</tt> to hide the Layer.
1978 * @param {Object} config An object with config options.
1979 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
1982 Ext.Layer = function(config, existingEl){
1983 config = config || {};
1984 var dh = Ext.DomHelper;
1985 var cp = config.parentEl, pel = cp ? Ext.getDom(cp) : document.body;
1987 this.dom = Ext.getDom(existingEl);
1990 var o = config.dh || {tag: 'div', cls: 'x-layer'};
1991 this.dom = dh.append(pel, o);
1994 this.addClass(config.cls);
1996 this.constrain = config.constrain !== false;
1997 this.setVisibilityMode(Ext.Element.VISIBILITY);
1999 this.id = this.dom.id = config.id;
2001 this.id = Ext.id(this.dom);
2003 this.zindex = config.zindex || this.getZIndex();
2004 this.position('absolute', this.zindex);
2006 this.shadowOffset = config.shadowOffset || 4;
2007 this.shadow = new Ext.Shadow({
2008 offset : this.shadowOffset,
2009 mode : config.shadow
2012 this.shadowOffset = 0;
2014 this.useShim = config.shim !== false && Ext.useShims;
2015 this.useDisplay = config.useDisplay;
2019 var supr = Ext.Element.prototype;
2021 // shims are shared among layer to keep from having 100 iframes
2024 Ext.extend(Ext.Layer, Ext.Element, {
2026 getZIndex : function(){
2027 return this.zindex || parseInt((this.getShim() || this).getStyle('z-index'), 10) || 11000;
2030 getShim : function(){
2037 var shim = shims.shift();
2039 shim = this.createShim();
2040 shim.enableDisplayMode('block');
2041 shim.dom.style.display = 'none';
2042 shim.dom.style.visibility = 'visible';
2044 var pn = this.dom.parentNode;
2045 if(shim.dom.parentNode != pn){
2046 pn.insertBefore(shim.dom, this.dom);
2048 shim.setStyle('z-index', this.getZIndex()-2);
2053 hideShim : function(){
2055 this.shim.setDisplayed(false);
2056 shims.push(this.shim);
2061 disableShadow : function(){
2063 this.shadowDisabled = true;
2065 this.lastShadowOffset = this.shadowOffset;
2066 this.shadowOffset = 0;
2070 enableShadow : function(show){
2072 this.shadowDisabled = false;
2073 this.shadowOffset = this.lastShadowOffset;
2074 delete this.lastShadowOffset;
2082 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
2083 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
2084 sync : function(doShow){
2085 var sw = this.shadow;
2086 if(!this.updating && this.isVisible() && (sw || this.useShim)){
2087 var sh = this.getShim();
2089 var w = this.getWidth(),
2090 h = this.getHeight();
2092 var l = this.getLeft(true),
2093 t = this.getTop(true);
2095 if(sw && !this.shadowDisabled){
2096 if(doShow && !sw.isVisible()){
2099 sw.realign(l, t, w, h);
2105 // fit the shim behind the shadow, so it is shimmed too
2106 var a = sw.adjusts, s = sh.dom.style;
2107 s.left = (Math.min(l, l+a.l))+'px';
2108 s.top = (Math.min(t, t+a.t))+'px';
2109 s.width = (w+a.w)+'px';
2110 s.height = (h+a.h)+'px';
2117 sh.setLeftTop(l, t);
2124 destroy : function(){
2129 this.removeAllListeners();
2130 Ext.removeNode(this.dom);
2131 Ext.Element.uncache(this.id);
2134 remove : function(){
2139 beginUpdate : function(){
2140 this.updating = true;
2144 endUpdate : function(){
2145 this.updating = false;
2150 hideUnders : function(negOffset){
2158 constrainXY : function(){
2160 var vw = Ext.lib.Dom.getViewWidth(),
2161 vh = Ext.lib.Dom.getViewHeight();
2162 var s = Ext.getDoc().getScroll();
2164 var xy = this.getXY();
2165 var x = xy[0], y = xy[1];
2166 var so = this.shadowOffset;
2167 var w = this.dom.offsetWidth+so, h = this.dom.offsetHeight+so;
2168 // only move it if it needs it
2170 // first validate right/bottom
2171 if((x + w) > vw+s.left){
2175 if((y + h) > vh+s.top){
2179 // then make sure top/left isn't negative
2190 var ay = this.avoidY;
2191 if(y <= ay && (y+h) >= ay){
2197 supr.setXY.call(this, xy);
2204 isVisible : function(){
2205 return this.visible;
2209 showAction : function(){
2210 this.visible = true; // track visibility to prevent getStyle calls
2211 if(this.useDisplay === true){
2212 this.setDisplayed('');
2213 }else if(this.lastXY){
2214 supr.setXY.call(this, this.lastXY);
2215 }else if(this.lastLT){
2216 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
2221 hideAction : function(){
2222 this.visible = false;
2223 if(this.useDisplay === true){
2224 this.setDisplayed(false);
2226 this.setLeftTop(-10000,-10000);
2230 // overridden Element method
2231 setVisible : function(v, a, d, c, e){
2236 var cb = function(){
2241 }.createDelegate(this);
2242 supr.setVisible.call(this, true, true, d, cb, e);
2245 this.hideUnders(true);
2254 }.createDelegate(this);
2256 supr.setVisible.call(this, v, a, d, cb, e);
2266 storeXY : function(xy){
2271 storeLeftTop : function(left, top){
2273 this.lastLT = [left, top];
2277 beforeFx : function(){
2278 this.beforeAction();
2279 return Ext.Layer.superclass.beforeFx.apply(this, arguments);
2283 afterFx : function(){
2284 Ext.Layer.superclass.afterFx.apply(this, arguments);
2285 this.sync(this.isVisible());
2289 beforeAction : function(){
2290 if(!this.updating && this.shadow){
2295 // overridden Element method
2296 setLeft : function(left){
2297 this.storeLeftTop(left, this.getTop(true));
2298 supr.setLeft.apply(this, arguments);
2303 setTop : function(top){
2304 this.storeLeftTop(this.getLeft(true), top);
2305 supr.setTop.apply(this, arguments);
2310 setLeftTop : function(left, top){
2311 this.storeLeftTop(left, top);
2312 supr.setLeftTop.apply(this, arguments);
2317 setXY : function(xy, a, d, c, e){
2319 this.beforeAction();
2321 var cb = this.createCB(c);
2322 supr.setXY.call(this, xy, a, d, cb, e);
2330 createCB : function(c){
2341 // overridden Element method
2342 setX : function(x, a, d, c, e){
2343 this.setXY([x, this.getY()], a, d, c, e);
2347 // overridden Element method
2348 setY : function(y, a, d, c, e){
2349 this.setXY([this.getX(), y], a, d, c, e);
2353 // overridden Element method
2354 setSize : function(w, h, a, d, c, e){
2355 this.beforeAction();
2356 var cb = this.createCB(c);
2357 supr.setSize.call(this, w, h, a, d, cb, e);
2364 // overridden Element method
2365 setWidth : function(w, a, d, c, e){
2366 this.beforeAction();
2367 var cb = this.createCB(c);
2368 supr.setWidth.call(this, w, a, d, cb, e);
2375 // overridden Element method
2376 setHeight : function(h, a, d, c, e){
2377 this.beforeAction();
2378 var cb = this.createCB(c);
2379 supr.setHeight.call(this, h, a, d, cb, e);
2386 // overridden Element method
2387 setBounds : function(x, y, w, h, a, d, c, e){
2388 this.beforeAction();
2389 var cb = this.createCB(c);
2391 this.storeXY([x, y]);
2392 supr.setXY.call(this, [x, y]);
2393 supr.setSize.call(this, w, h, a, d, cb, e);
2396 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
2402 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
2403 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
2404 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
2405 * @param {Number} zindex The new z-index to set
2406 * @return {this} The Layer
2408 setZIndex : function(zindex){
2409 this.zindex = zindex;
2410 this.setStyle('z-index', zindex + 2);
2412 this.shadow.setZIndex(zindex + 1);
2415 this.shim.setStyle('z-index', zindex);
2422 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
2423 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
2424 * functionality that can also provide the same shadow effect, see the {@link Ext.Layer} class.
2426 * Create a new Shadow
2427 * @param {Object} config The config object
2429 Ext.Shadow = function(config){
2430 Ext.apply(this, config);
2431 if(typeof this.mode != "string"){
2432 this.mode = this.defaultMode;
2434 var o = this.offset, a = {h: 0};
2435 var rad = Math.floor(this.offset/2);
2436 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
2442 a.l -= this.offset + rad;
2443 a.t -= this.offset + rad;
2454 a.l -= (this.offset - rad);
2455 a.t -= this.offset + rad;
2457 a.w -= (this.offset - rad)*2;
2468 a.l -= (this.offset - rad);
2469 a.t -= (this.offset - rad);
2471 a.w -= (this.offset + rad + 1);
2472 a.h -= (this.offset + rad);
2481 Ext.Shadow.prototype = {
2483 * @cfg {String} mode
2484 * The shadow display mode. Supports the following options:<div class="mdetail-params"><ul>
2485 * <li><b><tt>sides</tt></b> : Shadow displays on both sides and bottom only</li>
2486 * <li><b><tt>frame</tt></b> : Shadow displays equally on all four sides</li>
2487 * <li><b><tt>drop</tt></b> : Traditional bottom-right drop shadow</li>
2491 * @cfg {String} offset
2492 * The number of pixels to offset the shadow from the element (defaults to <tt>4</tt>)
2497 defaultMode: "drop",
2500 * Displays the shadow under the target element
2501 * @param {Mixed} targetEl The id or element under which the shadow should display
2503 show : function(target){
2504 target = Ext.get(target);
2506 this.el = Ext.Shadow.Pool.pull();
2507 if(this.el.dom.nextSibling != target.dom){
2508 this.el.insertBefore(target);
2511 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
2513 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
2516 target.getLeft(true),
2517 target.getTop(true),
2521 this.el.dom.style.display = "block";
2525 * Returns true if the shadow is visible, else false
2527 isVisible : function(){
2528 return this.el ? true : false;
2532 * Direct alignment when values are already available. Show must be called at least once before
2533 * calling this method to ensure it is initialized.
2534 * @param {Number} left The target element left position
2535 * @param {Number} top The target element top position
2536 * @param {Number} width The target element width
2537 * @param {Number} height The target element height
2539 realign : function(l, t, w, h){
2543 var a = this.adjusts, d = this.el.dom, s = d.style;
2545 s.left = (l+a.l)+"px";
2546 s.top = (t+a.t)+"px";
2547 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
2548 if(s.width != sws || s.height != shs){
2552 var cn = d.childNodes;
2553 var sww = Math.max(0, (sw-12))+"px";
2554 cn[0].childNodes[1].style.width = sww;
2555 cn[1].childNodes[1].style.width = sww;
2556 cn[2].childNodes[1].style.width = sww;
2557 cn[1].style.height = Math.max(0, (sh-12))+"px";
2567 this.el.dom.style.display = "none";
2568 Ext.Shadow.Pool.push(this.el);
2574 * Adjust the z-index of this shadow
2575 * @param {Number} zindex The new z-index
2577 setZIndex : function(z){
2580 this.el.setStyle("z-index", z);
2585 // Private utility class that manages the internal Shadow cache
2586 Ext.Shadow.Pool = function(){
2588 var markup = Ext.isIE ?
2589 '<div class="x-ie-shadow"></div>' :
2590 '<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>';
2595 sh = Ext.get(Ext.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
2596 sh.autoBoxAdjust = false;
2601 push : function(sh){
2606 * @class Ext.BoxComponent
2607 * @extends Ext.Component
2608 * <p>Base class for any {@link Ext.Component Component} that is to be sized as a box, using width and height.</p>
2609 * <p>BoxComponent provides automatic box model adjustments for sizing and positioning and will work correctly
2610 * within the Component rendering model.</p>
2611 * <p>A BoxComponent may be created as a custom Component which encapsulates any HTML element, either a pre-existing
2612 * element, or one that is created to your specifications at render time. Usually, to participate in layouts,
2613 * a Component will need to be a <b>Box</b>Component in order to have its width and height managed.</p>
2614 * <p>To use a pre-existing element as a BoxComponent, configure it so that you preset the <b>el</b> property to the
2615 * element to reference:<pre><code>
2616 var pageHeader = new Ext.BoxComponent({
2619 * This may then be {@link Ext.Container#add added} to a {@link Ext.Container Container} as a child item.</p>
2620 * <p>To create a BoxComponent based around a HTML element to be created at render time, use the
2621 * {@link Ext.Component#autoEl autoEl} config option which takes the form of a
2622 * {@link Ext.DomHelper DomHelper} specification:<pre><code>
2623 var myImage = new Ext.BoxComponent({
2626 src: '/images/my-image.jpg'
2628 });</code></pre></p>
2630 * @param {Ext.Element/String/Object} config The configuration options.
2633 Ext.BoxComponent = Ext.extend(Ext.Component, {
2635 // tabTip config is used when a BoxComponent is a child of a TabPanel
2637 * @cfg {String} tabTip
2638 * <p><b>Note</b>: this config is only used when this BoxComponent is a child item of a TabPanel.</p>
2639 * A string to be used as innerHTML (html tags are accepted) to show in a tooltip when mousing over
2640 * the associated tab selector element. {@link Ext.QuickTips}.init()
2641 * must be called in order for the tips to render.
2643 // Configs below are used for all Components when rendered by BorderLayout.
2645 * @cfg {String} region <p><b>Note</b>: this config is only used when this BoxComponent is rendered
2646 * by a Container which has been configured to use the <b>{@link Ext.layout.BorderLayout BorderLayout}</b>
2647 * layout manager (e.g. specifying <tt>layout:'border'</tt>).</p><br>
2648 * <p>See {@link Ext.layout.BorderLayout} also.</p>
2650 // margins config is used when a BoxComponent is rendered by BorderLayout or BoxLayout.
2652 * @cfg {Object} margins <p><b>Note</b>: this config is only used when this BoxComponent is rendered
2653 * by a Container which has been configured to use the <b>{@link Ext.layout.BorderLayout BorderLayout}</b>
2654 * or one of the two <b>{@link Ext.layout.BoxLayout BoxLayout} subclasses.</b></p>
2655 * <p>An object containing margins to apply to this BoxComponent in the
2656 * format:</p><pre><code>
2659 right: (right margin),
2660 bottom: (bottom margin),
2663 * <p>May also be a string containing space-separated, numeric margin values. The order of the
2664 * sides associated with each value matches the way CSS processes margin values:</p>
2665 * <p><div class="mdetail-params"><ul>
2666 * <li>If there is only one value, it applies to all sides.</li>
2667 * <li>If there are two values, the top and bottom borders are set to the first value and the
2668 * right and left are set to the second.</li>
2669 * <li>If there are three values, the top is set to the first value, the left and right are set
2670 * to the second, and the bottom is set to the third.</li>
2671 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
2673 * <p>Defaults to:</p><pre><code>
2674 * {top:0, right:0, bottom:0, left:0}
2679 * The local x (left) coordinate for this component if contained within a positioning container.
2683 * The local y (top) coordinate for this component if contained within a positioning container.
2686 * @cfg {Number} pageX
2687 * The page level x coordinate for this component if contained within a positioning container.
2690 * @cfg {Number} pageY
2691 * The page level y coordinate for this component if contained within a positioning container.
2694 * @cfg {Number} height
2695 * The height of this component in pixels (defaults to auto).
2696 * <b>Note</b> to express this dimension as a percentage or offset see {@link Ext.Component#anchor}.
2699 * @cfg {Number} width
2700 * The width of this component in pixels (defaults to auto).
2701 * <b>Note</b> to express this dimension as a percentage or offset see {@link Ext.Component#anchor}.
2704 * @cfg {Boolean} autoHeight
2705 * <p>True to use height:'auto', false to use fixed height (or allow it to be managed by its parent
2706 * Container's {@link Ext.Container#layout layout manager}. Defaults to false.</p>
2707 * <p><b>Note</b>: Although many components inherit this config option, not all will
2708 * function as expected with a height of 'auto'. Setting autoHeight:true means that the
2709 * browser will manage height based on the element's contents, and that Ext will not manage it at all.</p>
2710 * <p>If the <i>browser</i> is managing the height, be aware that resizes performed by the browser in response
2711 * to changes within the structure of the Component cannot be detected. Therefore changes to the height might
2712 * result in elements needing to be synchronized with the new height. Example:</p><pre><code>
2713 var w = new Ext.Window({
2718 title: 'Collapse Me',
2723 beforecollapse: function() {
2726 beforeexpand: function() {
2729 collapse: function() {
2732 expand: function() {
2741 * @cfg {Boolean} autoWidth
2742 * <p>True to use width:'auto', false to use fixed width (or allow it to be managed by its parent
2743 * Container's {@link Ext.Container#layout layout manager}. Defaults to false.</p>
2744 * <p><b>Note</b>: Although many components inherit this config option, not all will
2745 * function as expected with a width of 'auto'. Setting autoWidth:true means that the
2746 * browser will manage width based on the element's contents, and that Ext will not manage it at all.</p>
2747 * <p>If the <i>browser</i> is managing the width, be aware that resizes performed by the browser in response
2748 * to changes within the structure of the Component cannot be detected. Therefore changes to the width might
2749 * result in elements needing to be synchronized with the new width. For example, where the target element is:</p><pre><code>
2750 <div id='grid-container' style='margin-left:25%;width:50%'></div>
2752 * A Panel rendered into that target element must listen for browser window resize in order to relay its
2753 * child items when the browser changes its width:<pre><code>
2754 var myPanel = new Ext.Panel({
2755 renderTo: 'grid-container',
2756 monitorResize: true, // relay on browser resize
2778 /* // private internal config
2779 * {Boolean} deferHeight
2780 * True to defer height calculations to an external component, false to allow this component to set its own
2781 * height (defaults to false).
2785 initComponent : function(){
2786 Ext.BoxComponent.superclass.initComponent.call(this);
2790 * Fires after the component is resized.
2791 * @param {Ext.Component} this
2792 * @param {Number} adjWidth The box-adjusted width that was set
2793 * @param {Number} adjHeight The box-adjusted height that was set
2794 * @param {Number} rawWidth The width that was originally specified
2795 * @param {Number} rawHeight The height that was originally specified
2800 * Fires after the component is moved.
2801 * @param {Ext.Component} this
2802 * @param {Number} x The new x position
2803 * @param {Number} y The new y position
2809 // private, set in afterRender to signify that the component has been rendered
2811 // private, used to defer height settings to subclasses
2815 * Sets the width and height of this BoxComponent. This method fires the {@link #resize} event. This method can accept
2816 * either width and height as separate arguments, or you can pass a size object like <code>{width:10, height:20}</code>.
2817 * @param {Mixed} width The new width to set. This may be one of:<div class="mdetail-params"><ul>
2818 * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li>
2819 * <li>A String used to set the CSS width style.</li>
2820 * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>
2821 * <li><code>undefined</code> to leave the width unchanged.</li>
2823 * @param {Mixed} height The new height to set (not required if a size object is passed as the first arg).
2824 * This may be one of:<div class="mdetail-params"><ul>
2825 * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li>
2826 * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
2827 * <li><code>undefined</code> to leave the height unchanged.</li>
2829 * @return {Ext.BoxComponent} this
2831 setSize : function(w, h){
2832 // support for standard size objects
2833 if(typeof w == 'object'){
2844 // prevent recalcs when not needed
2845 if(this.cacheSizes !== false && this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
2848 this.lastSize = {width: w, height: h};
2849 var adj = this.adjustSize(w, h);
2850 var aw = adj.width, ah = adj.height;
2851 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
2852 var rz = this.getResizeEl();
2853 if(!this.deferHeight && aw !== undefined && ah !== undefined){
2855 }else if(!this.deferHeight && ah !== undefined){
2857 }else if(aw !== undefined){
2860 this.onResize(aw, ah, w, h);
2861 this.fireEvent('resize', this, aw, ah, w, h);
2867 * Sets the width of the component. This method fires the {@link #resize} event.
2868 * @param {Number} width The new width to setThis may be one of:<div class="mdetail-params"><ul>
2869 * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li>
2870 * <li>A String used to set the CSS width style.</li>
2872 * @return {Ext.BoxComponent} this
2874 setWidth : function(width){
2875 return this.setSize(width);
2879 * Sets the height of the component. This method fires the {@link #resize} event.
2880 * @param {Number} height The new height to set. This may be one of:<div class="mdetail-params"><ul>
2881 * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li>
2882 * <li>A String used to set the CSS height style.</li>
2883 * <li><i>undefined</i> to leave the height unchanged.</li>
2885 * @return {Ext.BoxComponent} this
2887 setHeight : function(height){
2888 return this.setSize(undefined, height);
2892 * Gets the current size of the component's underlying element.
2893 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
2895 getSize : function(){
2896 return this.getResizeEl().getSize();
2900 * Gets the current width of the component's underlying element.
2903 getWidth : function(){
2904 return this.getResizeEl().getWidth();
2908 * Gets the current height of the component's underlying element.
2911 getHeight : function(){
2912 return this.getResizeEl().getHeight();
2916 * Gets the current size of the component's underlying element, including space taken by its margins.
2917 * @return {Object} An object containing the element's size {width: (element width + left/right margins), height: (element height + top/bottom margins)}
2919 getOuterSize : function(){
2920 var el = this.getResizeEl();
2921 return {width: el.getWidth() + el.getMargins('lr'),
2922 height: el.getHeight() + el.getMargins('tb')};
2926 * Gets the current XY position of the component's underlying element.
2927 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
2928 * @return {Array} The XY position of the element (e.g., [100, 200])
2930 getPosition : function(local){
2931 var el = this.getPositionEl();
2933 return [el.getLeft(true), el.getTop(true)];
2935 return this.xy || el.getXY();
2939 * Gets the current box measurements of the component's underlying element.
2940 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
2941 * @return {Object} box An object in the format {x, y, width, height}
2943 getBox : function(local){
2944 var pos = this.getPosition(local);
2945 var s = this.getSize();
2952 * Sets the current box measurements of the component's underlying element.
2953 * @param {Object} box An object in the format {x, y, width, height}
2954 * @return {Ext.BoxComponent} this
2956 updateBox : function(box){
2957 this.setSize(box.width, box.height);
2958 this.setPagePosition(box.x, box.y);
2963 * <p>Returns the outermost Element of this Component which defines the Components overall size.</p>
2964 * <p><i>Usually</i> this will return the same Element as <code>{@link #getEl}</code>,
2965 * but in some cases, a Component may have some more wrapping Elements around its main
2966 * active Element.</p>
2967 * <p>An example is a ComboBox. It is encased in a <i>wrapping</i> Element which
2968 * contains both the <code><input></code> Element (which is what would be returned
2969 * by its <code>{@link #getEl}</code> method, <i>and</i> the trigger button Element.
2970 * This Element is returned as the <code>resizeEl</code>.
2972 getResizeEl : function(){
2973 return this.resizeEl || this.el;
2977 getPositionEl : function(){
2978 return this.positionEl || this.el;
2982 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
2983 * This method fires the {@link #move} event.
2984 * @param {Number} left The new left
2985 * @param {Number} top The new top
2986 * @return {Ext.BoxComponent} this
2988 setPosition : function(x, y){
2989 if(x && typeof x[1] == 'number'){
2998 var adj = this.adjustPosition(x, y);
2999 var ax = adj.x, ay = adj.y;
3001 var el = this.getPositionEl();
3002 if(ax !== undefined || ay !== undefined){
3003 if(ax !== undefined && ay !== undefined){
3004 el.setLeftTop(ax, ay);
3005 }else if(ax !== undefined){
3007 }else if(ay !== undefined){
3010 this.onPosition(ax, ay);
3011 this.fireEvent('move', this, ax, ay);
3017 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
3018 * This method fires the {@link #move} event.
3019 * @param {Number} x The new x position
3020 * @param {Number} y The new y position
3021 * @return {Ext.BoxComponent} this
3023 setPagePosition : function(x, y){
3024 if(x && typeof x[1] == 'number'){
3033 if(x === undefined || y === undefined){ // cannot translate undefined points
3036 var p = this.getPositionEl().translatePoints(x, y);
3037 this.setPosition(p.left, p.top);
3042 afterRender : function(){
3043 Ext.BoxComponent.superclass.afterRender.call(this);
3045 this.resizeEl = Ext.get(this.resizeEl);
3047 if(this.positionEl){
3048 this.positionEl = Ext.get(this.positionEl);
3050 this.boxReady = true;
3051 this.setSize(this.width, this.height);
3052 if(this.x || this.y){
3053 this.setPosition(this.x, this.y);
3054 }else if(this.pageX || this.pageY){
3055 this.setPagePosition(this.pageX, this.pageY);
3060 * Force the component's size to recalculate based on the underlying element's current height and width.
3061 * @return {Ext.BoxComponent} this
3063 syncSize : function(){
3064 delete this.lastSize;
3065 this.setSize(this.autoWidth ? undefined : this.getResizeEl().getWidth(), this.autoHeight ? undefined : this.getResizeEl().getHeight());
3070 * Called after the component is resized, this method is empty by default but can be implemented by any
3071 * subclass that needs to perform custom logic after a resize occurs.
3072 * @param {Number} adjWidth The box-adjusted width that was set
3073 * @param {Number} adjHeight The box-adjusted height that was set
3074 * @param {Number} rawWidth The width that was originally specified
3075 * @param {Number} rawHeight The height that was originally specified
3077 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
3082 * Called after the component is moved, this method is empty by default but can be implemented by any
3083 * subclass that needs to perform custom logic after a move occurs.
3084 * @param {Number} x The new x position
3085 * @param {Number} y The new y position
3087 onPosition : function(x, y){
3092 adjustSize : function(w, h){
3096 if(this.autoHeight){
3099 return {width : w, height: h};
3103 adjustPosition : function(x, y){
3104 return {x : x, y: y};
3107 Ext.reg('box', Ext.BoxComponent);
3112 * @extends Ext.BoxComponent
3113 * <p>Used to provide a sizable space in a layout.</p>
3115 * @param {Object} config
3117 Ext.Spacer = Ext.extend(Ext.BoxComponent, {
3120 Ext.reg('spacer', Ext.Spacer);/**
\r
3121 * @class Ext.SplitBar
\r
3122 * @extends Ext.util.Observable
\r
3123 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
\r
3127 var split = new Ext.SplitBar("elementToDrag", "elementToSize",
\r
3128 Ext.SplitBar.HORIZONTAL, Ext.SplitBar.LEFT);
\r
3129 split.setAdapter(new Ext.SplitBar.AbsoluteLayoutAdapter("container"));
\r
3130 split.minSize = 100;
\r
3131 split.maxSize = 600;
\r
3132 split.animate = true;
\r
3133 split.on('moved', splitterMoved);
\r
3136 * Create a new SplitBar
\r
3137 * @param {Mixed} dragElement The element to be dragged and act as the SplitBar.
\r
3138 * @param {Mixed} resizingElement The element to be resized based on where the SplitBar element is dragged
\r
3139 * @param {Number} orientation (optional) Either Ext.SplitBar.HORIZONTAL or Ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
\r
3140 * @param {Number} placement (optional) Either Ext.SplitBar.LEFT or Ext.SplitBar.RIGHT for horizontal or
\r
3141 Ext.SplitBar.TOP or Ext.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
\r
3142 position of the SplitBar).
\r
3144 Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
\r
3147 this.el = Ext.get(dragElement, true);
\r
3148 this.el.dom.unselectable = "on";
\r
3150 this.resizingEl = Ext.get(resizingElement, true);
\r
3154 * The orientation of the split. Either Ext.SplitBar.HORIZONTAL or Ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
\r
3155 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
\r
3158 this.orientation = orientation || Ext.SplitBar.HORIZONTAL;
\r
3161 * The increment, in pixels by which to move this SplitBar. When <i>undefined</i>, the SplitBar moves smoothly.
\r
3163 * @property tickSize
\r
3166 * The minimum size of the resizing element. (Defaults to 0)
\r
3172 * The maximum size of the resizing element. (Defaults to 2000)
\r
3175 this.maxSize = 2000;
\r
3178 * Whether to animate the transition to the new size
\r
3181 this.animate = false;
\r
3184 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
\r
3187 this.useShim = false;
\r
3192 if(!existingProxy){
\r
3194 this.proxy = Ext.SplitBar.createProxy(this.orientation);
\r
3196 this.proxy = Ext.get(existingProxy).dom;
\r
3199 this.dd = new Ext.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
\r
3202 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
\r
3205 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
\r
3208 this.dragSpecs = {};
\r
3211 * @private The adapter to use to positon and resize elements
\r
3213 this.adapter = new Ext.SplitBar.BasicLayoutAdapter();
\r
3214 this.adapter.init(this);
\r
3216 if(this.orientation == Ext.SplitBar.HORIZONTAL){
\r
3218 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Ext.SplitBar.LEFT : Ext.SplitBar.RIGHT);
\r
3219 this.el.addClass("x-splitbar-h");
\r
3222 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Ext.SplitBar.TOP : Ext.SplitBar.BOTTOM);
\r
3223 this.el.addClass("x-splitbar-v");
\r
3229 * Fires when the splitter is moved (alias for {@link #moved})
\r
3230 * @param {Ext.SplitBar} this
\r
3231 * @param {Number} newSize the new width or height
\r
3236 * Fires when the splitter is moved
\r
3237 * @param {Ext.SplitBar} this
\r
3238 * @param {Number} newSize the new width or height
\r
3242 * @event beforeresize
\r
3243 * Fires before the splitter is dragged
\r
3244 * @param {Ext.SplitBar} this
\r
3251 Ext.SplitBar.superclass.constructor.call(this);
\r
3254 Ext.extend(Ext.SplitBar, Ext.util.Observable, {
\r
3255 onStartProxyDrag : function(x, y){
\r
3256 this.fireEvent("beforeresize", this);
\r
3257 this.overlay = Ext.DomHelper.append(document.body, {cls: "x-drag-overlay", html: " "}, true);
\r
3258 this.overlay.unselectable();
\r
3259 this.overlay.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
\r
3260 this.overlay.show();
\r
3261 Ext.get(this.proxy).setDisplayed("block");
\r
3262 var size = this.adapter.getElementSize(this);
\r
3263 this.activeMinSize = this.getMinimumSize();
\r
3264 this.activeMaxSize = this.getMaximumSize();
\r
3265 var c1 = size - this.activeMinSize;
\r
3266 var c2 = Math.max(this.activeMaxSize - size, 0);
\r
3267 if(this.orientation == Ext.SplitBar.HORIZONTAL){
\r
3268 this.dd.resetConstraints();
\r
3269 this.dd.setXConstraint(
\r
3270 this.placement == Ext.SplitBar.LEFT ? c1 : c2,
\r
3271 this.placement == Ext.SplitBar.LEFT ? c2 : c1,
\r
3274 this.dd.setYConstraint(0, 0);
\r
3276 this.dd.resetConstraints();
\r
3277 this.dd.setXConstraint(0, 0);
\r
3278 this.dd.setYConstraint(
\r
3279 this.placement == Ext.SplitBar.TOP ? c1 : c2,
\r
3280 this.placement == Ext.SplitBar.TOP ? c2 : c1,
\r
3284 this.dragSpecs.startSize = size;
\r
3285 this.dragSpecs.startPoint = [x, y];
\r
3286 Ext.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
\r
3290 * @private Called after the drag operation by the DDProxy
\r
3292 onEndProxyDrag : function(e){
\r
3293 Ext.get(this.proxy).setDisplayed(false);
\r
3294 var endPoint = Ext.lib.Event.getXY(e);
\r
3296 Ext.destroy(this.overlay);
\r
3297 delete this.overlay;
\r
3300 if(this.orientation == Ext.SplitBar.HORIZONTAL){
\r
3301 newSize = this.dragSpecs.startSize +
\r
3302 (this.placement == Ext.SplitBar.LEFT ?
\r
3303 endPoint[0] - this.dragSpecs.startPoint[0] :
\r
3304 this.dragSpecs.startPoint[0] - endPoint[0]
\r
3307 newSize = this.dragSpecs.startSize +
\r
3308 (this.placement == Ext.SplitBar.TOP ?
\r
3309 endPoint[1] - this.dragSpecs.startPoint[1] :
\r
3310 this.dragSpecs.startPoint[1] - endPoint[1]
\r
3313 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
\r
3314 if(newSize != this.dragSpecs.startSize){
\r
3315 if(this.fireEvent('beforeapply', this, newSize) !== false){
\r
3316 this.adapter.setElementSize(this, newSize);
\r
3317 this.fireEvent("moved", this, newSize);
\r
3318 this.fireEvent("resize", this, newSize);
\r
3324 * Get the adapter this SplitBar uses
\r
3325 * @return The adapter object
\r
3327 getAdapter : function(){
\r
3328 return this.adapter;
\r
3332 * Set the adapter this SplitBar uses
\r
3333 * @param {Object} adapter A SplitBar adapter object
\r
3335 setAdapter : function(adapter){
\r
3336 this.adapter = adapter;
\r
3337 this.adapter.init(this);
\r
3341 * Gets the minimum size for the resizing element
\r
3342 * @return {Number} The minimum size
\r
3344 getMinimumSize : function(){
\r
3345 return this.minSize;
\r
3349 * Sets the minimum size for the resizing element
\r
3350 * @param {Number} minSize The minimum size
\r
3352 setMinimumSize : function(minSize){
\r
3353 this.minSize = minSize;
\r
3357 * Gets the maximum size for the resizing element
\r
3358 * @return {Number} The maximum size
\r
3360 getMaximumSize : function(){
\r
3361 return this.maxSize;
\r
3365 * Sets the maximum size for the resizing element
\r
3366 * @param {Number} maxSize The maximum size
\r
3368 setMaximumSize : function(maxSize){
\r
3369 this.maxSize = maxSize;
\r
3373 * Sets the initialize size for the resizing element
\r
3374 * @param {Number} size The initial size
\r
3376 setCurrentSize : function(size){
\r
3377 var oldAnimate = this.animate;
\r
3378 this.animate = false;
\r
3379 this.adapter.setElementSize(this, size);
\r
3380 this.animate = oldAnimate;
\r
3384 * Destroy this splitbar.
\r
3385 * @param {Boolean} removeEl True to remove the element
\r
3387 destroy : function(removeEl){
\r
3388 Ext.destroy(this.shim, Ext.get(this.proxy));
\r
3393 this.purgeListeners();
\r
3398 * @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
3400 Ext.SplitBar.createProxy = function(dir){
\r
3401 var proxy = new Ext.Element(document.createElement("div"));
\r
3402 proxy.unselectable();
\r
3403 var cls = 'x-splitbar-proxy';
\r
3404 proxy.addClass(cls + ' ' + (dir == Ext.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
\r
3405 document.body.appendChild(proxy.dom);
\r
3410 * @class Ext.SplitBar.BasicLayoutAdapter
\r
3411 * Default Adapter. It assumes the splitter and resizing element are not positioned
\r
3412 * elements and only gets/sets the width of the element. Generally used for table based layouts.
\r
3414 Ext.SplitBar.BasicLayoutAdapter = function(){
\r
3417 Ext.SplitBar.BasicLayoutAdapter.prototype = {
\r
3418 // do nothing for now
\r
3419 init : function(s){
\r
3423 * Called before drag operations to get the current size of the resizing element.
\r
3424 * @param {Ext.SplitBar} s The SplitBar using this adapter
\r
3426 getElementSize : function(s){
\r
3427 if(s.orientation == Ext.SplitBar.HORIZONTAL){
\r
3428 return s.resizingEl.getWidth();
\r
3430 return s.resizingEl.getHeight();
\r
3435 * Called after drag operations to set the size of the resizing element.
\r
3436 * @param {Ext.SplitBar} s The SplitBar using this adapter
\r
3437 * @param {Number} newSize The new size to set
\r
3438 * @param {Function} onComplete A function to be invoked when resizing is complete
\r
3440 setElementSize : function(s, newSize, onComplete){
\r
3441 if(s.orientation == Ext.SplitBar.HORIZONTAL){
\r
3443 s.resizingEl.setWidth(newSize);
\r
3445 onComplete(s, newSize);
\r
3448 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
\r
3453 s.resizingEl.setHeight(newSize);
\r
3455 onComplete(s, newSize);
\r
3458 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
\r
3465 *@class Ext.SplitBar.AbsoluteLayoutAdapter
\r
3466 * @extends Ext.SplitBar.BasicLayoutAdapter
\r
3467 * Adapter that moves the splitter element to align with the resized sizing element.
\r
3468 * Used with an absolute positioned SplitBar.
\r
3469 * @param {Mixed} container The container that wraps around the absolute positioned content. If it's
\r
3470 * document.body, make sure you assign an id to the body element.
\r
3472 Ext.SplitBar.AbsoluteLayoutAdapter = function(container){
\r
3473 this.basic = new Ext.SplitBar.BasicLayoutAdapter();
\r
3474 this.container = Ext.get(container);
\r
3477 Ext.SplitBar.AbsoluteLayoutAdapter.prototype = {
\r
3478 init : function(s){
\r
3479 this.basic.init(s);
\r
3482 getElementSize : function(s){
\r
3483 return this.basic.getElementSize(s);
\r
3486 setElementSize : function(s, newSize, onComplete){
\r
3487 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
\r
3490 moveSplitter : function(s){
\r
3491 var yes = Ext.SplitBar;
\r
3492 switch(s.placement){
\r
3494 s.el.setX(s.resizingEl.getRight());
\r
3497 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
\r
3500 s.el.setY(s.resizingEl.getBottom());
\r
3503 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
\r
3510 * Orientation constant - Create a vertical SplitBar
\r
3514 Ext.SplitBar.VERTICAL = 1;
\r
3517 * Orientation constant - Create a horizontal SplitBar
\r
3521 Ext.SplitBar.HORIZONTAL = 2;
\r
3524 * Placement constant - The resizing element is to the left of the splitter element
\r
3528 Ext.SplitBar.LEFT = 1;
\r
3531 * Placement constant - The resizing element is to the right of the splitter element
\r
3535 Ext.SplitBar.RIGHT = 2;
\r
3538 * Placement constant - The resizing element is positioned above the splitter element
\r
3542 Ext.SplitBar.TOP = 3;
\r
3545 * Placement constant - The resizing element is positioned under splitter element
\r
3549 Ext.SplitBar.BOTTOM = 4;
\r
3551 * @class Ext.Container
\r
3552 * @extends Ext.BoxComponent
\r
3553 * <p>Base class for any {@link Ext.BoxComponent} that may contain other Components. Containers handle the
\r
3554 * basic behavior of containing items, namely adding, inserting and removing items.</p>
\r
3556 * <p>The most commonly used Container classes are {@link Ext.Panel}, {@link Ext.Window} and {@link Ext.TabPanel}.
\r
3557 * If you do not need the capabilities offered by the aforementioned classes you can create a lightweight
\r
3558 * Container to be encapsulated by an HTML element to your specifications by using the
\r
3559 * <tt><b>{@link Ext.Component#autoEl autoEl}</b></tt> config option. This is a useful technique when creating
\r
3560 * embedded {@link Ext.layout.ColumnLayout column} layouts inside {@link Ext.form.FormPanel FormPanels}
\r
3561 * for example.</p>
\r
3563 * <p>The code below illustrates both how to explicitly create a Container, and how to implicitly
\r
3564 * create one using the <b><tt>'container'</tt></b> xtype:<pre><code>
\r
3565 // explicitly create a Container
\r
3566 var embeddedColumns = new Ext.Container({
\r
3567 autoEl: 'div', // This is the default
\r
3570 // implicitly create Container by specifying xtype
\r
3571 xtype: 'container',
\r
3572 autoEl: 'div', // This is the default.
\r
3579 // The two items below will be Ext.Containers, each encapsulated by a <DIV> element.
\r
3582 xtype: 'datefield',
\r
3583 name: 'startDate',
\r
3584 fieldLabel: 'Start date'
\r
3588 xtype: 'datefield',
\r
3590 fieldLabel: 'End date'
\r
3593 });</code></pre></p>
\r
3595 * <p><u><b>Layout</b></u></p>
\r
3596 * <p>Container classes delegate the rendering of child Components to a layout
\r
3597 * manager class which must be configured into the Container using the
\r
3598 * <code><b>{@link #layout}</b></code> configuration property.</p>
\r
3599 * <p>When either specifying child <code>{@link #items}</code> of a Container,
\r
3600 * or dynamically {@link #add adding} Components to a Container, remember to
\r
3601 * consider how you wish the Container to arrange those child elements, and
\r
3602 * whether those child elements need to be sized using one of Ext's built-in
\r
3603 * <b><code>{@link #layout}</code></b> schemes. By default, Containers use the
\r
3604 * {@link Ext.layout.ContainerLayout ContainerLayout} scheme which only
\r
3605 * renders child components, appending them one after the other inside the
\r
3606 * Container, and <b>does not apply any sizing</b> at all.</p>
\r
3607 * <p>A common mistake is when a developer neglects to specify a
\r
3608 * <b><code>{@link #layout}</code></b> (e.g. widgets like GridPanels or
\r
3609 * TreePanels are added to Containers for which no <tt><b>{@link #layout}</b></tt>
\r
3610 * has been specified). If a Container is left to use the default
\r
3611 * {@link Ext.layout.ContainerLayout ContainerLayout} scheme, none of its
\r
3612 * child components will be resized, or changed in any way when the Container
\r
3614 * <p>Certain layout managers allow dynamic addition of child components.
\r
3615 * Those that do include {@link Ext.layout.CardLayout},
\r
3616 * {@link Ext.layout.AnchorLayout}, {@link Ext.layout.FormLayout}, and
\r
3617 * {@link Ext.layout.TableLayout}. For example:<pre><code>
\r
3618 // Create the GridPanel.
\r
3619 var myNewGrid = new Ext.grid.GridPanel({
\r
3621 columns: myColumnModel,
\r
3622 title: 'Results', // the title becomes the title of the tab
\r
3625 myTabPanel.add(myNewGrid); // {@link Ext.TabPanel} implicitly uses {@link Ext.layout.CardLayout CardLayout}
\r
3626 myTabPanel.{@link Ext.TabPanel#setActiveTab setActiveTab}(myNewGrid);
\r
3627 * </code></pre></p>
\r
3628 * <p>The example above adds a newly created GridPanel to a TabPanel. Note that
\r
3629 * a TabPanel uses {@link Ext.layout.CardLayout} as its layout manager which
\r
3630 * means all its child items are sized to {@link Ext.layout.FitLayout fit}
\r
3631 * exactly into its client area.
\r
3632 * <p><b><u>Overnesting is a common problem</u></b>.
\r
3633 * An example of overnesting occurs when a GridPanel is added to a TabPanel
\r
3634 * by wrapping the GridPanel <i>inside</i> a wrapping Panel (that has no
\r
3635 * <tt><b>{@link #layout}</b></tt> specified) and then add that wrapping Panel
\r
3636 * to the TabPanel. The point to realize is that a GridPanel <b>is</b> a
\r
3637 * Component which can be added directly to a Container. If the wrapping Panel
\r
3638 * has no <tt><b>{@link #layout}</b></tt> configuration, then the overnested
\r
3639 * GridPanel will not be sized as expected.<p>
\r
3641 * <p><u><b>Adding via remote configuration</b></u></p>
\r
3643 * <p>A server side script can be used to add Components which are generated dynamically on the server.
\r
3644 * An example of adding a GridPanel to a TabPanel where the GridPanel is generated by the server
\r
3645 * based on certain parameters:
\r
3647 // execute an Ajax request to invoke server side script:
\r
3648 Ext.Ajax.request({
\r
3649 url: 'gen-invoice-grid.php',
\r
3650 // send additional parameters to instruct server script
\r
3652 startDate: Ext.getCmp('start-date').getValue(),
\r
3653 endDate: Ext.getCmp('end-date').getValue()
\r
3655 // process the response object to add it to the TabPanel:
\r
3656 success: function(xhr) {
\r
3657 var newComponent = eval(xhr.responseText); // see discussion below
\r
3658 myTabPanel.add(newComponent); // add the component to the TabPanel
\r
3659 myTabPanel.setActiveTab(newComponent);
\r
3661 failure: function() {
\r
3662 Ext.Msg.alert("Grid create failed", "Server communication failure");
\r
3666 * <p>The server script needs to return an executable Javascript statement which, when processed
\r
3667 * using <tt>eval()</tt>, will return either a config object with an {@link Ext.Component#xtype xtype},
\r
3668 * or an instantiated Component. The server might return this for example:</p><pre><code>
\r
3670 function formatDate(value){
\r
3671 return value ? value.dateFormat('M d, Y') : '';
\r
3674 var store = new Ext.data.Store({
\r
3675 url: 'get-invoice-data.php',
\r
3677 startDate: '01/01/2008',
\r
3678 endDate: '01/31/2008'
\r
3680 reader: new Ext.data.JsonReader({
\r
3681 record: 'transaction',
\r
3683 totalRecords: 'total'
\r
3687 {name: 'date', type: 'date', dateFormat: 'm/d/Y'},
\r
3688 {name: 'value', type: 'float'}
\r
3692 var grid = new Ext.grid.GridPanel({
\r
3693 title: 'Invoice Report',
\r
3694 bbar: new Ext.PagingToolbar(store),
\r
3697 {header: "Customer", width: 250, dataIndex: 'customer', sortable: true},
\r
3698 {header: "Invoice Number", width: 120, dataIndex: 'invNo', sortable: true},
\r
3699 {header: "Invoice Date", width: 100, dataIndex: 'date', renderer: formatDate, sortable: true},
\r
3700 {header: "Value", width: 120, dataIndex: 'value', renderer: 'usMoney', sortable: true}
\r
3704 return grid; // return instantiated component
\r
3707 * <p>When the above code fragment is passed through the <tt>eval</tt> function in the success handler
\r
3708 * of the Ajax request, the code is executed by the Javascript processor, and the anonymous function
\r
3709 * runs, and returns the instantiated grid component.</p>
\r
3710 * <p>Note: since the code above is <i>generated</i> by a server script, the <tt>baseParams</tt> for
\r
3711 * the Store, the metadata to allow generation of the Record layout, and the ColumnModel
\r
3712 * can all be generated into the code since these are all known on the server.</p>
\r
3714 * @xtype container
\r
3716 Ext.Container = Ext.extend(Ext.BoxComponent, {
\r
3718 * @cfg {Boolean} monitorResize
\r
3719 * True to automatically monitor window resize events to handle anything that is sensitive to the current size
\r
3720 * of the viewport. This value is typically managed by the chosen <code>{@link #layout}</code> and should not need
\r
3721 * to be set manually.
\r
3724 * @cfg {String/Object} layout
\r
3725 * <p><b>*Important</b>: In order for child items to be correctly sized and
\r
3726 * positioned, typically a layout manager <b>must</b> be specified through
\r
3727 * the <code>layout</code> configuration option.</p>
\r
3728 * <br><p>The sizing and positioning of child {@link items} is the responsibility of
\r
3729 * the Container's layout manager which creates and manages the type of layout
\r
3730 * you have in mind. For example:</p><pre><code>
\r
3732 width:300, height: 300,
\r
3733 layout: 'fit', // explicitly set layout manager: override the default (layout:'auto')
\r
3735 title: 'Panel inside a Window'
\r
3739 * <p>If the {@link #layout} configuration is not explicitly specified for
\r
3740 * a general purpose container (e.g. Container or Panel) the
\r
3741 * {@link Ext.layout.ContainerLayout default layout manager} will be used
\r
3742 * which does nothing but render child components sequentially into the
\r
3743 * Container (no sizing or positioning will be performed in this situation).
\r
3744 * Some container classes implicitly specify a default layout
\r
3745 * (e.g. FormPanel specifies <code>layout:'form'</code>). Other specific
\r
3746 * purpose classes internally specify/manage their internal layout (e.g.
\r
3747 * GridPanel, TabPanel, TreePanel, Toolbar, Menu, etc.).</p>
\r
3748 * <br><p><b><code>layout</code></b> may be specified as either as an Object or
\r
3749 * as a String:</p><div><ul class="mdetail-params">
\r
3751 * <li><u>Specify as an Object</u></li>
\r
3752 * <div><ul class="mdetail-params">
\r
3753 * <li>Example usage:</li>
\r
3762 * <li><tt><b>type</b></tt></li>
\r
3763 * <br/><p>The layout type to be used for this container. If not specified,
\r
3764 * a default {@link Ext.layout.ContainerLayout} will be created and used.</p>
\r
3765 * <br/><p>Valid layout <tt>type</tt> values are:</p>
\r
3766 * <div class="sub-desc"><ul class="mdetail-params">
\r
3767 * <li><tt><b>{@link Ext.layout.AbsoluteLayout absolute}</b></tt></li>
\r
3768 * <li><tt><b>{@link Ext.layout.AccordionLayout accordion}</b></tt></li>
\r
3769 * <li><tt><b>{@link Ext.layout.AnchorLayout anchor}</b></tt></li>
\r
3770 * <li><tt><b>{@link Ext.layout.ContainerLayout auto}</b></tt> <b>Default</b></li>
\r
3771 * <li><tt><b>{@link Ext.layout.BorderLayout border}</b></tt></li>
\r
3772 * <li><tt><b>{@link Ext.layout.CardLayout card}</b></tt></li>
\r
3773 * <li><tt><b>{@link Ext.layout.ColumnLayout column}</b></tt></li>
\r
3774 * <li><tt><b>{@link Ext.layout.FitLayout fit}</b></tt></li>
\r
3775 * <li><tt><b>{@link Ext.layout.FormLayout form}</b></tt></li>
\r
3776 * <li><tt><b>{@link Ext.layout.HBoxLayout hbox}</b></tt></li>
\r
3777 * <li><tt><b>{@link Ext.layout.MenuLayout menu}</b></tt></li>
\r
3778 * <li><tt><b>{@link Ext.layout.TableLayout table}</b></tt></li>
\r
3779 * <li><tt><b>{@link Ext.layout.ToolbarLayout toolbar}</b></tt></li>
\r
3780 * <li><tt><b>{@link Ext.layout.VBoxLayout vbox}</b></tt></li>
\r
3783 * <li>Layout specific configuration properties</li>
\r
3784 * <br/><p>Additional layout specific configuration properties may also be
\r
3785 * specified. For complete details regarding the valid config options for
\r
3786 * each layout type, see the layout class corresponding to the <tt>type</tt>
\r
3791 * <li><u>Specify as a String</u></li>
\r
3792 * <div><ul class="mdetail-params">
\r
3793 * <li>Example usage:</li>
\r
3801 * <li><tt><b>layout</b></tt></li>
\r
3802 * <br/><p>The layout <tt>type</tt> to be used for this container (see list
\r
3803 * of valid layout type values above).</p><br/>
\r
3804 * <li><tt><b>{@link #layoutConfig}</b></tt></li>
\r
3805 * <br/><p>Additional layout specific configuration properties. For complete
\r
3806 * details regarding the valid config options for each layout type, see the
\r
3807 * layout class corresponding to the <tt>layout</tt> specified.</p>
\r
3808 * </ul></div></ul></div>
\r
3811 * @cfg {Object} layoutConfig
\r
3812 * This is a config object containing properties specific to the chosen
\r
3813 * <b><code>{@link #layout}</code></b> if <b><code>{@link #layout}</code></b>
\r
3814 * has been specified as a <i>string</i>.</p>
\r
3817 * @cfg {Boolean/Number} bufferResize
\r
3818 * When set to true (50 milliseconds) or a number of milliseconds, the layout assigned for this container will buffer
\r
3819 * the frequency it calculates and does a re-layout of components. This is useful for heavy containers or containers
\r
3820 * with a large quantity of sub-components for which frequent layout calls would be expensive. Defaults to <tt>50</tt>.
\r
3825 * @cfg {String/Number} activeItem
\r
3826 * A string component id or the numeric index of the component that should be initially activated within the
\r
3827 * container's layout on render. For example, activeItem: 'item-1' or activeItem: 0 (index 0 = the first
\r
3828 * item in the container's collection). activeItem only applies to layout styles that can display
\r
3829 * items one at a time (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout} and
\r
3830 * {@link Ext.layout.FitLayout}). Related to {@link Ext.layout.ContainerLayout#activeItem}.
\r
3833 * @cfg {Object/Array} items
\r
3834 * <pre><b>** IMPORTANT</b>: be sure to <b>{@link #layout specify a <code>layout</code>} if needed ! **</b></pre>
\r
3835 * <p>A single item, or an array of child Components to be added to this container,
\r
3836 * for example:</p>
\r
3838 // specifying a single item
\r
3840 layout: 'fit', // specify a layout!
\r
3842 // specifying multiple items
\r
3843 items: [{...}, {...}],
\r
3844 layout: 'anchor', // specify a layout!
\r
3846 * <p>Each item may be:</p>
\r
3847 * <div><ul class="mdetail-params">
\r
3848 * <li>any type of object based on {@link Ext.Component}</li>
\r
3849 * <li>a fully instanciated object or</li>
\r
3850 * <li>an object literal that:</li>
\r
3851 * <div><ul class="mdetail-params">
\r
3852 * <li>has a specified <code>{@link Ext.Component#xtype xtype}</code></li>
\r
3853 * <li>the {@link Ext.Component#xtype} specified is associated with the Component
\r
3854 * desired and should be chosen from one of the available xtypes as listed
\r
3855 * in {@link Ext.Component}.</li>
\r
3856 * <li>If an <code>{@link Ext.Component#xtype xtype}</code> is not explicitly
\r
3857 * specified, the {@link #defaultType} for that Container is used.</li>
\r
3858 * <li>will be "lazily instanciated", avoiding the overhead of constructing a fully
\r
3859 * instanciated Component object</li>
\r
3860 * </ul></div></ul></div>
\r
3861 * <p><b>Notes</b>:</p>
\r
3862 * <div><ul class="mdetail-params">
\r
3863 * <li>Ext uses lazy rendering. Child Components will only be rendered
\r
3864 * should it become necessary. Items are automatically laid out when they are first
\r
3865 * shown (no sizing is done while hidden), or in response to a {@link #doLayout} call.</li>
\r
3866 * <li>Do not specify <code>{@link Ext.Panel#contentEl contentEl}</code>/
\r
3867 * <code>{@link Ext.Panel#html html}</code> with <code>items</code>.</li>
\r
3871 * @cfg {Object} defaults
\r
3872 * <p>A config object that will be applied to all components added to this container either via the {@link #items}
\r
3873 * config or via the {@link #add} or {@link #insert} methods. The <tt>defaults</tt> config can contain any
\r
3874 * number of name/value property pairs to be added to each item, and should be valid for the types of items
\r
3875 * being added to the container. For example, to automatically apply padding to the body of each of a set of
\r
3876 * contained {@link Ext.Panel} items, you could pass: <tt>defaults: {bodyStyle:'padding:15px'}</tt>.</p><br/>
\r
3877 * <p><b>Note</b>: <tt>defaults</tt> will not be applied to config objects if the option is already specified.
\r
3878 * For example:</p><pre><code>
\r
3879 defaults: { // defaults are applied to items, not the container
\r
3884 xtype: 'panel', // defaults <b>do not</b> have precedence over
\r
3885 id: 'panel1', // options in config objects, so the defaults
\r
3886 autoScroll: false // will not be applied here, panel1 will be autoScroll:false
\r
3888 new Ext.Panel({ // defaults <b>do</b> have precedence over options
\r
3889 id: 'panel2', // options in components, so the defaults
\r
3890 autoScroll: false // will be applied here, panel2 will be autoScroll:true.
\r
3897 /** @cfg {Boolean} autoDestroy
\r
3898 * If true the container will automatically destroy any contained component that is removed from it, else
\r
3899 * destruction must be handled manually (defaults to true).
\r
3901 autoDestroy : true,
\r
3903 /** @cfg {Boolean} forceLayout
\r
3904 * If true the container will force a layout initially even if hidden or collapsed. This option
\r
3905 * is useful for forcing forms to render in collapsed or hidden containers. (defaults to false).
\r
3907 forceLayout: false,
\r
3909 /** @cfg {Boolean} hideBorders
\r
3910 * True to hide the borders of each contained component, false to defer to the component's existing
\r
3911 * border settings (defaults to false).
\r
3913 /** @cfg {String} defaultType
\r
3914 * <p>The default {@link Ext.Component xtype} of child Components to create in this Container when
\r
3915 * a child item is specified as a raw configuration object, rather than as an instantiated Component.</p>
\r
3916 * <p>Defaults to <tt>'panel'</tt>, except {@link Ext.menu.Menu} which defaults to <tt>'menuitem'</tt>,
\r
3917 * and {@link Ext.Toolbar} and {@link Ext.ButtonGroup} which default to <tt>'button'</tt>.</p>
\r
3919 defaultType : 'panel',
\r
3921 /** @cfg {String} resizeEvent
\r
3922 * The event to listen to for resizing in layouts. Defaults to <tt>'resize'</tt>.
\r
3924 resizeEvent: 'resize',
\r
3927 * @cfg {Array} bubbleEvents
\r
3928 * <p>An array of events that, when fired, should be bubbled to any parent container.
\r
3929 * Defaults to <tt>['add', 'remove']</tt>.
\r
3931 bubbleEvents: ['add', 'remove'],
\r
3934 initComponent : function(){
\r
3935 Ext.Container.superclass.initComponent.call(this);
\r
3939 * @event afterlayout
\r
3940 * Fires when the components in this container are arranged by the associated layout manager.
\r
3941 * @param {Ext.Container} this
\r
3942 * @param {ContainerLayout} layout The ContainerLayout implementation for this container
\r
3946 * @event beforeadd
\r
3947 * Fires before any {@link Ext.Component} is added or inserted into the container.
\r
3948 * A handler can return false to cancel the add.
\r
3949 * @param {Ext.Container} this
\r
3950 * @param {Ext.Component} component The component being added
\r
3951 * @param {Number} index The index at which the component will be added to the container's items collection
\r
3955 * @event beforeremove
\r
3956 * Fires before any {@link Ext.Component} is removed from the container. A handler can return
\r
3957 * false to cancel the remove.
\r
3958 * @param {Ext.Container} this
\r
3959 * @param {Ext.Component} component The component being removed
\r
3965 * Fires after any {@link Ext.Component} is added or inserted into the container.
\r
3966 * @param {Ext.Container} this
\r
3967 * @param {Ext.Component} component The component that was added
\r
3968 * @param {Number} index The index at which the component was added to the container's items collection
\r
3974 * Fires after any {@link Ext.Component} is removed from the container.
\r
3975 * @param {Ext.Container} this
\r
3976 * @param {Ext.Component} component The component that was removed
\r
3981 this.enableBubble(this.bubbleEvents);
\r
3984 * The collection of components in this container as a {@link Ext.util.MixedCollection}
\r
3985 * @type MixedCollection
\r
3988 var items = this.items;
\r
3990 delete this.items;
\r
3996 initItems : function(){
\r
3998 this.items = new Ext.util.MixedCollection(false, this.getComponentId);
\r
3999 this.getLayout(); // initialize the layout
\r
4004 setLayout : function(layout){
\r
4005 if(this.layout && this.layout != layout){
\r
4006 this.layout.setContainer(null);
\r
4009 this.layout = layout;
\r
4010 layout.setContainer(this);
\r
4013 afterRender: function(){
\r
4014 Ext.Container.superclass.afterRender.call(this);
\r
4016 this.layout = 'auto';
\r
4018 if(Ext.isObject(this.layout) && !this.layout.layout){
\r
4019 this.layoutConfig = this.layout;
\r
4020 this.layout = this.layoutConfig.type;
\r
4022 if(Ext.isString(this.layout)){
\r
4023 this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig);
\r
4025 this.setLayout(this.layout);
\r
4027 if(this.activeItem !== undefined){
\r
4028 var item = this.activeItem;
\r
4029 delete this.activeItem;
\r
4030 this.layout.setActiveItem(item);
\r
4032 if(!this.ownerCt){
\r
4033 // force a layout if no ownerCt is set
\r
4034 this.doLayout(false, true);
\r
4036 if(this.monitorResize === true){
\r
4037 Ext.EventManager.onWindowResize(this.doLayout, this, [false]);
\r
4042 * <p>Returns the Element to be used to contain the child Components of this Container.</p>
\r
4043 * <p>An implementation is provided which returns the Container's {@link #getEl Element}, but
\r
4044 * if there is a more complex structure to a Container, this may be overridden to return
\r
4045 * the element into which the {@link #layout layout} renders child Components.</p>
\r
4046 * @return {Ext.Element} The Element to render child Components into.
\r
4048 getLayoutTarget : function(){
\r
4052 // private - used as the key lookup function for the items collection
\r
4053 getComponentId : function(comp){
\r
4054 return comp.getItemId();
\r
4058 * <p>Adds {@link Ext.Component Component}(s) to this Container.</p>
\r
4059 * <br><p><b>Description</b></u> :
\r
4060 * <div><ul class="mdetail-params">
\r
4061 * <li>Fires the {@link #beforeadd} event before adding</li>
\r
4062 * <li>The Container's {@link #defaults default config values} will be applied
\r
4063 * accordingly (see <code>{@link #defaults}</code> for details).</li>
\r
4064 * <li>Fires the {@link #add} event after the component has been added.</li>
\r
4066 * <br><p><b>Notes</b></u> :
\r
4067 * <div><ul class="mdetail-params">
\r
4068 * <li>If the Container is <i>already rendered</i> when <tt>add</tt>
\r
4069 * is called, you may need to call {@link #doLayout} to refresh the view which causes
\r
4070 * any unrendered child Components to be rendered. This is required so that you can
\r
4071 * <tt>add</tt> multiple child components if needed while only refreshing the layout
\r
4072 * once. For example:<pre><code>
\r
4073 var tb = new {@link Ext.Toolbar}();
\r
4074 tb.render(document.body); // toolbar is rendered
\r
4075 tb.add({text:'Button 1'}); // add multiple items ({@link #defaultType} for {@link Ext.Toolbar Toolbar} is 'button')
\r
4076 tb.add({text:'Button 2'});
\r
4077 tb.{@link #doLayout}(); // refresh the layout
\r
4078 * </code></pre></li>
\r
4079 * <li><i>Warning:</i> Containers directly managed by the BorderLayout layout manager
\r
4080 * may not be removed or added. See the Notes for {@link Ext.layout.BorderLayout BorderLayout}
\r
4081 * for more details.</li>
\r
4083 * @param {Object/Array} component
\r
4084 * <p>Either a single component or an Array of components to add. See
\r
4085 * <code>{@link #items}</code> for additional information.</p>
\r
4086 * @param {Object} (Optional) component_2
\r
4087 * @param {Object} (Optional) component_n
\r
4088 * @return {Ext.Component} component The Component (or config object) that was added.
\r
4090 add : function(comp){
\r
4092 var args = arguments.length > 1;
\r
4093 if(args || Ext.isArray(comp)){
\r
4094 Ext.each(args ? arguments : comp, function(c){
\r
4099 var c = this.lookupComponent(this.applyDefaults(comp));
\r
4100 var pos = this.items.length;
\r
4101 if(this.fireEvent('beforeadd', this, c, pos) !== false && this.onBeforeAdd(c) !== false){
\r
4102 this.items.add(c);
\r
4105 this.fireEvent('add', this, c, pos);
\r
4110 onAdd : function(c){
\r
4111 // Empty template method
\r
4115 * Inserts a Component into this Container at a specified index. Fires the
\r
4116 * {@link #beforeadd} event before inserting, then fires the {@link #add} event after the
\r
4117 * Component has been inserted.
\r
4118 * @param {Number} index The index at which the Component will be inserted
\r
4119 * into the Container's items collection
\r
4120 * @param {Ext.Component} component The child Component to insert.<br><br>
\r
4121 * Ext uses lazy rendering, and will only render the inserted Component should
\r
4122 * it become necessary.<br><br>
\r
4123 * A Component config object may be passed in order to avoid the overhead of
\r
4124 * constructing a real Component object if lazy rendering might mean that the
\r
4125 * inserted Component will not be rendered immediately. To take advantage of
\r
4126 * this 'lazy instantiation', set the {@link Ext.Component#xtype} config
\r
4127 * property to the registered type of the Component wanted.<br><br>
\r
4128 * For a list of all available xtypes, see {@link Ext.Component}.
\r
4129 * @return {Ext.Component} component The Component (or config object) that was
\r
4130 * inserted with the Container's default config values applied.
\r
4132 insert : function(index, comp){
\r
4134 var a = arguments, len = a.length;
\r
4136 for(var i = len-1; i >= 1; --i) {
\r
4137 this.insert(index, a[i]);
\r
4141 var c = this.lookupComponent(this.applyDefaults(comp));
\r
4142 index = Math.min(index, this.items.length);
\r
4143 if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){
\r
4144 if(c.ownerCt == this){
\r
4145 this.items.remove(c);
\r
4147 this.items.insert(index, c);
\r
4150 this.fireEvent('add', this, c, index);
\r
4156 applyDefaults : function(c){
\r
4157 if(this.defaults){
\r
4158 if(Ext.isString(c)){
\r
4159 c = Ext.ComponentMgr.get(c);
\r
4160 Ext.apply(c, this.defaults);
\r
4161 }else if(!c.events){
\r
4162 Ext.applyIf(c, this.defaults);
\r
4164 Ext.apply(c, this.defaults);
\r
4171 onBeforeAdd : function(item){
\r
4173 item.ownerCt.remove(item, false);
\r
4175 if(this.hideBorders === true){
\r
4176 item.border = (item.border === true);
\r
4181 * Removes a component from this container. Fires the {@link #beforeremove} event before removing, then fires
\r
4182 * the {@link #remove} event after the component has been removed.
\r
4183 * @param {Component/String} component The component reference or id to remove.
\r
4184 * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
\r
4185 * Defaults to the value of this Container's {@link #autoDestroy} config.
\r
4186 * @return {Ext.Component} component The Component that was removed.
\r
4188 remove : function(comp, autoDestroy){
\r
4190 var c = this.getComponent(comp);
\r
4191 if(c && this.fireEvent('beforeremove', this, c) !== false){
\r
4193 if(this.layout && this.rendered){
\r
4194 this.layout.onRemove(c);
\r
4197 this.items.remove(c);
\r
4198 if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){
\r
4201 this.fireEvent('remove', this, c);
\r
4206 onRemove: function(c){
\r
4207 // Empty template method
\r
4211 * Removes all components from this container.
\r
4212 * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
\r
4213 * Defaults to the value of this Container's {@link #autoDestroy} config.
\r
4214 * @return {Array} Array of the destroyed components
\r
4216 removeAll: function(autoDestroy){
\r
4218 var item, rem = [], items = [];
\r
4219 this.items.each(function(i){
\r
4222 for (var i = 0, len = rem.length; i < len; ++i){
\r
4224 this.remove(item, autoDestroy);
\r
4225 if(item.ownerCt !== this){
\r
4233 * Examines this container's <code>{@link #items}</code> <b>property</b>
\r
4234 * and gets a direct child component of this container.
\r
4235 * @param {String/Number} comp This parameter may be any of the following:
\r
4236 * <div><ul class="mdetail-params">
\r
4237 * <li>a <b><tt>String</tt></b> : representing the <code>{@link Ext.Component#itemId itemId}</code>
\r
4238 * or <code>{@link Ext.Component#id id}</code> of the child component </li>
\r
4239 * <li>a <b><tt>Number</tt></b> : representing the position of the child component
\r
4240 * within the <code>{@link #items}</code> <b>property</b></li>
\r
4242 * <p>For additional information see {@link Ext.util.MixedCollection#get}.
\r
4243 * @return Ext.Component The component (if found).
\r
4245 getComponent : function(comp){
\r
4246 if(Ext.isObject(comp)){
\r
4247 comp = comp.getItemId();
\r
4249 return this.items.get(comp);
\r
4253 lookupComponent : function(comp){
\r
4254 if(Ext.isString(comp)){
\r
4255 return Ext.ComponentMgr.get(comp);
\r
4256 }else if(!comp.events){
\r
4257 return this.createComponent(comp);
\r
4263 createComponent : function(config){
\r
4264 return Ext.create(config, this.defaultType);
\r
4268 canLayout: function() {
\r
4269 var el = this.getVisibilityEl();
\r
4270 return el && !el.isStyle("display", "none");
\r
4275 * Force this container's layout to be recalculated. A call to this function is required after adding a new component
\r
4276 * to an already rendered container, or possibly after changing sizing/position properties of child components.
\r
4277 * @param {Boolean} shallow (optional) True to only calc the layout of this component, and let child components auto
\r
4278 * calc layouts as required (defaults to false, which calls doLayout recursively for each subcontainer)
\r
4279 * @param {Boolean} force (optional) True to force a layout to occur, even if the item is hidden.
\r
4280 * @return {Ext.Container} this
\r
4282 doLayout: function(shallow, force){
\r
4283 var rendered = this.rendered;
\r
4284 forceLayout = force || this.forceLayout;
\r
4286 if(!this.canLayout() || this.collapsed){
\r
4287 this.deferLayout = this.deferLayout || !shallow;
\r
4291 shallow = shallow && !this.deferLayout;
\r
4293 delete this.deferLayout;
\r
4295 if(rendered && this.layout){
\r
4296 this.layout.layout();
\r
4298 if(shallow !== true && this.items){
\r
4299 var cs = this.items.items;
\r
4300 for(var i = 0, len = cs.length; i < len; i++){
\r
4303 c.doLayout(false, forceLayout);
\r
4308 this.onLayout(shallow, forceLayout);
\r
4310 // Initial layout completed
\r
4311 this.hasLayout = true;
\r
4312 delete this.forceLayout;
\r
4316 onLayout : Ext.emptyFn,
\r
4319 shouldBufferLayout: function(){
\r
4321 * Returns true if the container should buffer a layout.
\r
4322 * This is true only if the container has previously been laid out
\r
4323 * and has a parent container that is pending a layout.
\r
4325 var hl = this.hasLayout;
\r
4327 // Only ever buffer if we've laid out the first time and we have one pending.
\r
4328 return hl ? !this.hasLayoutPending() : false;
\r
4330 // Never buffer initial layout
\r
4335 hasLayoutPending: function(){
\r
4336 // Traverse hierarchy to see if any parent container has a pending layout.
\r
4337 var pending = false;
\r
4338 this.ownerCt.bubble(function(c){
\r
4339 if(c.layoutPending){
\r
4347 onShow : function(){
\r
4348 Ext.Container.superclass.onShow.call(this);
\r
4349 if(this.deferLayout !== undefined){
\r
4350 this.doLayout(true);
\r
4355 * Returns the layout currently in use by the container. If the container does not currently have a layout
\r
4356 * set, a default {@link Ext.layout.ContainerLayout} will be created and set as the container's layout.
\r
4357 * @return {ContainerLayout} layout The container's layout
\r
4359 getLayout : function(){
\r
4361 var layout = new Ext.layout.ContainerLayout(this.layoutConfig);
\r
4362 this.setLayout(layout);
\r
4364 return this.layout;
\r
4368 beforeDestroy : function(){
\r
4370 Ext.destroy.apply(Ext, this.items.items);
\r
4372 if(this.monitorResize){
\r
4373 Ext.EventManager.removeResizeListener(this.doLayout, this);
\r
4375 Ext.destroy(this.layout);
\r
4376 Ext.Container.superclass.beforeDestroy.call(this);
\r
4380 * Bubbles up the component/container heirarchy, calling the specified function with each component. The scope (<i>this</i>) of
\r
4381 * function call will be the scope provided or the current component. The arguments to the function
\r
4382 * will be the args provided or the current component. If the function returns false at any point,
\r
4383 * the bubble is stopped.
\r
4384 * @param {Function} fn The function to call
\r
4385 * @param {Object} scope (optional) The scope of the function (defaults to current node)
\r
4386 * @param {Array} args (optional) The args to call the function with (default to passing the current component)
\r
4387 * @return {Ext.Container} this
\r
4389 bubble : function(fn, scope, args){
\r
4392 if(fn.apply(scope || p, args || [p]) === false){
\r
4401 * Cascades down the component/container heirarchy from this component (called first), calling the specified function with
\r
4402 * each component. The scope (<i>this</i>) of
\r
4403 * function call will be the scope provided or the current component. The arguments to the function
\r
4404 * will be the args provided or the current component. If the function returns false at any point,
\r
4405 * the cascade is stopped on that branch.
\r
4406 * @param {Function} fn The function to call
\r
4407 * @param {Object} scope (optional) The scope of the function (defaults to current component)
\r
4408 * @param {Array} args (optional) The args to call the function with (defaults to passing the current component)
\r
4409 * @return {Ext.Container} this
\r
4411 cascade : function(fn, scope, args){
\r
4412 if(fn.apply(scope || this, args || [this]) !== false){
\r
4414 var cs = this.items.items;
\r
4415 for(var i = 0, len = cs.length; i < len; i++){
\r
4416 if(cs[i].cascade){
\r
4417 cs[i].cascade(fn, scope, args);
\r
4419 fn.apply(scope || cs[i], args || [cs[i]]);
\r
4428 * Find a component under this container at any level by id
\r
4429 * @param {String} id
\r
4430 * @return Ext.Component
\r
4432 findById : function(id){
\r
4434 this.cascade(function(c){
\r
4435 if(ct != c && c.id === id){
\r
4444 * Find a component under this container at any level by xtype or class
\r
4445 * @param {String/Class} xtype The xtype string for a component, or the class of the component directly
\r
4446 * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
\r
4447 * the default), or true to check whether this Component is directly of the specified xtype.
\r
4448 * @return {Array} Array of Ext.Components
\r
4450 findByType : function(xtype, shallow){
\r
4451 return this.findBy(function(c){
\r
4452 return c.isXType(xtype, shallow);
\r
4457 * Find a component under this container at any level by property
\r
4458 * @param {String} prop
\r
4459 * @param {String} value
\r
4460 * @return {Array} Array of Ext.Components
\r
4462 find : function(prop, value){
\r
4463 return this.findBy(function(c){
\r
4464 return c[prop] === value;
\r
4469 * Find a component under this container at any level by a custom function. If the passed function returns
\r
4470 * true, the component will be included in the results. The passed function is called with the arguments (component, this container).
\r
4471 * @param {Function} fn The function to call
\r
4472 * @param {Object} scope (optional)
\r
4473 * @return {Array} Array of Ext.Components
\r
4475 findBy : function(fn, scope){
\r
4476 var m = [], ct = this;
\r
4477 this.cascade(function(c){
\r
4478 if(ct != c && fn.call(scope || c, c, ct) === true){
\r
4486 * Get a component contained by this container (alias for items.get(key))
\r
4487 * @param {String/Number} key The index or id of the component
\r
4488 * @return {Ext.Component} Ext.Component
\r
4490 get : function(key){
\r
4491 return this.items.get(key);
\r
4495 Ext.Container.LAYOUTS = {};
\r
4496 Ext.reg('container', Ext.Container);
\r
4498 * @class Ext.layout.ContainerLayout
4499 * <p>The ContainerLayout class is the default layout manager delegated by {@link Ext.Container} to
4500 * render any child Components when no <tt>{@link Ext.Container#layout layout}</tt> is configured into
4501 * a {@link Ext.Container Container}. ContainerLayout provides the basic foundation for all other layout
4502 * classes in Ext. It simply renders all child Components into the Container, performing no sizing or
4503 * positioning services. To utilize a layout that provides sizing and positioning of child Components,
4504 * specify an appropriate <tt>{@link Ext.Container#layout layout}</tt>.</p>
4505 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
4506 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
4508 Ext.layout.ContainerLayout = function(config){
4509 Ext.apply(this, config);
4512 Ext.layout.ContainerLayout.prototype = {
4514 * @cfg {String} extraCls
4515 * <p>An optional extra CSS class that will be added to the container. This can be useful for adding
4516 * customized styles to the container or any of its children using standard CSS rules. See
4517 * {@link Ext.Component}.{@link Ext.Component#ctCls ctCls} also.</p>
4518 * <p><b>Note</b>: <tt>extraCls</tt> defaults to <tt>''</tt> except for the following classes
4519 * which assign a value by default:
4520 * <div class="mdetail-params"><ul>
4521 * <li>{@link Ext.layout.AbsoluteLayout Absolute Layout} : <tt>'x-abs-layout-item'</tt></li>
4522 * <li>{@link Ext.layout.Box Box Layout} : <tt>'x-box-item'</tt></li>
4523 * <li>{@link Ext.layout.ColumnLayout Column Layout} : <tt>'x-column'</tt></li>
4525 * To configure the above Classes with an extra CSS class append to the default. For example,
4526 * for ColumnLayout:<pre><code>
4527 * extraCls: 'x-column custom-class'
4532 * @cfg {Boolean} renderHidden
4533 * True to hide each contained item on render (defaults to false).
4537 * A reference to the {@link Ext.Component} that is active. For example, <pre><code>
4538 * if(myPanel.layout.activeItem.id == 'item-1') { ... }
4540 * <tt>activeItem</tt> only applies to layout styles that can display items one at a time
4541 * (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout}
4542 * and {@link Ext.layout.FitLayout}). Read-only. Related to {@link Ext.Container#activeItem}.
4543 * @type {Ext.Component}
4544 * @property activeItem
4548 monitorResize:false,
4553 layout : function(){
4554 var target = this.container.getLayoutTarget();
4555 this.onLayout(this.container, target);
4556 this.container.fireEvent('afterlayout', this.container, this);
4560 onLayout : function(ct, target){
4561 this.renderAll(ct, target);
4565 isValidParent : function(c, target){
4566 return target && c.getDomPositionEl().dom.parentNode == (target.dom || target);
4570 renderAll : function(ct, target){
4571 var items = ct.items.items;
4572 for(var i = 0, len = items.length; i < len; i++) {
4574 if(c && (!c.rendered || !this.isValidParent(c, target))){
4575 this.renderItem(c, i, target);
4581 renderItem : function(c, position, target){
4582 if(c && !c.rendered){
4583 c.render(target, position);
4584 this.configureItem(c, position);
4585 }else if(c && !this.isValidParent(c, target)){
4586 if(Ext.isNumber(position)){
4587 position = target.dom.childNodes[position];
4589 target.dom.insertBefore(c.getDomPositionEl().dom, position || null);
4590 c.container = target;
4591 this.configureItem(c, position);
4596 configureItem: function(c, position){
4598 var t = c.getPositionEl ? c.getPositionEl() : c;
4599 t.addClass(this.extraCls);
4601 if (this.renderHidden && c != this.activeItem) {
4604 if(c.doLayout && this.forceLayout){
4605 c.doLayout(false, true);
4609 onRemove: function(c){
4610 if(this.activeItem == c){
4611 delete this.activeItem;
4613 if(c.rendered && this.extraCls){
4614 var t = c.getPositionEl ? c.getPositionEl() : c;
4615 t.removeClass(this.extraCls);
4620 onResize: function(){
4621 var ct = this.container,
4627 if(b = ct.bufferResize){
4628 // Only allow if we should buffer the layout
4629 if(ct.shouldBufferLayout()){
4630 if(!this.resizeTask){
4631 this.resizeTask = new Ext.util.DelayedTask(this.runLayout, this);
4632 this.resizeBuffer = Ext.isNumber(b) ? b : 50;
4634 ct.layoutPending = true;
4635 this.resizeTask.delay(this.resizeBuffer);
4643 runLayout: function(){
4644 var ct = this.container;
4646 delete ct.layoutPending;
4650 setContainer : function(ct){
4651 if(this.monitorResize && ct != this.container){
4652 var old = this.container;
4654 old.un(old.resizeEvent, this.onResize, this);
4657 ct.on(ct.resizeEvent, this.onResize, this);
4660 this.container = ct;
4664 parseMargins : function(v){
4665 if(Ext.isNumber(v)){
4668 var ms = v.split(' ');
4669 var len = ms.length;
4683 top:parseInt(ms[0], 10) || 0,
4684 right:parseInt(ms[1], 10) || 0,
4685 bottom:parseInt(ms[2], 10) || 0,
4686 left:parseInt(ms[3], 10) || 0
4691 * The {@link Ext.Template Ext.Template} used by Field rendering layout classes (such as
4692 * {@link Ext.layout.FormLayout}) to create the DOM structure of a fully wrapped,
4693 * labeled and styled form Field. A default Template is supplied, but this may be
4694 * overriden to create custom field structures. The template processes values returned from
4695 * {@link Ext.layout.FormLayout#getTemplateArgs}.
4696 * @property fieldTpl
4697 * @type Ext.Template
4699 fieldTpl: (function() {
4700 var t = new Ext.Template(
4701 '<div class="x-form-item {itemCls}" tabIndex="-1">',
4702 '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{labelSeparator}</label>',
4703 '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
4704 '</div><div class="{clearCls}"></div>',
4707 t.disableFormats = true;
4712 * Destroys this layout. This is a template method that is empty by default, but should be implemented
4713 * by subclasses that require explicit destruction to purge event handlers or remove DOM nodes.
4716 destroy : Ext.emptyFn
4718 Ext.Container.LAYOUTS['auto'] = Ext.layout.ContainerLayout;/**
\r
4719 * @class Ext.layout.FitLayout
\r
4720 * @extends Ext.layout.ContainerLayout
\r
4721 * <p>This is a base class for layouts that contain <b>a single item</b> that automatically expands to fill the layout's
\r
4722 * container. This class is intended to be extended or created via the <tt>layout:'fit'</tt> {@link Ext.Container#layout}
\r
4723 * config, and should generally not need to be created directly via the new keyword.</p>
\r
4724 * <p>FitLayout does not have any direct config options (other than inherited ones). To fit a panel to a container
\r
4725 * using FitLayout, simply set layout:'fit' on the container and add a single panel to it. If the container has
\r
4726 * multiple panels, only the first one will be displayed. Example usage:</p>
\r
4728 var p = new Ext.Panel({
\r
4729 title: 'Fit Layout',
\r
4732 title: 'Inner Panel',
\r
4733 html: '<p>This is the inner panel content</p>',
\r
4739 Ext.layout.FitLayout = Ext.extend(Ext.layout.ContainerLayout, {
\r
4741 monitorResize:true,
\r
4744 onLayout : function(ct, target){
\r
4745 Ext.layout.FitLayout.superclass.onLayout.call(this, ct, target);
\r
4746 if(!this.container.collapsed){
\r
4747 var sz = (Ext.isIE6 && Ext.isStrict && target.dom == document.body) ? target.getViewSize() : target.getStyleSize();
\r
4748 this.setItemSize(this.activeItem || ct.items.itemAt(0), sz);
\r
4753 setItemSize : function(item, size){
\r
4754 if(item && size.height > 0){ // display none?
\r
4755 item.setSize(size);
\r
4759 Ext.Container.LAYOUTS['fit'] = Ext.layout.FitLayout;/**
\r
4760 * @class Ext.layout.CardLayout
\r
4761 * @extends Ext.layout.FitLayout
\r
4762 * <p>This layout manages multiple child Components, each fitted to the Container, where only a single child Component can be
\r
4763 * visible at any given time. This layout style is most commonly used for wizards, tab implementations, etc.
\r
4764 * This class is intended to be extended or created via the layout:'card' {@link Ext.Container#layout} config,
\r
4765 * and should generally not need to be created directly via the new keyword.</p>
\r
4766 * <p>The CardLayout's focal method is {@link #setActiveItem}. Since only one panel is displayed at a time,
\r
4767 * the only way to move from one Component to the next is by calling setActiveItem, passing the id or index of
\r
4768 * the next panel to display. The layout itself does not provide a user interface for handling this navigation,
\r
4769 * so that functionality must be provided by the developer.</p>
\r
4770 * <p>In the following example, a simplistic wizard setup is demonstrated. A button bar is added
\r
4771 * to the footer of the containing panel to provide navigation buttons. The buttons will be handled by a
\r
4772 * common navigation routine -- for this example, the implementation of that routine has been ommitted since
\r
4773 * it can be any type of custom logic. Note that other uses of a CardLayout (like a tab control) would require a
\r
4774 * completely different implementation. For serious implementations, a better approach would be to extend
\r
4775 * CardLayout to provide the custom functionality needed. Example usage:</p>
\r
4777 var navHandler = function(direction){
\r
4778 // This routine could contain business logic required to manage the navigation steps.
\r
4779 // It would call setActiveItem as needed, manage navigation button state, handle any
\r
4780 // branching logic that might be required, handle alternate actions like cancellation
\r
4781 // or finalization, etc. A complete wizard implementation could get pretty
\r
4782 // sophisticated depending on the complexity required, and should probably be
\r
4783 // done as a subclass of CardLayout in a real-world implementation.
\r
4786 var card = new Ext.Panel({
\r
4787 title: 'Example Wizard',
\r
4789 activeItem: 0, // make sure the active item is set on the container config!
\r
4790 bodyStyle: 'padding:15px',
\r
4792 // applied to each contained panel
\r
4795 // just an example of one possible navigation scheme, using buttons
\r
4800 handler: navHandler.createDelegate(this, [-1]),
\r
4803 '->', // greedy spacer so that the buttons are aligned to each side
\r
4807 handler: navHandler.createDelegate(this, [1])
\r
4810 // the panels (or "cards") within the layout
\r
4813 html: '<h1>Welcome to the Wizard!</h1><p>Step 1 of 3</p>'
\r
4816 html: '<p>Step 2 of 3</p>'
\r
4819 html: '<h1>Congratulations!</h1><p>Step 3 of 3 - Complete</p>'
\r
4824 Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, {
\r
4826 * @cfg {Boolean} deferredRender
\r
4827 * True to render each contained item at the time it becomes active, false to render all contained items
\r
4828 * as soon as the layout is rendered (defaults to false). If there is a significant amount of content or
\r
4829 * a lot of heavy controls being rendered into panels that are not displayed by default, setting this to
\r
4830 * true might improve performance.
\r
4832 deferredRender : false,
\r
4835 * @cfg {Boolean} layoutOnCardChange
\r
4836 * True to force a layout of the active item when the active card is changed. Defaults to false.
\r
4838 layoutOnCardChange : false,
\r
4841 * @cfg {Boolean} renderHidden @hide
\r
4844 renderHidden : true,
\r
4846 constructor: function(config){
\r
4847 Ext.layout.CardLayout.superclass.constructor.call(this, config);
\r
4848 this.forceLayout = (this.deferredRender === false);
\r
4852 * Sets the active (visible) item in the layout.
\r
4853 * @param {String/Number} item The string component id or numeric index of the item to activate
\r
4855 setActiveItem : function(item){
\r
4856 item = this.container.getComponent(item);
\r
4857 if(this.activeItem != item){
\r
4858 if(this.activeItem){
\r
4859 this.activeItem.hide();
\r
4861 var layout = item.doLayout && (this.layoutOnCardChange || !item.rendered);
\r
4862 this.activeItem = item;
\r
4872 renderAll : function(ct, target){
\r
4873 if(this.deferredRender){
\r
4874 this.renderItem(this.activeItem, undefined, target);
\r
4876 Ext.layout.CardLayout.superclass.renderAll.call(this, ct, target);
\r
4880 Ext.Container.LAYOUTS['card'] = Ext.layout.CardLayout;/**
\r
4881 * @class Ext.layout.AnchorLayout
\r
4882 * @extends Ext.layout.ContainerLayout
\r
4883 * <p>This is a layout that enables anchoring of contained elements relative to the container's dimensions.
\r
4884 * If the container is resized, all anchored items are automatically rerendered according to their
\r
4885 * <b><tt>{@link #anchor}</tt></b> rules.</p>
\r
4886 * <p>This class is intended to be extended or created via the layout:'anchor' {@link Ext.Container#layout}
\r
4887 * config, and should generally not need to be created directly via the new keyword.</p>
\r
4888 * <p>AnchorLayout does not have any direct config options (other than inherited ones). By default,
\r
4889 * AnchorLayout will calculate anchor measurements based on the size of the container itself. However, the
\r
4890 * container using the AnchorLayout can supply an anchoring-specific config property of <b>anchorSize</b>.
\r
4891 * If anchorSize is specifed, the layout will use it as a virtual container for the purposes of calculating
\r
4892 * anchor measurements based on it instead, allowing the container to be sized independently of the anchoring
\r
4893 * logic if necessary. For example:</p>
\r
4895 var viewport = new Ext.Viewport({
\r
4897 anchorSize: {width:800, height:600},
\r
4902 anchor:'right 20%'
\r
4917 Ext.layout.AnchorLayout = Ext.extend(Ext.layout.ContainerLayout, {
\r
4919 * @cfg {String} anchor
\r
4920 * <p>This configuation option is to be applied to <b>child <tt>items</tt></b> of a container managed by
\r
4921 * this layout (ie. configured with <tt>layout:'anchor'</tt>).</p><br/>
\r
4923 * <p>This value is what tells the layout how an item should be anchored to the container. <tt>items</tt>
\r
4924 * added to an AnchorLayout accept an anchoring-specific config property of <b>anchor</b> which is a string
\r
4925 * containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%').
\r
4926 * The following types of anchor values are supported:<div class="mdetail-params"><ul>
\r
4928 * <li><b>Percentage</b> : Any value between 1 and 100, expressed as a percentage.<div class="sub-desc">
\r
4929 * The first anchor is the percentage width that the item should take up within the container, and the
\r
4930 * second is the percentage height. For example:<pre><code>
\r
4931 // two values specified
\r
4932 anchor: '100% 50%' // render item complete width of the container and
\r
4933 // 1/2 height of the container
\r
4934 // one value specified
\r
4935 anchor: '100%' // the width value; the height will default to auto
\r
4936 * </code></pre></div></li>
\r
4938 * <li><b>Offsets</b> : Any positive or negative integer value.<div class="sub-desc">
\r
4939 * This is a raw adjustment where the first anchor is the offset from the right edge of the container,
\r
4940 * and the second is the offset from the bottom edge. For example:<pre><code>
\r
4941 // two values specified
\r
4942 anchor: '-50 -100' // render item the complete width of the container
\r
4943 // minus 50 pixels and
\r
4944 // the complete height minus 100 pixels.
\r
4945 // one value specified
\r
4946 anchor: '-50' // anchor value is assumed to be the right offset value
\r
4947 // bottom offset will default to 0
\r
4948 * </code></pre></div></li>
\r
4950 * <li><b>Sides</b> : Valid values are <tt>'right'</tt> (or <tt>'r'</tt>) and <tt>'bottom'</tt>
\r
4951 * (or <tt>'b'</tt>).<div class="sub-desc">
\r
4952 * Either the container must have a fixed size or an anchorSize config value defined at render time in
\r
4953 * order for these to have any effect.</div></li>
\r
4955 * <li><b>Mixed</b> : <div class="sub-desc">
\r
4956 * Anchor values can also be mixed as needed. For example, to render the width offset from the container
\r
4957 * right edge by 50 pixels and 75% of the container's height use:
\r
4959 anchor: '-50 75%'
\r
4960 * </code></pre></div></li>
\r
4967 monitorResize:true,
\r
4970 getAnchorViewSize : function(ct, target){
\r
4971 return target.dom == document.body ?
\r
4972 target.getViewSize() : target.getStyleSize();
\r
4976 onLayout : function(ct, target){
\r
4977 Ext.layout.AnchorLayout.superclass.onLayout.call(this, ct, target);
\r
4979 var size = this.getAnchorViewSize(ct, target);
\r
4981 var w = size.width, h = size.height;
\r
4983 if(w < 20 && h < 20){
\r
4987 // find the container anchoring size
\r
4989 if(ct.anchorSize){
\r
4990 if(typeof ct.anchorSize == 'number'){
\r
4991 aw = ct.anchorSize;
\r
4993 aw = ct.anchorSize.width;
\r
4994 ah = ct.anchorSize.height;
\r
4997 aw = ct.initialConfig.width;
\r
4998 ah = ct.initialConfig.height;
\r
5001 var cs = ct.items.items, len = cs.length, i, c, a, cw, ch;
\r
5002 for(i = 0; i < len; i++){
\r
5006 if(!a){ // cache all anchor values
\r
5007 var vs = c.anchor.split(' ');
\r
5008 c.anchorSpec = a = {
\r
5009 right: this.parseAnchor(vs[0], c.initialConfig.width, aw),
\r
5010 bottom: this.parseAnchor(vs[1], c.initialConfig.height, ah)
\r
5013 cw = a.right ? this.adjustWidthAnchor(a.right(w), c) : undefined;
\r
5014 ch = a.bottom ? this.adjustHeightAnchor(a.bottom(h), c) : undefined;
\r
5017 c.setSize(cw || undefined, ch || undefined);
\r
5024 parseAnchor : function(a, start, cstart){
\r
5025 if(a && a != 'none'){
\r
5027 if(/^(r|right|b|bottom)$/i.test(a)){ // standard anchor
\r
5028 var diff = cstart - start;
\r
5029 return function(v){
\r
5035 }else if(a.indexOf('%') != -1){
\r
5036 var ratio = parseFloat(a.replace('%', ''))*.01; // percentage
\r
5037 return function(v){
\r
5040 return Math.floor(v*ratio);
\r
5044 a = parseInt(a, 10);
\r
5045 if(!isNaN(a)){ // simple offset adjustment
\r
5046 return function(v){
\r
5059 adjustWidthAnchor : function(value, comp){
\r
5064 adjustHeightAnchor : function(value, comp){
\r
5069 * @property activeItem
\r
5073 Ext.Container.LAYOUTS['anchor'] = Ext.layout.AnchorLayout;/**
\r
5074 * @class Ext.layout.ColumnLayout
\r
5075 * @extends Ext.layout.ContainerLayout
\r
5076 * <p>This is the layout style of choice for creating structural layouts in a multi-column format where the width of
\r
5077 * each column can be specified as a percentage or fixed width, but the height is allowed to vary based on the content.
\r
5078 * This class is intended to be extended or created via the layout:'column' {@link Ext.Container#layout} config,
\r
5079 * and should generally not need to be created directly via the new keyword.</p>
\r
5080 * <p>ColumnLayout does not have any direct config options (other than inherited ones), but it does support a
\r
5081 * specific config property of <b><tt>columnWidth</tt></b> that can be included in the config of any panel added to it. The
\r
5082 * layout will use the columnWidth (if present) or width of each panel during layout to determine how to size each panel.
\r
5083 * If width or columnWidth is not specified for a given panel, its width will default to the panel's width (or auto).</p>
\r
5084 * <p>The width property is always evaluated as pixels, and must be a number greater than or equal to 1.
\r
5085 * The columnWidth property is always evaluated as a percentage, and must be a decimal value greater than 0 and
\r
5086 * less than 1 (e.g., .25).</p>
\r
5087 * <p>The basic rules for specifying column widths are pretty simple. The logic makes two passes through the
\r
5088 * set of contained panels. During the first layout pass, all panels that either have a fixed width or none
\r
5089 * specified (auto) are skipped, but their widths are subtracted from the overall container width. During the second
\r
5090 * pass, all panels with columnWidths are assigned pixel widths in proportion to their percentages based on
\r
5091 * the total <b>remaining</b> container width. In other words, percentage width panels are designed to fill the space
\r
5092 * left over by all the fixed-width and/or auto-width panels. Because of this, while you can specify any number of columns
\r
5093 * with different percentages, the columnWidths must always add up to 1 (or 100%) when added together, otherwise your
\r
5094 * layout may not render as expected. Example usage:</p>
\r
5096 // All columns are percentages -- they must add up to 1
\r
5097 var p = new Ext.Panel({
\r
5098 title: 'Column Layout - Percentage Only',
\r
5101 title: 'Column 1',
\r
5104 title: 'Column 2',
\r
5107 title: 'Column 3',
\r
5112 // Mix of width and columnWidth -- all columnWidth values must add up
\r
5113 // to 1. The first column will take up exactly 120px, and the last two
\r
5114 // columns will fill the remaining container width.
\r
5115 var p = new Ext.Panel({
\r
5116 title: 'Column Layout - Mixed',
\r
5119 title: 'Column 1',
\r
5122 title: 'Column 2',
\r
5125 title: 'Column 3',
\r
5131 Ext.layout.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, {
\r
5133 monitorResize:true,
\r
5135 extraCls: 'x-column',
\r
5140 isValidParent : function(c, target){
\r
5141 return (c.getPositionEl ? c.getPositionEl() : c.getEl()).dom.parentNode == this.innerCt.dom;
\r
5145 onLayout : function(ct, target){
\r
5146 var cs = ct.items.items, len = cs.length, c, i;
\r
5148 if(!this.innerCt){
\r
5149 target.addClass('x-column-layout-ct');
\r
5151 // the innerCt prevents wrapping and shuffling while
\r
5152 // the container is resizing
\r
5153 this.innerCt = target.createChild({cls:'x-column-inner'});
\r
5154 this.innerCt.createChild({cls:'x-clear'});
\r
5156 this.renderAll(ct, this.innerCt);
\r
5158 var size = Ext.isIE && target.dom != Ext.getBody().dom ? target.getStyleSize() : target.getViewSize();
\r
5160 if(size.width < 1 && size.height < 1){ // display none?
\r
5164 var w = size.width - target.getPadding('lr') - this.scrollOffset,
\r
5165 h = size.height - target.getPadding('tb'),
\r
5168 this.innerCt.setWidth(w);
\r
5170 // some columns can be percentages while others are fixed
\r
5171 // so we need to make 2 passes
\r
5173 for(i = 0; i < len; i++){
\r
5175 if(!c.columnWidth){
\r
5176 pw -= (c.getSize().width + c.getEl().getMargins('lr'));
\r
5180 pw = pw < 0 ? 0 : pw;
\r
5182 for(i = 0; i < len; i++){
\r
5184 if(c.columnWidth){
\r
5185 c.setSize(Math.floor(c.columnWidth*pw) - c.getEl().getMargins('lr'));
\r
5191 * @property activeItem
\r
5196 Ext.Container.LAYOUTS['column'] = Ext.layout.ColumnLayout;/**
5197 * @class Ext.layout.BorderLayout
5198 * @extends Ext.layout.ContainerLayout
5199 * <p>This is a multi-pane, application-oriented UI layout style that supports multiple
5200 * nested panels, automatic {@link Ext.layout.BorderLayout.Region#split split} bars between
5201 * {@link Ext.layout.BorderLayout.Region#BorderLayout.Region regions} and built-in
5202 * {@link Ext.layout.BorderLayout.Region#collapsible expanding and collapsing} of regions.</p>
5203 * <p>This class is intended to be extended or created via the <tt>layout:'border'</tt>
5204 * {@link Ext.Container#layout} config, and should generally not need to be created directly
5205 * via the new keyword.</p>
5206 * <p>BorderLayout does not have any direct config options (other than inherited ones).
5207 * All configuration options available for customizing the BorderLayout are at the
5208 * {@link Ext.layout.BorderLayout.Region} and {@link Ext.layout.BorderLayout.SplitRegion}
5210 * <p>Example usage:</p>
5212 var myBorderPanel = new Ext.Panel({
5213 {@link Ext.Component#renderTo renderTo}: document.body,
5214 {@link Ext.BoxComponent#width width}: 700,
5215 {@link Ext.BoxComponent#height height}: 500,
5216 {@link Ext.Panel#title title}: 'Border Layout',
5217 {@link Ext.Container#layout layout}: 'border',
5218 {@link Ext.Container#items items}: [{
5219 {@link Ext.Panel#title title}: 'South Region is resizable',
5220 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'south', // position for region
5221 {@link Ext.BoxComponent#height height}: 100,
5222 {@link Ext.layout.BorderLayout.Region#split split}: true, // enable resizing
5223 {@link Ext.SplitBar#minSize minSize}: 75, // defaults to {@link Ext.layout.BorderLayout.Region#minHeight 50}
5224 {@link Ext.SplitBar#maxSize maxSize}: 150,
5225 {@link Ext.layout.BorderLayout.Region#margins margins}: '0 5 5 5'
5227 // xtype: 'panel' implied by default
5228 {@link Ext.Panel#title title}: 'West Region is collapsible',
5229 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}:'west',
5230 {@link Ext.layout.BorderLayout.Region#margins margins}: '5 0 0 5',
5231 {@link Ext.BoxComponent#width width}: 200,
5232 {@link Ext.layout.BorderLayout.Region#collapsible collapsible}: true, // make collapsible
5233 {@link Ext.layout.BorderLayout.Region#cmargins cmargins}: '5 5 0 5', // adjust top margin when collapsed
5234 {@link Ext.Component#id id}: 'west-region-container',
5235 {@link Ext.Container#layout layout}: 'fit',
5236 {@link Ext.Panel#unstyled unstyled}: true
5238 {@link Ext.Panel#title title}: 'Center Region',
5239 {@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'center', // center region is required, no width/height specified
5240 {@link Ext.Component#xtype xtype}: 'container',
5241 {@link Ext.Container#layout layout}: 'fit',
5242 {@link Ext.layout.BorderLayout.Region#margins margins}: '5 5 0 0'
5246 * <p><b><u>Notes</u></b>:</p><div class="mdetail-params"><ul>
5247 * <li>Any container using the BorderLayout <b>must</b> have a child item with <tt>region:'center'</tt>.
5248 * The child item in the center region will always be resized to fill the remaining space not used by
5249 * the other regions in the layout.</li>
5250 * <li>Any child items with a region of <tt>west</tt> or <tt>east</tt> must have <tt>width</tt> defined
5251 * (an integer representing the number of pixels that the region should take up).</li>
5252 * <li>Any child items with a region of <tt>north</tt> or <tt>south</tt> must have <tt>height</tt> defined.</li>
5253 * <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
5254 * Components within a BorderLayout, have them wrapped by an additional Container which is directly
5255 * managed by the BorderLayout. If the region is to be collapsible, the Container used directly
5256 * by the BorderLayout manager should be a Panel. In the following example a Container (an Ext.Panel)
5257 * is added to the west region:
5258 * <div style="margin-left:16px"><pre><code>
5259 wrc = {@link Ext#getCmp Ext.getCmp}('west-region-container');
5260 wrc.{@link Ext.Panel#removeAll removeAll}();
5261 wrc.{@link Ext.Container#add add}({
5262 title: 'Added Panel',
5263 html: 'Some content'
5265 wrc.{@link Ext.Container#doLayout doLayout}();
5266 * </code></pre></div>
5268 * <li> To reference a {@link Ext.layout.BorderLayout.Region Region}:
5269 * <div style="margin-left:16px"><pre><code>
5270 wr = myBorderPanel.layout.west;
5271 * </code></pre></div>
5275 Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {
5282 onLayout : function(ct, target){
5285 target.addClass('x-border-layout-ct');
5286 var items = ct.items.items;
5288 for(var i = 0, len = items.length; i < len; i++) {
5294 c.collapsed = false;
5296 c.render(target, i);
5297 c.getDomPositionEl().addClass('x-border-panel');
5299 this[pos] = pos != 'center' && c.split ?
5300 new Ext.layout.BorderLayout.SplitRegion(this, c.initialConfig, pos) :
5301 new Ext.layout.BorderLayout.Region(this, c.initialConfig, pos);
5302 this[pos].render(target, c);
5304 this.rendered = true;
5307 var size = target.getViewSize();
5308 if(size.width < 20 || size.height < 20){ // display none?
5310 this.restoreCollapsed = collapsed;
5313 }else if(this.restoreCollapsed){
5314 collapsed = this.restoreCollapsed;
5315 delete this.restoreCollapsed;
5318 var w = size.width, h = size.height;
5319 var centerW = w, centerH = h, centerY = 0, centerX = 0;
5321 var n = this.north, s = this.south, west = this.west, e = this.east, c = this.center;
5322 if(!c && Ext.layout.BorderLayout.WARN !== false){
5323 throw 'No center region defined in BorderLayout ' + ct.id;
5326 if(n && n.isVisible()){
5327 var b = n.getSize();
5328 var m = n.getMargins();
5329 b.width = w - (m.left+m.right);
5332 centerY = b.height + b.y + m.bottom;
5336 if(s && s.isVisible()){
5337 var b = s.getSize();
5338 var m = s.getMargins();
5339 b.width = w - (m.left+m.right);
5341 var totalHeight = (b.height + m.top + m.bottom);
5342 b.y = h - totalHeight + m.top;
5343 centerH -= totalHeight;
5346 if(west && west.isVisible()){
5347 var b = west.getSize();
5348 var m = west.getMargins();
5349 b.height = centerH - (m.top+m.bottom);
5351 b.y = centerY + m.top;
5352 var totalWidth = (b.width + m.left + m.right);
5353 centerX += totalWidth;
5354 centerW -= totalWidth;
5355 west.applyLayout(b);
5357 if(e && e.isVisible()){
5358 var b = e.getSize();
5359 var m = e.getMargins();
5360 b.height = centerH - (m.top+m.bottom);
5361 var totalWidth = (b.width + m.left + m.right);
5362 b.x = w - totalWidth + m.left;
5363 b.y = centerY + m.top;
5364 centerW -= totalWidth;
5368 var m = c.getMargins();
5370 x: centerX + m.left,
5372 width: centerW - (m.left+m.right),
5373 height: centerH - (m.top+m.bottom)
5375 c.applyLayout(centerBox);
5378 for(var i = 0, len = collapsed.length; i < len; i++){
5379 collapsed[i].collapse(false);
5382 if(Ext.isIE && Ext.isStrict){ // workaround IE strict repainting issue
5387 destroy: function() {
5388 var r = ['north', 'south', 'east', 'west'];
5389 for (var i = 0; i < r.length; i++) {
5390 var region = this[r[i]];
5394 }else if (region.split){
5395 region.split.destroy(true);
5399 Ext.layout.BorderLayout.superclass.destroy.call(this);
5403 * @property activeItem
5409 * @class Ext.layout.BorderLayout.Region
5410 * <p>This is a region of a {@link Ext.layout.BorderLayout BorderLayout} that acts as a subcontainer
5411 * within the layout. Each region has its own {@link Ext.layout.ContainerLayout layout} that is
5412 * independent of other regions and the containing BorderLayout, and can be any of the
5413 * {@link Ext.layout.ContainerLayout valid Ext layout types}.</p>
5414 * <p>Region size is managed automatically and cannot be changed by the user -- for
5415 * {@link #split resizable regions}, see {@link Ext.layout.BorderLayout.SplitRegion}.</p>
5417 * Create a new Region.
5418 * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region.
5419 * @param {Object} config The configuration options
5420 * @param {String} position The region position. Valid values are: <tt>north</tt>, <tt>south</tt>,
5421 * <tt>east</tt>, <tt>west</tt> and <tt>center</tt>. Every {@link Ext.layout.BorderLayout BorderLayout}
5422 * <b>must have a center region</b> for the primary content -- all other regions are optional.
5424 Ext.layout.BorderLayout.Region = function(layout, config, pos){
5425 Ext.apply(this, config);
5426 this.layout = layout;
5427 this.position = pos;
5429 if(typeof this.margins == 'string'){
5430 this.margins = this.layout.parseMargins(this.margins);
5432 this.margins = Ext.applyIf(this.margins || {}, this.defaultMargins);
5433 if(this.collapsible){
5434 if(typeof this.cmargins == 'string'){
5435 this.cmargins = this.layout.parseMargins(this.cmargins);
5437 if(this.collapseMode == 'mini' && !this.cmargins){
5438 this.cmargins = {left:0,top:0,right:0,bottom:0};
5440 this.cmargins = Ext.applyIf(this.cmargins || {},
5441 pos == 'north' || pos == 'south' ? this.defaultNSCMargins : this.defaultEWCMargins);
5446 Ext.layout.BorderLayout.Region.prototype = {
5448 * @cfg {Boolean} animFloat
5449 * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated
5450 * panel that will close again once the user mouses out of that panel (or clicks out if
5451 * <tt>{@link #autoHide} = false</tt>). Setting <tt>{@link #animFloat} = false</tt> will
5452 * prevent the open and close of these floated panels from being animated (defaults to <tt>true</tt>).
5455 * @cfg {Boolean} autoHide
5456 * When a collapsed region's bar is clicked, the region's panel will be displayed as a floated
5457 * panel. If <tt>autoHide = true</tt>, the panel will automatically hide after the user mouses
5458 * out of the panel. If <tt>autoHide = false</tt>, the panel will continue to display until the
5459 * user clicks outside of the panel (defaults to <tt>true</tt>).
5462 * @cfg {String} collapseMode
5463 * <tt>collapseMode</tt> supports two configuration values:<div class="mdetail-params"><ul>
5464 * <li><b><tt>undefined</tt></b> (default)<div class="sub-desc">By default, {@link #collapsible}
5465 * regions are collapsed by clicking the expand/collapse tool button that renders into the region's
5466 * title bar.</div></li>
5467 * <li><b><tt>'mini'</tt></b><div class="sub-desc">Optionally, when <tt>collapseMode</tt> is set to
5468 * <tt>'mini'</tt> the region's split bar will also display a small collapse button in the center of
5469 * the bar. In <tt>'mini'</tt> mode the region will collapse to a thinner bar than in normal mode.
5472 * <p><b>Note</b>: if a collapsible region does not have a title bar, then set <tt>collapseMode =
5473 * 'mini'</tt> and <tt>{@link #split} = true</tt> in order for the region to be {@link #collapsible}
5474 * by the user as the expand/collapse tool button (that would go in the title bar) will not be rendered.</p>
5475 * <p>See also <tt>{@link #cmargins}</tt>.</p>
5478 * @cfg {Object} margins
5479 * An object containing margins to apply to the region when in the expanded state in the
5480 * format:<pre><code>
5483 right: (right margin),
5484 bottom: (bottom margin),
5487 * <p>May also be a string containing space-separated, numeric margin values. The order of the
5488 * sides associated with each value matches the way CSS processes margin values:</p>
5489 * <p><div class="mdetail-params"><ul>
5490 * <li>If there is only one value, it applies to all sides.</li>
5491 * <li>If there are two values, the top and bottom borders are set to the first value and the
5492 * right and left are set to the second.</li>
5493 * <li>If there are three values, the top is set to the first value, the left and right are set
5494 * to the second, and the bottom is set to the third.</li>
5495 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
5497 * <p>Defaults to:</p><pre><code>
5498 * {top:0, right:0, bottom:0, left:0}
5502 * @cfg {Object} cmargins
5503 * An object containing margins to apply to the region when in the collapsed state in the
5504 * format:<pre><code>
5507 right: (right margin),
5508 bottom: (bottom margin),
5511 * <p>May also be a string containing space-separated, numeric margin values. The order of the
5512 * sides associated with each value matches the way CSS processes margin values.</p>
5514 * <li>If there is only one value, it applies to all sides.</li>
5515 * <li>If there are two values, the top and bottom borders are set to the first value and the
5516 * right and left are set to the second.</li>
5517 * <li>If there are three values, the top is set to the first value, the left and right are set
5518 * to the second, and the bottom is set to the third.</li>
5519 * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li>
5523 * @cfg {Boolean} collapsible
5524 * <p><tt>true</tt> to allow the user to collapse this region (defaults to <tt>false</tt>). If
5525 * <tt>true</tt>, an expand/collapse tool button will automatically be rendered into the title
5526 * bar of the region, otherwise the button will not be shown.</p>
5527 * <p><b>Note</b>: that a title bar is required to display the collapse/expand toggle button -- if
5528 * no <tt>title</tt> is specified for the region's panel, the region will only be collapsible if
5529 * <tt>{@link #collapseMode} = 'mini'</tt> and <tt>{@link #split} = true</tt>.
5531 collapsible : false,
5533 * @cfg {Boolean} split
5534 * <p><tt>true</tt> to create a {@link Ext.layout.BorderLayout.SplitRegion SplitRegion} and
5535 * display a 5px wide {@link Ext.SplitBar} between this region and its neighbor, allowing the user to
5536 * resize the regions dynamically. Defaults to <tt>false</tt> creating a
5537 * {@link Ext.layout.BorderLayout.Region Region}.</p><br>
5538 * <p><b>Notes</b>:</p><div class="mdetail-params"><ul>
5539 * <li>this configuration option is ignored if <tt>region='center'</tt></li>
5540 * <li>when <tt>split == true</tt>, it is common to specify a
5541 * <tt>{@link Ext.SplitBar#minSize minSize}</tt> and <tt>{@link Ext.SplitBar#maxSize maxSize}</tt>
5542 * for the {@link Ext.BoxComponent BoxComponent} representing the region. These are not native
5543 * configs of {@link Ext.BoxComponent BoxComponent}, and are used only by this class.</li>
5544 * <li>if <tt>{@link #collapseMode} = 'mini'</tt> requires <tt>split = true</tt> to reserve space
5545 * for the collapse tool</tt></li>
5550 * @cfg {Boolean} floatable
5551 * <tt>true</tt> to allow clicking a collapsed region's bar to display the region's panel floated
5552 * above the layout, <tt>false</tt> to force the user to fully expand a collapsed region by
5553 * clicking the expand button to see it again (defaults to <tt>true</tt>).
5557 * @cfg {Number} minWidth
5558 * <p>The minimum allowable width in pixels for this region (defaults to <tt>50</tt>).
5559 * <tt>maxWidth</tt> may also be specified.</p><br>
5560 * <p><b>Note</b>: setting the <tt>{@link Ext.SplitBar#minSize minSize}</tt> /
5561 * <tt>{@link Ext.SplitBar#maxSize maxSize}</tt> supersedes any specified
5562 * <tt>minWidth</tt> / <tt>maxWidth</tt>.</p>
5566 * @cfg {Number} minHeight
5567 * The minimum allowable height in pixels for this region (defaults to <tt>50</tt>)
5568 * <tt>maxHeight</tt> may also be specified.</p><br>
5569 * <p><b>Note</b>: setting the <tt>{@link Ext.SplitBar#minSize minSize}</tt> /
5570 * <tt>{@link Ext.SplitBar#maxSize maxSize}</tt> supersedes any specified
5571 * <tt>minHeight</tt> / <tt>maxHeight</tt>.</p>
5576 defaultMargins : {left:0,top:0,right:0,bottom:0},
5578 defaultNSCMargins : {left:5,top:5,right:5,bottom:5},
5580 defaultEWCMargins : {left:5,top:0,right:5,bottom:0},
5581 floatingZIndex: 100,
5584 * True if this region is collapsed. Read-only.
5588 isCollapsed : false,
5591 * This region's panel. Read-only.
5596 * This region's layout. Read-only.
5601 * This region's layout position (north, south, east, west or center). Read-only.
5603 * @property position
5607 render : function(ct, p){
5609 p.el.enableDisplayMode();
5613 var gs = p.getState, ps = this.position;
5614 p.getState = function(){
5615 return Ext.apply(gs.call(p) || {}, this.state);
5616 }.createDelegate(this);
5619 p.allowQueuedExpand = false;
5621 beforecollapse: this.beforeCollapse,
5622 collapse: this.onCollapse,
5623 beforeexpand: this.beforeExpand,
5624 expand: this.onExpand,
5629 if(this.collapsible || this.floatable){
5630 p.collapseEl = 'el';
5631 p.slideAnchor = this.getSlideAnchor();
5633 if(p.tools && p.tools.toggle){
5634 p.tools.toggle.addClass('x-tool-collapse-'+ps);
5635 p.tools.toggle.addClassOnOver('x-tool-collapse-'+ps+'-over');
5641 getCollapsedEl : function(){
5642 if(!this.collapsedEl){
5643 if(!this.toolTemplate){
5644 var tt = new Ext.Template(
5645 '<div class="x-tool x-tool-{id}"> </div>'
5647 tt.disableFormats = true;
5649 Ext.layout.BorderLayout.Region.prototype.toolTemplate = tt;
5651 this.collapsedEl = this.targetEl.createChild({
5652 cls: "x-layout-collapsed x-layout-collapsed-"+this.position,
5653 id: this.panel.id + '-xcollapsed'
5655 this.collapsedEl.enableDisplayMode('block');
5657 if(this.collapseMode == 'mini'){
5658 this.collapsedEl.addClass('x-layout-cmini-'+this.position);
5659 this.miniCollapsedEl = this.collapsedEl.createChild({
5660 cls: "x-layout-mini x-layout-mini-"+this.position, html: " "
5662 this.miniCollapsedEl.addClassOnOver('x-layout-mini-over');
5663 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
5664 this.collapsedEl.on('click', this.onExpandClick, this, {stopEvent:true});
5666 if(this.collapsible !== false && !this.hideCollapseTool) {
5667 var t = this.toolTemplate.append(
5668 this.collapsedEl.dom,
5669 {id:'expand-'+this.position}, true);
5670 t.addClassOnOver('x-tool-expand-'+this.position+'-over');
5671 t.on('click', this.onExpandClick, this, {stopEvent:true});
5673 if(this.floatable !== false || this.titleCollapse){
5674 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
5675 this.collapsedEl.on("click", this[this.floatable ? 'collapseClick' : 'onExpandClick'], this);
5679 return this.collapsedEl;
5683 onExpandClick : function(e){
5685 this.afterSlideIn();
5686 this.panel.expand(false);
5688 this.panel.expand();
5693 onCollapseClick : function(e){
5694 this.panel.collapse();
5698 beforeCollapse : function(p, animate){
5699 this.lastAnim = animate;
5701 this.splitEl.hide();
5703 this.getCollapsedEl().show();
5704 this.panel.el.setStyle('z-index', 100);
5705 this.isCollapsed = true;
5706 this.layout.layout();
5710 onCollapse : function(animate){
5711 this.panel.el.setStyle('z-index', 1);
5712 if(this.lastAnim === false || this.panel.animCollapse === false){
5713 this.getCollapsedEl().dom.style.visibility = 'visible';
5715 this.getCollapsedEl().slideIn(this.panel.slideAnchor, {duration:.2});
5717 this.state.collapsed = true;
5718 this.panel.saveState();
5722 beforeExpand : function(animate){
5723 var c = this.getCollapsedEl();
5725 if(this.position == 'east' || this.position == 'west'){
5726 this.panel.setSize(undefined, c.getHeight());
5728 this.panel.setSize(c.getWidth(), undefined);
5731 c.dom.style.visibility = 'hidden';
5732 this.panel.el.setStyle('z-index', this.floatingZIndex);
5736 onExpand : function(){
5737 this.isCollapsed = false;
5739 this.splitEl.show();
5741 this.layout.layout();
5742 this.panel.el.setStyle('z-index', 1);
5743 this.state.collapsed = false;
5744 this.panel.saveState();
5748 collapseClick : function(e){
5750 e.stopPropagation();
5753 e.stopPropagation();
5759 onHide : function(){
5760 if(this.isCollapsed){
5761 this.getCollapsedEl().hide();
5762 }else if(this.splitEl){
5763 this.splitEl.hide();
5768 onShow : function(){
5769 if(this.isCollapsed){
5770 this.getCollapsedEl().show();
5771 }else if(this.splitEl){
5772 this.splitEl.show();
5777 * True if this region is currently visible, else false.
5780 isVisible : function(){
5781 return !this.panel.hidden;
5785 * Returns the current margins for this region. If the region is collapsed, the
5786 * {@link #cmargins} (collapsed margins) value will be returned, otherwise the
5787 * {@link #margins} value will be returned.
5788 * @return {Object} An object containing the element's margins: <tt>{left: (left
5789 * margin), top: (top margin), right: (right margin), bottom: (bottom margin)}</tt>
5791 getMargins : function(){
5792 return this.isCollapsed && this.cmargins ? this.cmargins : this.margins;
5796 * Returns the current size of this region. If the region is collapsed, the size of the
5797 * collapsedEl will be returned, otherwise the size of the region's panel will be returned.
5798 * @return {Object} An object containing the element's size: <tt>{width: (element width),
5799 * height: (element height)}</tt>
5801 getSize : function(){
5802 return this.isCollapsed ? this.getCollapsedEl().getSize() : this.panel.getSize();
5806 * Sets the specified panel as the container element for this region.
5807 * @param {Ext.Panel} panel The new panel
5809 setPanel : function(panel){
5814 * Returns the minimum allowable width for this region.
5815 * @return {Number} The minimum width
5817 getMinWidth: function(){
5818 return this.minWidth;
5822 * Returns the minimum allowable height for this region.
5823 * @return {Number} The minimum height
5825 getMinHeight: function(){
5826 return this.minHeight;
5830 applyLayoutCollapsed : function(box){
5831 var ce = this.getCollapsedEl();
5832 ce.setLeftTop(box.x, box.y);
5833 ce.setSize(box.width, box.height);
5837 applyLayout : function(box){
5838 if(this.isCollapsed){
5839 this.applyLayoutCollapsed(box);
5841 this.panel.setPosition(box.x, box.y);
5842 this.panel.setSize(box.width, box.height);
5847 beforeSlide: function(){
5848 this.panel.beforeEffect();
5852 afterSlide : function(){
5853 this.panel.afterEffect();
5857 initAutoHide : function(){
5858 if(this.autoHide !== false){
5859 if(!this.autoHideHd){
5860 var st = new Ext.util.DelayedTask(this.slideIn, this);
5862 "mouseout": function(e){
5863 if(!e.within(this.el, true)){
5867 "mouseover" : function(e){
5873 this.el.on(this.autoHideHd);
5878 clearAutoHide : function(){
5879 if(this.autoHide !== false){
5880 this.el.un("mouseout", this.autoHideHd.mouseout);
5881 this.el.un("mouseover", this.autoHideHd.mouseover);
5886 clearMonitor : function(){
5887 Ext.getDoc().un("click", this.slideInIf, this);
5891 * If this Region is {@link #floatable}, this method slides this Region into full visibility <i>over the top
5892 * of the center Region</i> where it floats until either {@link #slideIn} is called, or other regions of the layout
5893 * are clicked, or the mouse exits the Region.
5895 slideOut : function(){
5896 if(this.isSlid || this.el.hasActiveFx()){
5900 var ts = this.panel.tools;
5901 if(ts && ts.toggle){
5905 if(this.position == 'east' || this.position == 'west'){
5906 this.panel.setSize(undefined, this.collapsedEl.getHeight());
5908 this.panel.setSize(this.collapsedEl.getWidth(), undefined);
5910 this.restoreLT = [this.el.dom.style.left, this.el.dom.style.top];
5911 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
5912 this.el.setStyle("z-index", this.floatingZIndex+2);
5913 this.panel.el.replaceClass('x-panel-collapsed', 'x-panel-floating');
5914 if(this.animFloat !== false){
5916 this.el.slideIn(this.getSlideAnchor(), {
5917 callback: function(){
5919 this.initAutoHide();
5920 Ext.getDoc().on("click", this.slideInIf, this);
5926 this.initAutoHide();
5927 Ext.getDoc().on("click", this.slideInIf, this);
5932 afterSlideIn : function(){
5933 this.clearAutoHide();
5934 this.isSlid = false;
5935 this.clearMonitor();
5936 this.el.setStyle("z-index", "");
5937 this.panel.el.replaceClass('x-panel-floating', 'x-panel-collapsed');
5938 this.el.dom.style.left = this.restoreLT[0];
5939 this.el.dom.style.top = this.restoreLT[1];
5941 var ts = this.panel.tools;
5942 if(ts && ts.toggle){
5948 * If this Region is {@link #floatable}, and this Region has been slid into floating visibility, then this method slides
5949 * this region back into its collapsed state.
5951 slideIn : function(cb){
5952 if(!this.isSlid || this.el.hasActiveFx()){
5956 this.isSlid = false;
5957 if(this.animFloat !== false){
5959 this.el.slideOut(this.getSlideAnchor(), {
5960 callback: function(){
5963 this.afterSlideIn();
5971 this.afterSlideIn();
5976 slideInIf : function(e){
5977 if(!e.within(this.el)){
6007 getAnchor : function(){
6008 return this.anchors[this.position];
6012 getCollapseAnchor : function(){
6013 return this.canchors[this.position];
6017 getSlideAnchor : function(){
6018 return this.sanchors[this.position];
6022 getAlignAdj : function(){
6023 var cm = this.cmargins;
6024 switch(this.position){
6041 getExpandAdj : function(){
6042 var c = this.collapsedEl, cm = this.cmargins;
6043 switch(this.position){
6045 return [-(cm.right+c.getWidth()+cm.left), 0];
6048 return [cm.right+c.getWidth()+cm.left, 0];
6051 return [0, -(cm.top+cm.bottom+c.getHeight())];
6054 return [0, cm.top+cm.bottom+c.getHeight()];
6061 * @class Ext.layout.BorderLayout.SplitRegion
6062 * @extends Ext.layout.BorderLayout.Region
6063 * <p>This is a specialized type of {@link Ext.layout.BorderLayout.Region BorderLayout region} that
6064 * has a built-in {@link Ext.SplitBar} for user resizing of regions. The movement of the split bar
6065 * is configurable to move either {@link #tickSize smooth or incrementally}.</p>
6067 * Create a new SplitRegion.
6068 * @param {Layout} layout The {@link Ext.layout.BorderLayout BorderLayout} instance that is managing this Region.
6069 * @param {Object} config The configuration options
6070 * @param {String} position The region position. Valid values are: north, south, east, west and center. Every
6071 * BorderLayout must have a center region for the primary content -- all other regions are optional.
6073 Ext.layout.BorderLayout.SplitRegion = function(layout, config, pos){
6074 Ext.layout.BorderLayout.SplitRegion.superclass.constructor.call(this, layout, config, pos);
6076 this.applyLayout = this.applyFns[pos];
6079 Ext.extend(Ext.layout.BorderLayout.SplitRegion, Ext.layout.BorderLayout.Region, {
6081 * @cfg {Number} tickSize
6082 * The increment, in pixels by which to move this Region's {@link Ext.SplitBar SplitBar}.
6083 * By default, the {@link Ext.SplitBar SplitBar} moves smoothly.
6086 * @cfg {String} splitTip
6087 * The tooltip to display when the user hovers over a
6088 * {@link Ext.layout.BorderLayout.Region#collapsible non-collapsible} region's split bar
6089 * (defaults to <tt>"Drag to resize."</tt>). Only applies if
6090 * <tt>{@link #useSplitTips} = true</tt>.
6092 splitTip : "Drag to resize.",
6094 * @cfg {String} collapsibleSplitTip
6095 * The tooltip to display when the user hovers over a
6096 * {@link Ext.layout.BorderLayout.Region#collapsible collapsible} region's split bar
6097 * (defaults to "Drag to resize. Double click to hide."). Only applies if
6098 * <tt>{@link #useSplitTips} = true</tt>.
6100 collapsibleSplitTip : "Drag to resize. Double click to hide.",
6102 * @cfg {Boolean} useSplitTips
6103 * <tt>true</tt> to display a tooltip when the user hovers over a region's split bar
6104 * (defaults to <tt>false</tt>). The tooltip text will be the value of either
6105 * <tt>{@link #splitTip}</tt> or <tt>{@link #collapsibleSplitTip}</tt> as appropriate.
6107 useSplitTips : false,
6112 orientation: Ext.SplitBar.VERTICAL,
6113 placement: Ext.SplitBar.TOP,
6114 maxFn : 'getVMaxSize',
6115 minProp: 'minHeight',
6116 maxProp: 'maxHeight'
6119 orientation: Ext.SplitBar.VERTICAL,
6120 placement: Ext.SplitBar.BOTTOM,
6121 maxFn : 'getVMaxSize',
6122 minProp: 'minHeight',
6123 maxProp: 'maxHeight'
6126 orientation: Ext.SplitBar.HORIZONTAL,
6127 placement: Ext.SplitBar.RIGHT,
6128 maxFn : 'getHMaxSize',
6129 minProp: 'minWidth',
6133 orientation: Ext.SplitBar.HORIZONTAL,
6134 placement: Ext.SplitBar.LEFT,
6135 maxFn : 'getHMaxSize',
6136 minProp: 'minWidth',
6143 west : function(box){
6144 if(this.isCollapsed){
6145 return this.applyLayoutCollapsed(box);
6147 var sd = this.splitEl.dom, s = sd.style;
6148 this.panel.setPosition(box.x, box.y);
6149 var sw = sd.offsetWidth;
6150 s.left = (box.x+box.width-sw)+'px';
6151 s.top = (box.y)+'px';
6152 s.height = Math.max(0, box.height)+'px';
6153 this.panel.setSize(box.width-sw, box.height);
6155 east : function(box){
6156 if(this.isCollapsed){
6157 return this.applyLayoutCollapsed(box);
6159 var sd = this.splitEl.dom, s = sd.style;
6160 var sw = sd.offsetWidth;
6161 this.panel.setPosition(box.x+sw, box.y);
6162 s.left = (box.x)+'px';
6163 s.top = (box.y)+'px';
6164 s.height = Math.max(0, box.height)+'px';
6165 this.panel.setSize(box.width-sw, box.height);
6167 north : function(box){
6168 if(this.isCollapsed){
6169 return this.applyLayoutCollapsed(box);
6171 var sd = this.splitEl.dom, s = sd.style;
6172 var sh = sd.offsetHeight;
6173 this.panel.setPosition(box.x, box.y);
6174 s.left = (box.x)+'px';
6175 s.top = (box.y+box.height-sh)+'px';
6176 s.width = Math.max(0, box.width)+'px';
6177 this.panel.setSize(box.width, box.height-sh);
6179 south : function(box){
6180 if(this.isCollapsed){
6181 return this.applyLayoutCollapsed(box);
6183 var sd = this.splitEl.dom, s = sd.style;
6184 var sh = sd.offsetHeight;
6185 this.panel.setPosition(box.x, box.y+sh);
6186 s.left = (box.x)+'px';
6187 s.top = (box.y)+'px';
6188 s.width = Math.max(0, box.width)+'px';
6189 this.panel.setSize(box.width, box.height-sh);
6194 render : function(ct, p){
6195 Ext.layout.BorderLayout.SplitRegion.superclass.render.call(this, ct, p);
6197 var ps = this.position;
6199 this.splitEl = ct.createChild({
6200 cls: "x-layout-split x-layout-split-"+ps, html: " ",
6201 id: this.panel.id + '-xsplit'
6204 if(this.collapseMode == 'mini'){
6205 this.miniSplitEl = this.splitEl.createChild({
6206 cls: "x-layout-mini x-layout-mini-"+ps, html: " "
6208 this.miniSplitEl.addClassOnOver('x-layout-mini-over');
6209 this.miniSplitEl.on('click', this.onCollapseClick, this, {stopEvent:true});
6212 var s = this.splitSettings[ps];
6214 this.split = new Ext.SplitBar(this.splitEl.dom, p.el, s.orientation);
6215 this.split.tickSize = this.tickSize;
6216 this.split.placement = s.placement;
6217 this.split.getMaximumSize = this[s.maxFn].createDelegate(this);
6218 this.split.minSize = this.minSize || this[s.minProp];
6219 this.split.on("beforeapply", this.onSplitMove, this);
6220 this.split.useShim = this.useShim === true;
6221 this.maxSize = this.maxSize || this[s.maxProp];
6224 this.splitEl.hide();
6227 if(this.useSplitTips){
6228 this.splitEl.dom.title = this.collapsible ? this.collapsibleSplitTip : this.splitTip;
6230 if(this.collapsible){
6231 this.splitEl.on("dblclick", this.onCollapseClick, this);
6235 //docs inherit from superclass
6236 getSize : function(){
6237 if(this.isCollapsed){
6238 return this.collapsedEl.getSize();
6240 var s = this.panel.getSize();
6241 if(this.position == 'north' || this.position == 'south'){
6242 s.height += this.splitEl.dom.offsetHeight;
6244 s.width += this.splitEl.dom.offsetWidth;
6250 getHMaxSize : function(){
6251 var cmax = this.maxSize || 10000;
6252 var center = this.layout.center;
6253 return Math.min(cmax, (this.el.getWidth()+center.el.getWidth())-center.getMinWidth());
6257 getVMaxSize : function(){
6258 var cmax = this.maxSize || 10000;
6259 var center = this.layout.center;
6260 return Math.min(cmax, (this.el.getHeight()+center.el.getHeight())-center.getMinHeight());
6264 onSplitMove : function(split, newSize){
6265 var s = this.panel.getSize();
6266 this.lastSplitSize = newSize;
6267 if(this.position == 'north' || this.position == 'south'){
6268 this.panel.setSize(s.width, newSize);
6269 this.state.height = newSize;
6271 this.panel.setSize(newSize, s.height);
6272 this.state.width = newSize;
6274 this.layout.layout();
6275 this.panel.saveState();
6280 * Returns a reference to the split bar in use by this region.
6281 * @return {Ext.SplitBar} The split bar
6283 getSplitBar : function(){
6288 destroy : function() {
6297 Ext.Container.LAYOUTS['border'] = Ext.layout.BorderLayout;/**
6298 * @class Ext.layout.FormLayout
6299 * @extends Ext.layout.AnchorLayout
6300 * <p>This layout manager is specifically designed for rendering and managing child Components of
6301 * {@link Ext.form.FormPanel forms}. It is responsible for rendering the labels of
6302 * {@link Ext.form.Field Field}s.</p>
6304 * <p>This layout manager is used when a Container is configured with the <tt>layout:'form'</tt>
6305 * {@link Ext.Container#layout layout} config option, and should generally not need to be created directly
6306 * via the new keyword. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
6308 * <p>In an application, it will usually be preferrable to use a {@link Ext.form.FormPanel FormPanel}
6309 * (which is configured with FormLayout as its layout class by default) since it also provides built-in
6310 * functionality for {@link Ext.form.BasicForm#doAction loading, validating and submitting} the form.</p>
6312 * <p>A {@link Ext.Container Container} <i>using</i> the FormLayout layout manager (e.g.
6313 * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>) can also accept the following
6314 * layout-specific config properties:<div class="mdetail-params"><ul>
6315 * <li><b><tt>{@link Ext.form.FormPanel#hideLabels hideLabels}</tt></b></li>
6316 * <li><b><tt>{@link Ext.form.FormPanel#labelAlign labelAlign}</tt></b></li>
6317 * <li><b><tt>{@link Ext.form.FormPanel#labelPad labelPad}</tt></b></li>
6318 * <li><b><tt>{@link Ext.form.FormPanel#labelSeparator labelSeparator}</tt></b></li>
6319 * <li><b><tt>{@link Ext.form.FormPanel#labelWidth labelWidth}</tt></b></li>
6322 * <p>Any Component (including Fields) managed by FormLayout accepts the following as a config option:
6323 * <div class="mdetail-params"><ul>
6324 * <li><b><tt>{@link Ext.Component#anchor anchor}</tt></b></li>
6327 * <p>Any Component managed by FormLayout may be rendered as a form field (with an associated label) by
6328 * configuring it with a non-null <b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b>. Components configured
6329 * in this way may be configured with the following options which affect the way the FormLayout renders them:
6330 * <div class="mdetail-params"><ul>
6331 * <li><b><tt>{@link Ext.Component#clearCls clearCls}</tt></b></li>
6332 * <li><b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b></li>
6333 * <li><b><tt>{@link Ext.Component#hideLabel hideLabel}</tt></b></li>
6334 * <li><b><tt>{@link Ext.Component#itemCls itemCls}</tt></b></li>
6335 * <li><b><tt>{@link Ext.Component#labelSeparator labelSeparator}</tt></b></li>
6336 * <li><b><tt>{@link Ext.Component#labelStyle labelStyle}</tt></b></li>
6339 * <p>Example usage:</p>
6341 // Required if showing validation messages
6342 Ext.QuickTips.init();
6344 // While you can create a basic Panel with layout:'form', practically
6345 // you should usually use a FormPanel to also get its form functionality
6346 // since it already creates a FormLayout internally.
6347 var form = new Ext.form.FormPanel({
6348 title: 'Form Layout',
6349 bodyStyle: 'padding:15px',
6351 defaultType: 'textfield',
6353 // applied to each contained item
6358 fieldLabel: 'First Name',
6361 {@link Ext.Component#labelSeparator labelSeparator}: ':' // override labelSeparator layout config
6363 fieldLabel: 'Last Name',
6366 fieldLabel: 'Email',
6371 hideLabel: true, // override hideLabels layout config
6381 {@link #labelSeparator}: '~' // superseded by assignment below
6383 // config options applicable to container when layout='form':
6385 labelAlign: 'left', // or 'right' or 'top'
6386 {@link Ext.form.FormPanel#labelSeparator labelSeparator}: '>>', // takes precedence over layoutConfig value
6387 labelWidth: 65, // defaults to 100
6388 labelPad: 8 // defaults to 5, must specify labelWidth to be honored
6392 Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, {
6395 * @cfg {String} labelSeparator
6396 * See {@link Ext.form.FormPanel}.{@link Ext.form.FormPanel#labelSeparator labelSeparator}. Configuration
6397 * of this property at the <b>container</b> level takes precedence.
6399 labelSeparator : ':',
6402 * Read only. The CSS style specification string added to field labels in this layout if not
6403 * otherwise {@link Ext.Component#labelStyle specified by each contained field}.
6405 * @property labelStyle
6409 * @cfg {Boolean} trackLabels
6410 * True to show/hide the field label when the field is hidden. Defaults to <tt>false</tt>.
6415 onRemove: function(c){
6416 Ext.layout.FormLayout.superclass.onRemove.call(this, c);
6417 if(this.trackLabels && !this.isHide(c)){
6418 c.un('show', this.onFieldShow, this);
6419 c.un('hide', this.onFieldHide, this);
6421 // check for itemCt, since we may be removing a fieldset or something similar
6422 var el = c.getPositionEl(),
6423 ct = c.getItemCt && c.getItemCt();
6424 if(c.rendered && ct){
6427 Ext.destroyMembers(c, 'label', 'itemCt');
6429 Ext.destroyMembers(c, 'getItemCt', 'customItemCt');
6435 setContainer : function(ct){
6436 Ext.layout.FormLayout.superclass.setContainer.call(this, ct);
6438 ct.addClass('x-form-label-'+ct.labelAlign);
6443 labelStyle: 'display:none',
6444 elementStyle: 'padding-left:0;',
6448 this.labelSeparator = ct.labelSeparator || this.labelSeparator;
6449 ct.labelWidth = ct.labelWidth || 100;
6450 if(Ext.isNumber(ct.labelWidth)){
6451 var pad = Ext.isNumber(ct.labelPad) ? ct.labelPad : 5;
6453 labelAdjust: ct.labelWidth + pad,
6454 labelStyle: 'width:' + ct.labelWidth + 'px;',
6455 elementStyle: 'padding-left:' + (ct.labelWidth + pad) + 'px'
6458 if(ct.labelAlign == 'top'){
6460 labelStyle: 'width:auto;',
6462 elementStyle: 'padding-left:0;'
6468 isHide: function(c){
6469 return c.hideLabel || this.container.hideLabels;
6472 onFieldShow: function(c){
6473 c.getItemCt().removeClass('x-hide-' + c.hideMode);
6476 onFieldHide: function(c){
6477 c.getItemCt().addClass('x-hide-' + c.hideMode);
6481 getLabelStyle: function(s){
6482 var ls = '', items = [this.labelStyle, s];
6483 for (var i = 0, len = items.length; i < len; ++i){
6486 if (ls.substr(-1, 1) != ';'){
6495 * @cfg {Ext.Template} fieldTpl
6496 * A {@link Ext.Template#compile compile}d {@link Ext.Template} for rendering
6497 * the fully wrapped, labeled and styled form Field. Defaults to:</p><pre><code>
6499 '<div class="x-form-item {itemCls}" tabIndex="-1">',
6500 '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{labelSeparator}</label>',
6501 '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
6502 '</div><div class="{clearCls}"></div>',
6506 * <p>This may be specified to produce a different DOM structure when rendering form Fields.</p>
6507 * <p>A description of the properties within the template follows:</p><div class="mdetail-params"><ul>
6508 * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper
6509 * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt>
6510 * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt>
6511 * supplied at the container level.</div></li>
6512 * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li>
6513 * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc">
6514 * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the
6515 * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li>
6516 * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this
6517 * field (defaults to <tt>''</tt>)</div></li>
6518 * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after
6519 * the text of the label for this field (defaults to a colon <tt>':'</tt> or the
6520 * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li>
6521 * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li>
6522 * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div
6523 * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li>
6525 * <p>Also see <tt>{@link #getTemplateArgs}</tt></p>
6529 renderItem : function(c, position, target){
6530 if(c && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){
6531 var args = this.getTemplateArgs(c);
6532 if(Ext.isNumber(position)){
6533 position = target.dom.childNodes[position] || null;
6536 c.itemCt = this.fieldTpl.insertBefore(position, args, true);
6538 c.itemCt = this.fieldTpl.append(target, args, true);
6541 c.render('x-form-el-' + c.id);
6542 }else if(!this.isValidParent(c, target)){
6543 Ext.fly('x-form-el-' + c.id).appendChild(c.getPositionEl());
6546 // Non form fields don't have getItemCt, apply it here
6547 // This will get cleaned up in onRemove
6549 getItemCt: function(){
6555 c.label = c.getItemCt().child('label.x-form-item-label');
6556 if(this.trackLabels && !this.isHide(c)){
6558 this.onFieldHide(c);
6562 show: this.onFieldShow,
6563 hide: this.onFieldHide
6566 this.configureItem(c);
6568 Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments);
6573 * <p>Provides template arguments for rendering the fully wrapped, labeled and styled form Field.</p>
6574 * <p>This method returns an object hash containing properties used by the layout's {@link #fieldTpl}
6575 * to create a correctly wrapped, labeled and styled form Field. This may be overriden to
6576 * create custom layouts. The properties which must be returned are:</p><div class="mdetail-params"><ul>
6577 * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper
6578 * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt>
6579 * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt>
6580 * supplied at the container level.</div></li>
6581 * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li>
6582 * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc">
6583 * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the
6584 * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li>
6585 * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this
6586 * field (defaults to <tt>''</tt>)</div></li>
6587 * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after
6588 * the text of the label for this field (defaults to a colon <tt>':'</tt> or the
6589 * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li>
6590 * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li>
6591 * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div
6592 * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li>
6594 * @param field The {@link Field Ext.form.Field} being rendered.
6595 * @return An object hash containing the properties required to render the Field.
6597 getTemplateArgs: function(field) {
6598 var noLabelSep = !field.fieldLabel || field.hideLabel;
6601 label: field.fieldLabel,
6602 labelStyle: this.getLabelStyle(field.labelStyle),
6603 elementStyle: this.elementStyle||'',
6604 labelSeparator: noLabelSep ? '' : (Ext.isDefined(field.labelSeparator) ? field.labelSeparator : this.labelSeparator),
6605 itemCls: (field.itemCls||this.container.itemCls||'') + (field.hideLabel ? ' x-hide-label' : ''),
6606 clearCls: field.clearCls || 'x-form-clear-left'
6611 adjustWidthAnchor: function(value, c){
6612 if(c.label && !this.isHide(c) && (this.container.labelAlign != 'top')){
6613 var adjust = Ext.isIE6 || (Ext.isIE && !Ext.isStrict);
6614 return value - this.labelAdjust + (adjust ? -3 : 0);
6619 adjustHeightAnchor : function(value, c){
6620 if(c.label && !this.isHide(c) && (this.container.labelAlign == 'top')){
6621 return value - c.label.getHeight();
6627 isValidParent : function(c, target){
6628 return target && this.container.getEl().contains(c.getDomPositionEl());
6632 * @property activeItem
6637 Ext.Container.LAYOUTS['form'] = Ext.layout.FormLayout;/**
\r
6638 * @class Ext.layout.AccordionLayout
\r
6639 * @extends Ext.layout.FitLayout
\r
6640 * <p>This is a layout that manages multiple Panels in an expandable accordion style such that only
\r
6641 * <b>one Panel can be expanded at any given time</b>. Each Panel has built-in support for expanding and collapsing.</p>
\r
6642 * <p>Note: Only Ext.Panels <b>and all subclasses of Ext.Panel</b> may be used in an accordion layout Container.</p>
\r
6643 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
\r
6644 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
\r
6645 * <p>Example usage:</p>
\r
6647 var accordion = new Ext.Panel({
\r
6648 title: 'Accordion Layout',
\r
6649 layout:'accordion',
\r
6651 // applied to each contained panel
\r
6652 bodyStyle: 'padding:15px'
\r
6655 // layout-specific configs go here
\r
6656 titleCollapse: false,
\r
6662 html: '<p>Panel content!</p>'
\r
6665 html: '<p>Panel content!</p>'
\r
6668 html: '<p>Panel content!</p>'
\r
6673 Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, {
\r
6675 * @cfg {Boolean} fill
\r
6676 * True to adjust the active item's height to fill the available space in the container, false to use the
\r
6677 * item's current height, or auto height if not explicitly set (defaults to true).
\r
6681 * @cfg {Boolean} autoWidth
\r
6682 * True to set each contained item's width to 'auto', false to use the item's current width (defaults to true).
\r
6683 * Note that some components, in particular the {@link Ext.grid.GridPanel grid}, will not function properly within
\r
6684 * layouts if they have auto width, so in such cases this config should be set to false.
\r
6688 * @cfg {Boolean} titleCollapse
\r
6689 * True to allow expand/collapse of each contained panel by clicking anywhere on the title bar, false to allow
\r
6690 * expand/collapse only when the toggle tool button is clicked (defaults to true). When set to false,
\r
6691 * {@link #hideCollapseTool} should be false also.
\r
6693 titleCollapse : true,
\r
6695 * @cfg {Boolean} hideCollapseTool
\r
6696 * True to hide the contained panels' collapse/expand toggle buttons, false to display them (defaults to false).
\r
6697 * When set to true, {@link #titleCollapse} should be true also.
\r
6699 hideCollapseTool : false,
\r
6701 * @cfg {Boolean} collapseFirst
\r
6702 * True to make sure the collapse/expand toggle button always renders first (to the left of) any other tools
\r
6703 * in the contained panels' title bars, false to render it last (defaults to false).
\r
6705 collapseFirst : false,
\r
6707 * @cfg {Boolean} animate
\r
6708 * True to slide the contained panels open and closed during expand/collapse using animation, false to open and
\r
6709 * close directly with no animation (defaults to false). Note: to defer to the specific config setting of each
\r
6710 * contained panel for this property, set this to undefined at the layout level.
\r
6714 * @cfg {Boolean} sequence
\r
6715 * <b>Experimental</b>. If animate is set to true, this will result in each animation running in sequence.
\r
6719 * @cfg {Boolean} activeOnTop
\r
6720 * True to swap the position of each panel as it is expanded so that it becomes the first item in the container,
\r
6721 * false to keep the panels in the rendered order. <b>This is NOT compatible with "animate:true"</b> (defaults to false).
\r
6723 activeOnTop : false,
\r
6725 renderItem : function(c){
\r
6726 if(this.animate === false){
\r
6727 c.animCollapse = false;
\r
6729 c.collapsible = true;
\r
6730 if(this.autoWidth){
\r
6731 c.autoWidth = true;
\r
6733 if(this.titleCollapse){
\r
6734 c.titleCollapse = true;
\r
6736 if(this.hideCollapseTool){
\r
6737 c.hideCollapseTool = true;
\r
6739 if(this.collapseFirst !== undefined){
\r
6740 c.collapseFirst = this.collapseFirst;
\r
6742 if(!this.activeItem && !c.collapsed){
\r
6743 this.activeItem = c;
\r
6744 }else if(this.activeItem && this.activeItem != c){
\r
6745 c.collapsed = true;
\r
6747 Ext.layout.AccordionLayout.superclass.renderItem.apply(this, arguments);
\r
6748 c.header.addClass('x-accordion-hd');
\r
6749 c.on('beforeexpand', this.beforeExpand, this);
\r
6752 onRemove: function(c){
\r
6753 Ext.layout.AccordionLayout.superclass.onRemove.call(this, c);
\r
6755 c.header.removeClass('x-accordion-hd');
\r
6757 c.un('beforeexpand', this.beforeExpand, this);
\r
6761 beforeExpand : function(p, anim){
\r
6762 var ai = this.activeItem;
\r
6764 if(this.sequence){
\r
6765 delete this.activeItem;
\r
6766 if (!ai.collapsed){
\r
6767 ai.collapse({callback:function(){
\r
6768 p.expand(anim || true);
\r
6773 ai.collapse(this.animate);
\r
6776 this.activeItem = p;
\r
6777 if(this.activeOnTop){
\r
6778 p.el.dom.parentNode.insertBefore(p.el.dom, p.el.dom.parentNode.firstChild);
\r
6784 setItemSize : function(item, size){
\r
6785 if(this.fill && item){
\r
6787 this.container.items.each(function(p){
\r
6789 hh += p.header.getHeight();
\r
6792 size.height -= hh;
\r
6793 item.setSize(size);
\r
6798 * Sets the active (expanded) item in the layout.
\r
6799 * @param {String/Number} item The string component id or numeric index of the item to activate
\r
6801 setActiveItem : function(item){
\r
6802 item = this.container.getComponent(item);
\r
6803 if(this.activeItem != item){
\r
6804 if(item.rendered && item.collapsed){
\r
6807 this.activeItem = item;
\r
6813 Ext.Container.LAYOUTS.accordion = Ext.layout.AccordionLayout;
\r
6815 //backwards compat
\r
6816 Ext.layout.Accordion = Ext.layout.AccordionLayout;/**
\r
6817 * @class Ext.layout.TableLayout
\r
6818 * @extends Ext.layout.ContainerLayout
\r
6819 * <p>This layout allows you to easily render content into an HTML table. The total number of columns can be
\r
6820 * specified, and rowspan and colspan can be used to create complex layouts within the table.
\r
6821 * This class is intended to be extended or created via the layout:'table' {@link Ext.Container#layout} config,
\r
6822 * and should generally not need to be created directly via the new keyword.</p>
\r
6823 * <p>Note that when creating a layout via config, the layout-specific config properties must be passed in via
\r
6824 * the {@link Ext.Container#layoutConfig} object which will then be applied internally to the layout. In the
\r
6825 * case of TableLayout, the only valid layout config property is {@link #columns}. However, the items added to a
\r
6826 * TableLayout can supply the following table-specific config properties:</p>
\r
6828 * <li><b>rowspan</b> Applied to the table cell containing the item.</li>
\r
6829 * <li><b>colspan</b> Applied to the table cell containing the item.</li>
\r
6830 * <li><b>cellId</b> An id applied to the table cell containing the item.</li>
\r
6831 * <li><b>cellCls</b> A CSS class name added to the table cell containing the item.</li>
\r
6833 * <p>The basic concept of building up a TableLayout is conceptually very similar to building up a standard
\r
6834 * HTML table. You simply add each panel (or "cell") that you want to include along with any span attributes
\r
6835 * specified as the special config properties of rowspan and colspan which work exactly like their HTML counterparts.
\r
6836 * Rather than explicitly creating and nesting rows and columns as you would in HTML, you simply specify the
\r
6837 * total column count in the layoutConfig and start adding panels in their natural order from left to right,
\r
6838 * top to bottom. The layout will automatically figure out, based on the column count, rowspans and colspans,
\r
6839 * how to position each panel within the table. Just like with HTML tables, your rowspans and colspans must add
\r
6840 * up correctly in your overall layout or you'll end up with missing and/or extra cells! Example usage:</p>
\r
6842 // This code will generate a layout table that is 3 columns by 2 rows
\r
6843 // with some spanning included. The basic layout will be:
\r
6844 // +--------+-----------------+
\r
6846 // | |--------+--------|
\r
6848 // +--------+--------+--------+
\r
6849 var table = new Ext.Panel({
\r
6850 title: 'Table Layout',
\r
6853 // applied to each contained panel
\r
6854 bodyStyle:'padding:20px'
\r
6857 // The total column count must be specified here
\r
6861 html: '<p>Cell A content</p>',
\r
6864 html: '<p>Cell B content</p>',
\r
6867 html: '<p>Cell C content</p>',
\r
6868 cellCls: 'highlight'
\r
6870 html: '<p>Cell D content</p>'
\r
6875 Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, {
\r
6877 * @cfg {Number} columns
\r
6878 * The total number of columns to create in the table for this layout. If not specified, all Components added to
\r
6879 * this layout will be rendered into a single row using one column per Component.
\r
6883 monitorResize:false,
\r
6886 * @cfg {Object} tableAttrs
\r
6887 * <p>An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification
\r
6888 * used to create the layout's <tt><table></tt> element. Example:</p><pre><code>
\r
6905 setContainer : function(ct){
\r
6906 Ext.layout.TableLayout.superclass.setContainer.call(this, ct);
\r
6908 this.currentRow = 0;
\r
6909 this.currentColumn = 0;
\r
6914 onLayout : function(ct, target){
\r
6915 var cs = ct.items.items, len = cs.length, c, i;
\r
6918 target.addClass('x-table-layout-ct');
\r
6920 this.table = target.createChild(
\r
6921 Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true);
\r
6923 this.renderAll(ct, target);
\r
6927 getRow : function(index){
\r
6928 var row = this.table.tBodies[0].childNodes[index];
\r
6930 row = document.createElement('tr');
\r
6931 this.table.tBodies[0].appendChild(row);
\r
6937 getNextCell : function(c){
\r
6938 var cell = this.getNextNonSpan(this.currentColumn, this.currentRow);
\r
6939 var curCol = this.currentColumn = cell[0], curRow = this.currentRow = cell[1];
\r
6940 for(var rowIndex = curRow; rowIndex < curRow + (c.rowspan || 1); rowIndex++){
\r
6941 if(!this.cells[rowIndex]){
\r
6942 this.cells[rowIndex] = [];
\r
6944 for(var colIndex = curCol; colIndex < curCol + (c.colspan || 1); colIndex++){
\r
6945 this.cells[rowIndex][colIndex] = true;
\r
6948 var td = document.createElement('td');
\r
6952 var cls = 'x-table-layout-cell';
\r
6954 cls += ' ' + c.cellCls;
\r
6956 td.className = cls;
\r
6958 td.colSpan = c.colspan;
\r
6961 td.rowSpan = c.rowspan;
\r
6963 this.getRow(curRow).appendChild(td);
\r
6968 getNextNonSpan: function(colIndex, rowIndex){
\r
6969 var cols = this.columns;
\r
6970 while((cols && colIndex >= cols) || (this.cells[rowIndex] && this.cells[rowIndex][colIndex])) {
\r
6971 if(cols && colIndex >= cols){
\r
6978 return [colIndex, rowIndex];
\r
6982 renderItem : function(c, position, target){
\r
6983 if(c && !c.rendered){
\r
6984 c.render(this.getNextCell(c));
\r
6985 this.configureItem(c, position);
\r
6986 }else if(c && !this.isValidParent(c, target)){
\r
6987 var container = this.getNextCell(c);
\r
6988 container.insertBefore(c.getDomPositionEl().dom, null);
\r
6989 c.container = Ext.get(container);
\r
6990 this.configureItem(c, position);
\r
6995 isValidParent : function(c, target){
\r
6996 return c.getDomPositionEl().up('table', 5).dom.parentNode === (target.dom || target);
\r
7000 * @property activeItem
\r
7005 Ext.Container.LAYOUTS['table'] = Ext.layout.TableLayout;/**
\r
7006 * @class Ext.layout.AbsoluteLayout
\r
7007 * @extends Ext.layout.AnchorLayout
\r
7008 * <p>This is a layout that inherits the anchoring of <b>{@link Ext.layout.AnchorLayout}</b> and adds the
\r
7009 * ability for x/y positioning using the standard x and y component config options.</p>
\r
7010 * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt>
\r
7011 * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p>
\r
7012 * <p>Example usage:</p>
\r
7014 var form = new Ext.form.FormPanel({
\r
7015 title: 'Absolute Layout',
\r
7016 layout:'absolute',
\r
7018 // layout-specific configs go here
\r
7019 extraCls: 'x-abs-layout-item',
\r
7021 baseCls: 'x-plain',
\r
7022 url:'save-form.php',
\r
7023 defaultType: 'textfield',
\r
7033 anchor:'100%' // anchor width by percentage
\r
7043 anchor: '100%' // anchor width by percentage
\r
7047 xtype: 'textarea',
\r
7049 anchor: '100% 100%' // anchor width and height
\r
7054 Ext.layout.AbsoluteLayout = Ext.extend(Ext.layout.AnchorLayout, {
\r
7056 extraCls: 'x-abs-layout-item',
\r
7058 onLayout : function(ct, target){
\r
7059 target.position();
\r
7060 this.paddingLeft = target.getPadding('l');
\r
7061 this.paddingTop = target.getPadding('t');
\r
7063 Ext.layout.AbsoluteLayout.superclass.onLayout.call(this, ct, target);
\r
7067 adjustWidthAnchor : function(value, comp){
\r
7068 return value ? value - comp.getPosition(true)[0] + this.paddingLeft : value;
\r
7072 adjustHeightAnchor : function(value, comp){
\r
7073 return value ? value - comp.getPosition(true)[1] + this.paddingTop : value;
\r
7076 * @property activeItem
\r
7080 Ext.Container.LAYOUTS['absolute'] = Ext.layout.AbsoluteLayout;
7082 * @class Ext.layout.BoxLayout
\r
7083 * @extends Ext.layout.ContainerLayout
\r
7084 * <p>Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.</p>
\r
7086 Ext.layout.BoxLayout = Ext.extend(Ext.layout.ContainerLayout, {
\r
7088 * @cfg {Object} defaultMargins
\r
7089 * <p>If the individual contained items do not have a <tt>margins</tt>
\r
7090 * property specified, the default margins from this property will be
\r
7091 * applied to each item.</p>
\r
7092 * <br><p>This property may be specified as an object containing margins
\r
7093 * to apply in the format:</p><pre><code>
\r
7095 top: (top margin),
\r
7096 right: (right margin),
\r
7097 bottom: (bottom margin),
\r
7098 left: (left margin)
\r
7100 * <p>This property may also be specified as a string containing
\r
7101 * space-separated, numeric margin values. The order of the sides associated
\r
7102 * with each value matches the way CSS processes margin values:</p>
\r
7103 * <div class="mdetail-params"><ul>
\r
7104 * <li>If there is only one value, it applies to all sides.</li>
\r
7105 * <li>If there are two values, the top and bottom borders are set to the
\r
7106 * first value and the right and left are set to the second.</li>
\r
7107 * <li>If there are three values, the top is set to the first value, the left
\r
7108 * and right are set to the second, and the bottom is set to the third.</li>
\r
7109 * <li>If there are four values, they apply to the top, right, bottom, and
\r
7110 * left, respectively.</li>
\r
7112 * <p>Defaults to:</p><pre><code>
\r
7113 * {top:0, right:0, bottom:0, left:0}
\r
7116 defaultMargins : {left:0,top:0,right:0,bottom:0},
\r
7118 * @cfg {String} padding
\r
7119 * <p>Sets the padding to be applied to all child items managed by this layout.</p>
\r
7120 * <p>This property must be specified as a string containing
\r
7121 * space-separated, numeric padding values. The order of the sides associated
\r
7122 * with each value matches the way CSS processes padding values:</p>
\r
7123 * <div class="mdetail-params"><ul>
\r
7124 * <li>If there is only one value, it applies to all sides.</li>
\r
7125 * <li>If there are two values, the top and bottom borders are set to the
\r
7126 * first value and the right and left are set to the second.</li>
\r
7127 * <li>If there are three values, the top is set to the first value, the left
\r
7128 * and right are set to the second, and the bottom is set to the third.</li>
\r
7129 * <li>If there are four values, they apply to the top, right, bottom, and
\r
7130 * left, respectively.</li>
\r
7132 * <p>Defaults to: <code>"0"</code></p>
\r
7135 // documented in subclasses
\r
7139 monitorResize : true,
\r
7141 extraCls : 'x-box-item',
\r
7142 ctCls : 'x-box-layout-ct',
\r
7143 innerCls : 'x-box-inner',
\r
7145 constructor : function(config){
\r
7146 Ext.layout.BoxLayout.superclass.constructor.call(this, config);
\r
7147 if(Ext.isString(this.defaultMargins)){
\r
7148 this.defaultMargins = this.parseMargins(this.defaultMargins);
\r
7153 isValidParent : function(c, target){
\r
7154 return c.getEl().dom.parentNode == this.innerCt.dom;
\r
7158 onLayout : function(ct, target){
\r
7159 var cs = ct.items.items, len = cs.length, c, i, last = len-1, cm;
\r
7161 if(!this.innerCt){
\r
7162 target.addClass(this.ctCls);
\r
7164 // the innerCt prevents wrapping and shuffling while
\r
7165 // the container is resizing
\r
7166 this.innerCt = target.createChild({cls:this.innerCls});
\r
7167 this.padding = this.parseMargins(this.padding);
\r
7169 this.renderAll(ct, this.innerCt);
\r
7173 renderItem : function(c){
\r
7174 if(Ext.isString(c.margins)){
\r
7175 c.margins = this.parseMargins(c.margins);
\r
7176 }else if(!c.margins){
\r
7177 c.margins = this.defaultMargins;
\r
7179 Ext.layout.BoxLayout.superclass.renderItem.apply(this, arguments);
\r
7182 getTargetSize : function(target){
7183 return (Ext.isIE6 && Ext.isStrict && target.dom == document.body) ? target.getStyleSize() : target.getViewSize();
\r
7186 getItems: function(ct){
\r
7188 ct.items.each(function(c){
\r
7189 if(c.isVisible()){
\r
7197 * @property activeItem
\r
7203 * @class Ext.layout.VBoxLayout
\r
7204 * @extends Ext.layout.BoxLayout
\r
7205 * <p>A layout that arranges items vertically down a Container. This layout optionally divides available vertical
\r
7206 * space between child items containing a numeric <code>flex</code> configuration.</p>
\r
7207 * This layout may also be used to set the widths of child items by configuring it with the {@link #align} option.
\r
7209 Ext.layout.VBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
\r
7211 * @cfg {String} align
\r
7212 * Controls how the child items of the container are aligned. Acceptable configuration values for this
\r
7214 * <div class="mdetail-params"><ul>
\r
7215 * <li><b><tt>left</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned horizontally
\r
7216 * at the <b>left</b> side of the container</div></li>
\r
7217 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are aligned horizontally at the
\r
7218 * <b>mid-width</b> of the container</div></li>
\r
7219 * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched horizontally to fill
\r
7220 * the width of the container</div></li>
\r
7221 * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched horizontally to
\r
7222 * the size of the largest item.</div></li>
\r
7225 align : 'left', // left, center, stretch, strechmax
\r
7227 * @cfg {String} pack
\r
7228 * Controls how the child items of the container are packed together. Acceptable configuration values
\r
7229 * for this property are:
\r
7230 * <div class="mdetail-params"><ul>
\r
7231 * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
\r
7232 * <b>top</b> side of container</div></li>
\r
7233 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
\r
7234 * <b>mid-height</b> of container</div></li>
\r
7235 * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>bottom</b>
\r
7236 * side of container</div></li>
\r
7240 * @cfg {Number} flex
\r
7241 * This configuation option is to be applied to <b>child <tt>items</tt></b> of the container managed
\r
7242 * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>vertically</b>
\r
7243 * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
\r
7244 * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
\r
7245 * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
\r
7249 onLayout : function(ct, target){
\r
7250 Ext.layout.VBoxLayout.superclass.onLayout.call(this, ct, target);
\r
7253 var cs = this.getItems(ct), cm, ch, margin,
\r
7254 size = this.getTargetSize(target),
\r
7255 w = size.width - target.getPadding('lr'),
\r
7256 h = size.height - target.getPadding('tb') - this.scrollOffset,
\r
7257 l = this.padding.left, t = this.padding.top,
\r
7258 isStart = this.pack == 'start',
\r
7259 isRestore = ['stretch', 'stretchmax'].indexOf(this.align) == -1,
\r
7260 stretchWidth = w - (this.padding.left + this.padding.right),
\r
7267 Ext.each(cs, function(c){
\r
7269 totalFlex += c.flex || 0;
\r
7270 ch = c.getHeight();
\r
7271 margin = cm.top + cm.bottom;
\r
7272 extraHeight += ch + margin;
\r
7273 flexHeight += margin + (c.flex ? 0 : ch);
\r
7274 maxWidth = Math.max(maxWidth, c.getWidth() + cm.left + cm.right);
\r
7276 extraHeight = h - extraHeight - this.padding.top - this.padding.bottom;
\r
7278 var innerCtWidth = maxWidth + this.padding.left + this.padding.right;
\r
7279 switch(this.align){
\r
7281 this.innerCt.setSize(w, h);
\r
7283 case 'stretchmax':
\r
7285 this.innerCt.setSize(innerCtWidth, h);
\r
7288 this.innerCt.setSize(w = Math.max(w, innerCtWidth), h);
\r
7292 var availHeight = Math.max(0, h - this.padding.top - this.padding.bottom - flexHeight),
\r
7293 leftOver = availHeight,
\r
7297 availableWidth = Math.max(0, w - this.padding.left - this.padding.right);
\r
7300 Ext.each(cs, function(c){
\r
7301 if(isStart && c.flex){
\r
7302 ch = Math.floor(availHeight * (c.flex / totalFlex));
\r
7308 if(this.pack == 'center'){
\r
7309 t += extraHeight ? extraHeight / 2 : 0;
\r
7310 }else if(this.pack == 'end'){
\r
7313 Ext.each(cs, function(c){
\r
7316 c.setPosition(l + cm.left, t);
\r
7317 if(isStart && c.flex){
\r
7318 ch = Math.max(0, heights[idx++] + (leftOver-- > 0 ? 1 : 0));
\r
7320 restore.push(c.getWidth());
\r
7322 c.setSize(availableWidth, ch);
\r
7324 ch = c.getHeight();
\r
7326 t += ch + cm.bottom;
\r
7330 Ext.each(cs, function(c){
\r
7332 if(this.align == 'stretch'){
\r
7333 c.setWidth((stretchWidth - (cm.left + cm.right)).constrain(
\r
7334 c.minWidth || 0, c.maxWidth || 1000000));
\r
7335 }else if(this.align == 'stretchmax'){
\r
7336 c.setWidth((maxWidth - (cm.left + cm.right)).constrain(
\r
7337 c.minWidth || 0, c.maxWidth || 1000000));
\r
7339 if(this.align == 'center'){
\r
7340 var diff = availableWidth - (c.getWidth() + cm.left + cm.right);
\r
7342 c.setPosition(l + cm.left + (diff/2), c.y);
\r
7345 if(isStart && c.flex){
\r
7346 c.setWidth(restore[idx++]);
\r
7352 * @property activeItem
\r
7357 Ext.Container.LAYOUTS.vbox = Ext.layout.VBoxLayout;
\r
7360 * @class Ext.layout.HBoxLayout
\r
7361 * @extends Ext.layout.BoxLayout
\r
7362 * <p>A layout that arranges items horizontally across a Container. This layout optionally divides available horizontal
\r
7363 * space between child items containing a numeric <code>flex</code> configuration.</p>
\r
7364 * This layout may also be used to set the heights of child items by configuring it with the {@link #align} option.
\r
7366 Ext.layout.HBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
\r
7368 * @cfg {String} align
\r
7369 * Controls how the child items of the container are aligned. Acceptable configuration values for this
\r
7371 * <div class="mdetail-params"><ul>
\r
7372 * <li><b><tt>top</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned vertically
\r
7373 * at the <b>left</b> side of the container</div></li>
\r
7374 * <li><b><tt>middle</tt></b> : <div class="sub-desc">child items are aligned vertically at the
\r
7375 * <b>mid-height</b> of the container</div></li>
\r
7376 * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched vertically to fill
\r
7377 * the height of the container</div></li>
\r
7378 * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched vertically to
\r
7379 * the size of the largest item.</div></li>
\r
7381 align : 'top', // top, middle, stretch, strechmax
\r
7383 * @cfg {String} pack
\r
7384 * Controls how the child items of the container are packed together. Acceptable configuration values
\r
7385 * for this property are:
\r
7386 * <div class="mdetail-params"><ul>
\r
7387 * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
\r
7388 * <b>left</b> side of container</div></li>
\r
7389 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
\r
7390 * <b>mid-width</b> of container</div></li>
\r
7391 * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>right</b>
\r
7392 * side of container</div></li>
\r
7396 * @cfg {Number} flex
\r
7397 * This configuation option is to be applied to <b>child <tt>items</tt></b> of the container managed
\r
7398 * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>horizontally</b>
\r
7399 * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
\r
7400 * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
\r
7401 * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
\r
7405 onLayout : function(ct, target){
\r
7406 Ext.layout.HBoxLayout.superclass.onLayout.call(this, ct, target);
\r
7408 var cs = this.getItems(ct), cm, cw, margin,
\r
7409 size = this.getTargetSize(target),
\r
7410 w = size.width - target.getPadding('lr') - this.scrollOffset,
\r
7411 h = size.height - target.getPadding('tb'),
\r
7412 l = this.padding.left, t = this.padding.top,
\r
7413 isStart = this.pack == 'start',
\r
7414 isRestore = ['stretch', 'stretchmax'].indexOf(this.align) == -1,
\r
7415 stretchHeight = h - (this.padding.top + this.padding.bottom),
\r
7422 Ext.each(cs, function(c){
\r
7424 totalFlex += c.flex || 0;
\r
7425 cw = c.getWidth();
\r
7426 margin = cm.left + cm.right;
\r
7427 extraWidth += cw + margin;
\r
7428 flexWidth += margin + (c.flex ? 0 : cw);
\r
7429 maxHeight = Math.max(maxHeight, c.getHeight() + cm.top + cm.bottom);
\r
7431 extraWidth = w - extraWidth - this.padding.left - this.padding.right;
\r
7433 var innerCtHeight = maxHeight + this.padding.top + this.padding.bottom;
\r
7434 switch(this.align){
\r
7436 this.innerCt.setSize(w, h);
\r
7438 case 'stretchmax':
\r
7440 this.innerCt.setSize(w, innerCtHeight);
\r
7443 this.innerCt.setSize(w, h = Math.max(h, innerCtHeight));
\r
7448 var availWidth = Math.max(0, w - this.padding.left - this.padding.right - flexWidth),
\r
7449 leftOver = availWidth,
\r
7453 availableHeight = Math.max(0, h - this.padding.top - this.padding.bottom);
\r
7456 Ext.each(cs, function(c){
\r
7457 if(isStart && c.flex){
\r
7458 cw = Math.floor(availWidth * (c.flex / totalFlex));
\r
7464 if(this.pack == 'center'){
\r
7465 l += extraWidth ? extraWidth / 2 : 0;
\r
7466 }else if(this.pack == 'end'){
\r
7469 Ext.each(cs, function(c){
\r
7472 c.setPosition(l, t + cm.top);
\r
7473 if(isStart && c.flex){
\r
7474 cw = Math.max(0, widths[idx++] + (leftOver-- > 0 ? 1 : 0));
\r
7476 restore.push(c.getHeight());
\r
7478 c.setSize(cw, availableHeight);
\r
7480 cw = c.getWidth();
\r
7482 l += cw + cm.right;
\r
7486 Ext.each(cs, function(c){
\r
7487 var cm = c.margins;
\r
7488 if(this.align == 'stretch'){
\r
7489 c.setHeight((stretchHeight - (cm.top + cm.bottom)).constrain(
\r
7490 c.minHeight || 0, c.maxHeight || 1000000));
\r
7491 }else if(this.align == 'stretchmax'){
\r
7492 c.setHeight((maxHeight - (cm.top + cm.bottom)).constrain(
\r
7493 c.minHeight || 0, c.maxHeight || 1000000));
\r
7495 if(this.align == 'middle'){
\r
7496 var diff = availableHeight - (c.getHeight() + cm.top + cm.bottom);
\r
7498 c.setPosition(c.x, t + cm.top + (diff/2));
\r
7501 if(isStart && c.flex){
\r
7502 c.setHeight(restore[idx++]);
\r
7509 * @property activeItem
\r
7514 Ext.Container.LAYOUTS.hbox = Ext.layout.HBoxLayout;
7516 * @class Ext.Viewport
\r
7517 * @extends Ext.Container
\r
7518 * <p>A specialized container representing the viewable application area (the browser viewport).</p>
\r
7519 * <p>The Viewport renders itself to the document body, and automatically sizes itself to the size of
\r
7520 * the browser viewport and manages window resizing. There may only be one Viewport created
\r
7521 * in a page. Inner layouts are available by virtue of the fact that all {@link Ext.Panel Panel}s
\r
7522 * added to the Viewport, either through its {@link #items}, or through the items, or the {@link #add}
\r
7523 * method of any of its child Panels may themselves have a layout.</p>
\r
7524 * <p>The Viewport does not provide scrolling, so child Panels within the Viewport should provide
\r
7525 * for scrolling if needed using the {@link #autoScroll} config.</p>
\r
7526 * <p>An example showing a classic application border layout:</p><pre><code>
\r
7527 new Ext.Viewport({
\r
7531 html: '<h1 class="x-panel-header">Page Title</h1>',
\r
7534 margins: '0 0 5 0'
\r
7537 collapsible: true,
\r
7538 title: 'Navigation',
\r
7540 // the west region might typically utilize a {@link Ext.tree.TreePanel TreePanel} or a Panel with {@link Ext.layout.AccordionLayout Accordion layout}
\r
7543 title: 'Title for Panel',
\r
7544 collapsible: true,
\r
7545 html: 'Information goes here',
\r
7551 title: 'Title for the Grid Panel',
\r
7552 collapsible: true,
\r
7556 // remaining grid configuration not shown ...
\r
7557 // notice that the GridPanel is added directly as the region
\r
7558 // it is not "overnested" inside another Panel
\r
7561 xtype: 'tabpanel', // TabPanel itself has no title
\r
7563 title: 'Default Tab',
\r
7564 html: 'The first tab\'s content. Others may be added dynamically'
\r
7570 * Create a new Viewport
\r
7571 * @param {Object} config The config object
\r
7574 Ext.Viewport = Ext.extend(Ext.Container, {
\r
7576 * Privatize config options which, if used, would interfere with the
\r
7577 * correct operation of the Viewport as the sole manager of the
\r
7578 * layout of the document body.
\r
7581 * @cfg {Mixed} applyTo @hide
\r
7584 * @cfg {Boolean} allowDomMove @hide
\r
7587 * @cfg {Boolean} hideParent @hide
\r
7590 * @cfg {Mixed} renderTo @hide
\r
7593 * @cfg {Boolean} hideParent @hide
\r
7596 * @cfg {Number} height @hide
\r
7599 * @cfg {Number} width @hide
\r
7602 * @cfg {Boolean} autoHeight @hide
\r
7605 * @cfg {Boolean} autoWidth @hide
\r
7608 * @cfg {Boolean} deferHeight @hide
\r
7611 * @cfg {Boolean} monitorResize @hide
\r
7613 initComponent : function() {
\r
7614 Ext.Viewport.superclass.initComponent.call(this);
\r
7615 document.getElementsByTagName('html')[0].className += ' x-viewport';
\r
7616 this.el = Ext.getBody();
\r
7617 this.el.setHeight = Ext.emptyFn;
\r
7618 this.el.setWidth = Ext.emptyFn;
\r
7619 this.el.setSize = Ext.emptyFn;
\r
7620 this.el.dom.scroll = 'no';
\r
7621 this.allowDomMove = false;
\r
7622 this.autoWidth = true;
\r
7623 this.autoHeight = true;
\r
7624 Ext.EventManager.onWindowResize(this.fireResize, this);
\r
7625 this.renderTo = this.el;
\r
7628 fireResize : function(w, h){
\r
7629 this.fireEvent('resize', this, w, h, w, h);
\r
7632 Ext.reg('viewport', Ext.Viewport);/**
7634 * @extends Ext.Container
7635 * <p>Panel is a container that has specific functionality and structural components that make
7636 * it the perfect building block for application-oriented user interfaces.</p>
7637 * <p>Panels are, by virtue of their inheritance from {@link Ext.Container}, capable
7638 * of being configured with a {@link Ext.Container#layout layout}, and containing child Components.</p>
7639 * <p>When either specifying child {@link Ext.Component#items items} of a Panel, or dynamically {@link Ext.Container#add adding} Components
7640 * to a Panel, remember to consider how you wish the Panel to arrange those child elements, and whether
7641 * 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
7642 * default, Panels use the {@link Ext.layout.ContainerLayout ContainerLayout} scheme. This simply renders
7643 * child components, appending them one after the other inside the Container, and <b>does not apply any sizing</b>
7645 * <p>A Panel may also contain {@link #bbar bottom} and {@link #tbar top} toolbars, along with separate
7646 * {@link #header}, {@link #footer} and {@link #body} sections (see {@link #frame} for additional
7648 * <p>Panel also provides built-in {@link #collapsible expandable and collapsible behavior}, along with
7649 * a variety of {@link #tools prebuilt tool buttons} that can be wired up to provide other customized
7650 * behavior. Panels can be easily dropped into any {@link Ext.Container Container} or layout, and the
7651 * layout and rendering pipeline is {@link Ext.Container#add completely managed by the framework}.</p>
7653 * @param {Object} config The config object
7656 Ext.Panel = Ext.extend(Ext.Container, {
7658 * The Panel's header {@link Ext.Element Element}. Read-only.
7659 * <p>This Element is used to house the {@link #title} and {@link #tools}</p>
7660 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
7665 * The Panel's body {@link Ext.Element Element} which may be used to contain HTML content.
7666 * The content may be specified in the {@link #html} config, or it may be loaded using the
7667 * {@link autoLoad} config, or through the Panel's {@link #getUpdater Updater}. Read-only.
7668 * <p>If this is used to load visible HTML elements in either way, then
7669 * the Panel may not be used as a Layout for hosting nested Panels.</p>
7670 * <p>If this Panel is intended to be used as the host of a Layout (See {@link #layout}
7671 * then the body Element must not be loaded or changed - it is under the control
7672 * of the Panel's Layout.
7673 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
7678 * The Panel's bwrap {@link Ext.Element Element} used to contain other Panel elements
7679 * (tbar, body, bbar, footer). See {@link #bodyCfg}. Read-only.
7684 * True if this panel is collapsed. Read-only.
7686 * @property collapsed
7689 * @cfg {Object} bodyCfg
7690 * <p>A {@link Ext.DomHelper DomHelper} element specification object may be specified for any
7691 * Panel Element.</p>
7692 * <p>By default, the Default element in the table below will be used for the html markup to
7693 * create a child element with the commensurate Default class name (<code>baseCls</code> will be
7694 * replaced by <code>{@link #baseCls}</code>):</p>
7696 * Panel Default Default Custom Additional Additional
7697 * Element element class element class style
7698 * ======== ========================== ========= ============== ===========
7699 * {@link #header} div {@link #baseCls}+'-header' {@link #headerCfg} headerCssClass headerStyle
7700 * {@link #bwrap} div {@link #baseCls}+'-bwrap' {@link #bwrapCfg} bwrapCssClass bwrapStyle
7701 * + tbar div {@link #baseCls}+'-tbar' {@link #tbarCfg} tbarCssClass tbarStyle
7702 * + {@link #body} div {@link #baseCls}+'-body' {@link #bodyCfg} {@link #bodyCssClass} {@link #bodyStyle}
7703 * + bbar div {@link #baseCls}+'-bbar' {@link #bbarCfg} bbarCssClass bbarStyle
7704 * + {@link #footer} div {@link #baseCls}+'-footer' {@link #footerCfg} footerCssClass footerStyle
7706 * <p>Configuring a Custom element may be used, for example, to force the {@link #body} Element
7707 * to use a different form of markup than is created by default. An example of this might be
7708 * to {@link Ext.Element#createChild create a child} Panel containing a custom content, such as
7709 * a header, or forcing centering of all Panel content by having the body be a <center>
7713 title: 'Message Title',
7714 renderTo: Ext.getBody(),
7715 width: 200, height: 130,
7718 cls: 'x-panel-body', // Default class not applied if Custom element specified
7723 cls: 'x-panel-footer' // same as the Default class
7726 footerCssClass: 'custom-footer', // additional css class, see {@link Ext.element#addClass addClass}
7727 footerStyle: 'background-color:red' // see {@link #bodyStyle}
7730 * <p>The example above also explicitly creates a <code>{@link #footer}</code> with custom markup and
7731 * styling applied.</p>
7734 * @cfg {Object} headerCfg
7735 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
7736 * of this Panel's {@link #header} Element. See <code>{@link #bodyCfg}</code> also.</p>
7739 * @cfg {Object} bwrapCfg
7740 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
7741 * of this Panel's {@link #bwrap} Element. See <code>{@link #bodyCfg}</code> also.</p>
7744 * @cfg {Object} tbarCfg
7745 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
7746 * of this Panel's {@link #tbar} Element. See <code>{@link #bodyCfg}</code> also.</p>
7749 * @cfg {Object} bbarCfg
7750 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
7751 * of this Panel's {@link #bbar} Element. See <code>{@link #bodyCfg}</code> also.</p>
7754 * @cfg {Object} footerCfg
7755 * <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
7756 * of this Panel's {@link #footer} Element. See <code>{@link #bodyCfg}</code> also.</p>
7759 * @cfg {Boolean} closable
7760 * Panels themselves do not directly support being closed, but some Panel subclasses do (like
7761 * {@link Ext.Window}) or a Panel Class within an {@link Ext.TabPanel}. Specify <code>true</code>
7762 * to enable closing in such situations. Defaults to <code>false</code>.
7765 * The Panel's footer {@link Ext.Element Element}. Read-only.
7766 * <p>This Element is used to house the Panel's <code>{@link #buttons}</code> or <code>{@link #fbar}</code>.</p>
7767 * <br><p><b>Note</b>: see the Note for <code>{@link Ext.Component#el el}</code> also.</p>
7772 * @cfg {Mixed} applyTo
7773 * <p>The id of the node, a DOM node or an existing Element corresponding to a DIV that is already present in
7774 * the document that specifies some panel-specific structural markup. When <code>applyTo</code> is used,
7775 * constituent parts of the panel can be specified by CSS class name within the main element, and the panel
7776 * will automatically create those components from that markup. Any required components not specified in the
7777 * markup will be autogenerated if necessary.</p>
7778 * <p>The following class names are supported (baseCls will be replaced by {@link #baseCls}):</p>
7779 * <ul><li>baseCls + '-header'</li>
7780 * <li>baseCls + '-header-text'</li>
7781 * <li>baseCls + '-bwrap'</li>
7782 * <li>baseCls + '-tbar'</li>
7783 * <li>baseCls + '-body'</li>
7784 * <li>baseCls + '-bbar'</li>
7785 * <li>baseCls + '-footer'</li></ul>
7786 * <p>Using this config, a call to render() is not required. If applyTo is specified, any value passed for
7787 * {@link #renderTo} will be ignored and the target element's parent node will automatically be used as the
7788 * panel's container.</p>
7791 * @cfg {Object/Array} tbar
7792 * <p>The top toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
7793 * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render.
7794 * To access the top toolbar after render, use {@link #getTopToolbar}.</p>
7795 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
7796 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
7797 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
7798 * submission parameters are collected from the DOM tree.</p>
7801 * @cfg {Object/Array} bbar
7802 * <p>The bottom toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
7803 * buttons/button configs to be added to the toolbar. Note that this is not available as a property after render.
7804 * To access the bottom toolbar after render, use {@link #getBottomToolbar}.</p>
7805 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
7806 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
7807 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
7808 * submission parameters are collected from the DOM tree.</p>
7810 /** @cfg {Object/Array} fbar
7811 * <p>A {@link Ext.Toolbar Toolbar} object, a Toolbar config, or an array of
7812 * {@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>
7813 * <p>After render, the <code>fbar</code> property will be an {@link Ext.Toolbar Toolbar} instance.</p>
7814 * <p>If <code>{@link #buttons}</code> are specified, they will supersede the <code>fbar</code> configuration property.</p>
7815 * The Panel's <code>{@link #buttonAlign}</code> configuration affects the layout of these items, for example:
7817 var w = new Ext.Window({
7820 bbar: new Ext.Toolbar({
7827 {@link #buttonAlign}: 'left', // anything but 'center' or 'right' and you can use '-', and '->'
7828 // to control the alignment of fbar items
7836 * <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
7837 * of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
7838 * so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
7839 * submission parameters are collected from the DOM tree.</p>
7842 * @cfg {Boolean} header
7843 * <code>true</code> to create the Panel's header element explicitly, <code>false</code> to skip creating
7844 * it. If a <code>{@link #title}</code> is set the header will be created automatically, otherwise it will not.
7845 * If a <code>{@link #title}</code> is set but <code>header</code> is explicitly set to <code>false</code>, the header
7846 * will not be rendered.
7849 * @cfg {Boolean} footer
7850 * <code>true</code> to create the footer element explicitly, false to skip creating it. The footer
7851 * will be created automatically if <code>{@link #buttons}</code> or a <code>{@link #fbar}</code> have
7852 * been configured. See <code>{@link #bodyCfg}</code> for an example.
7855 * @cfg {String} title
7856 * The title text to be used as innerHTML (html tags are accepted) to display in the panel
7857 * <code>{@link #header}</code> (defaults to ''). When a <code>title</code> is specified the
7858 * <code>{@link #header}</code> element will automatically be created and displayed unless
7859 * {@link #header} is explicitly set to <code>false</code>. If you do not want to specify a
7860 * <code>title</code> at config time, but you may want one later, you must either specify a non-empty
7861 * <code>title</code> (a blank space ' ' will do) or <code>header:true</code> so that the container
7862 * element will get created.
7865 * @cfg {Array} buttons
7866 * <code>buttons</code> will be used as <code>{@link Ext.Container#items items}</code> for the toolbar in
7867 * the footer (<code>{@link #fbar}</code>). Typically the value of this configuration property will be
7868 * an array of {@link Ext.Button}s or {@link Ext.Button} configuration objects.
7869 * If an item is configured with <code>minWidth</code> or the Panel is configured with <code>minButtonWidth</code>,
7870 * that width will be applied to the item.
7873 * @cfg {Object/String/Function} autoLoad
7874 * A valid url spec according to the Updater {@link Ext.Updater#update} method.
7875 * If autoLoad is not null, the panel will attempt to load its contents
7876 * immediately upon render.<p>
7877 * The URL will become the default URL for this panel's {@link #body} element,
7878 * so it may be {@link Ext.Element#refresh refresh}ed at any time.</p>
7881 * @cfg {Boolean} frame
7882 * <code>false</code> by default to render with plain 1px square borders. <code>true</code> to render with
7883 * 9 elements, complete with custom rounded corners (also see {@link Ext.Element#boxWrap}).
7884 * <p>The template generated for each condition is depicted below:</p><pre><code>
7887 <div id="developer-specified-id-goes-here" class="x-panel">
7889 <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:false)</span></div>
7891 <div class="x-panel-bwrap">
7892 <div class="x-panel-body"><p>html value goes here</p></div>
7896 // frame = true (create 9 elements)
7897 <div id="developer-specified-id-goes-here" class="x-panel">
7898 <div class="x-panel-tl"><div class="x-panel-tr"><div class="x-panel-tc">
7899 <div class="x-panel-header"><span class="x-panel-header-text">Title: (frame:true)</span></div>
7900 </div></div></div>
7902 <div class="x-panel-bwrap">
7903 <div class="x-panel-ml"><div class="x-panel-mr"><div class="x-panel-mc">
7904 <div class="x-panel-body"><p>html value goes here</p></div>
7905 </div></div></div>
7907 <div class="x-panel-bl"><div class="x-panel-br"><div class="x-panel-bc"/>
7908 </div></div></div>
7913 * @cfg {Boolean} border
7914 * True to display the borders of the panel's body element, false to hide them (defaults to true). By default,
7915 * the border is a 2px wide inset border, but this can be further altered by setting {@link #bodyBorder} to false.
7918 * @cfg {Boolean} bodyBorder
7919 * True to display an interior border on the body element of the panel, false to hide it (defaults to true).
7920 * This only applies when {@link #border} == true. If border == true and bodyBorder == false, the border will display
7921 * as a 1px wide inset border, giving the entire body element an inset appearance.
7924 * @cfg {String/Object/Function} bodyCssClass
7925 * Additional css class selector to be applied to the {@link #body} element in the format expected by
7926 * {@link Ext.Element#addClass} (defaults to null). See {@link #bodyCfg}.
7929 * @cfg {String/Object/Function} bodyStyle
7930 * Custom CSS styles to be applied to the {@link #body} element in the format expected by
7931 * {@link Ext.Element#applyStyles} (defaults to null). See {@link #bodyCfg}.
7934 * @cfg {String} iconCls
7935 * The CSS class selector that specifies a background image to be used as the header icon (defaults to '').
7936 * <p>An example of specifying a custom icon class would be something like:
7938 // specify the property in the config for the class:
7942 // css class that specifies background image to be used as the icon image:
7943 .my-icon { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
7947 * @cfg {Boolean} collapsible
7948 * True to make the panel collapsible and have the expand/collapse toggle button automatically rendered into
7949 * the header tool button area, false to keep the panel statically sized with no button (defaults to false).
7952 * @cfg {Array} tools
7953 * An array of tool button configs to be added to the header tool area. When rendered, each tool is
7954 * stored as an {@link Ext.Element Element} referenced by a public property called <code><b></b>tools.<i><tool-type></i></code>
7955 * <p>Each tool config may contain the following properties:
7956 * <div class="mdetail-params"><ul>
7957 * <li><b>id</b> : String<div class="sub-desc"><b>Required.</b> The type
7958 * of tool to create. By default, this assigns a CSS class of the form <code>x-tool-<i><tool-type></i></code> to the
7959 * resulting tool Element. Ext provides CSS rules, and an icon sprite containing images for the tool types listed below.
7960 * The developer may implement custom tools by supplying alternate CSS rules and background images:
7962 * <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>
7963 * <div class="x-tool x-tool-close" style="float:left; margin-right:5;"> </div><div><code> close</code></div>
7964 * <div class="x-tool x-tool-minimize" style="float:left; margin-right:5;"> </div><div><code> minimize</code></div>
7965 * <div class="x-tool x-tool-maximize" style="float:left; margin-right:5;"> </div><div><code> maximize</code></div>
7966 * <div class="x-tool x-tool-restore" style="float:left; margin-right:5;"> </div><div><code> restore</code></div>
7967 * <div class="x-tool x-tool-gear" style="float:left; margin-right:5;"> </div><div><code> gear</code></div>
7968 * <div class="x-tool x-tool-pin" style="float:left; margin-right:5;"> </div><div><code> pin</code></div>
7969 * <div class="x-tool x-tool-unpin" style="float:left; margin-right:5;"> </div><div><code> unpin</code></div>
7970 * <div class="x-tool x-tool-right" style="float:left; margin-right:5;"> </div><div><code> right</code></div>
7971 * <div class="x-tool x-tool-left" style="float:left; margin-right:5;"> </div><div><code> left</code></div>
7972 * <div class="x-tool x-tool-up" style="float:left; margin-right:5;"> </div><div><code> up</code></div>
7973 * <div class="x-tool x-tool-down" style="float:left; margin-right:5;"> </div><div><code> down</code></div>
7974 * <div class="x-tool x-tool-refresh" style="float:left; margin-right:5;"> </div><div><code> refresh</code></div>
7975 * <div class="x-tool x-tool-minus" style="float:left; margin-right:5;"> </div><div><code> minus</code></div>
7976 * <div class="x-tool x-tool-plus" style="float:left; margin-right:5;"> </div><div><code> plus</code></div>
7977 * <div class="x-tool x-tool-help" style="float:left; margin-right:5;"> </div><div><code> help</code></div>
7978 * <div class="x-tool x-tool-search" style="float:left; margin-right:5;"> </div><div><code> search</code></div>
7979 * <div class="x-tool x-tool-save" style="float:left; margin-right:5;"> </div><div><code> save</code></div>
7980 * <div class="x-tool x-tool-print" style="float:left; margin-right:5;"> </div><div><code> print</code></div>
7982 * <li><b>handler</b> : Function<div class="sub-desc"><b>Required.</b> The function to
7983 * call when clicked. Arguments passed are:<ul>
7984 * <li><b>event</b> : Ext.EventObject<div class="sub-desc">The click event.</div></li>
7985 * <li><b>toolEl</b> : Ext.Element<div class="sub-desc">The tool Element.</div></li>
7986 * <li><b>panel</b> : Ext.Panel<div class="sub-desc">The host Panel</div></li>
7987 * <li><b>tc</b> : Ext.Panel<div class="sub-desc">The tool configuration object</div></li>
7989 * <li><b>stopEvent</b> : Boolean<div class="sub-desc">Defaults to true. Specify as false to allow click event to propagate.</div></li>
7990 * <li><b>scope</b> : Object<div class="sub-desc">The scope in which to call the handler.</div></li>
7991 * <li><b>qtip</b> : String/Object<div class="sub-desc">A tip string, or
7992 * a config argument to {@link Ext.QuickTip#register}</div></li>
7993 * <li><b>hidden</b> : Boolean<div class="sub-desc">True to initially render hidden.</div></li>
7994 * <li><b>on</b> : Object<div class="sub-desc">A listener config object specifiying
7995 * event listeners in the format of an argument to {@link #addListener}</div></li>
7997 * <p>Note that, apart from the toggle tool which is provided when a panel is collapsible, these
7998 * tools only provide the visual button. Any required functionality must be provided by adding
7999 * handlers that implement the necessary behavior.</p>
8000 * <p>Example usage:</p>
8004 qtip: 'Refresh form Data',
8006 handler: function(event, toolEl, panel){
8013 handler: function(event, toolEl, panel){
8018 * <p>For the custom id of <code>'help'</code> define two relevant css classes with a link to
8019 * a 15x15 image:</p>
8021 .x-tool-help {background-image: url(images/help.png);}
8022 .x-tool-help-over {background-image: url(images/help_over.png);}
8023 // if using an image sprite:
8024 .x-tool-help {background-image: url(images/help.png) no-repeat 0 0;}
8025 .x-tool-help-over {background-position:-15px 0;}
8029 * @cfg {Ext.Template/Ext.XTemplate} toolTemplate
8030 * <p>A Template used to create {@link #tools} in the {@link #header} Element. Defaults to:</p><pre><code>
8031 new Ext.Template('<div class="x-tool x-tool-{id}">&#160;</div>')</code></pre>
8032 * <p>This may may be overridden to provide a custom DOM structure for tools based upon a more
8033 * complex XTemplate. The template's data is a single tool configuration object (Not the entire Array)
8034 * as specified in {@link #tools}. In the following example an <a> tag is used to provide a
8035 * visual indication when hovering over the tool:</p><pre><code>
8036 var win = new Ext.Window({
8039 href: '/MyPdfDoc.pdf'
8041 toolTemplate: new Ext.XTemplate(
8042 '<tpl if="id==\'download\'">',
8043 '<a class="x-tool x-tool-pdf" href="{href}"></a>',
8045 '<tpl if="id!=\'download\'">',
8046 '<div class="x-tool x-tool-{id}">&#160;</div>',
8053 * <p>Note that the CSS class 'x-tool-pdf' should have an associated style rule which provides an
8054 * appropriate background image, something like:</p>
8056 a.x-tool-pdf {background-image: url(../shared/extjs/images/pdf.gif)!important;}
8060 * @cfg {Boolean} hideCollapseTool
8061 * <code>true</code> to hide the expand/collapse toggle button when <code>{@link #collapsible} == true</code>,
8062 * <code>false</code> to display it (defaults to <code>false</code>).
8065 * @cfg {Boolean} titleCollapse
8066 * <code>true</code> to allow expanding and collapsing the panel (when <code>{@link #collapsible} = true</code>)
8067 * by clicking anywhere in the header bar, <code>false</code>) to allow it only by clicking to tool button
8068 * (defaults to <code>false</code>)). If this panel is a child item of a border layout also see the
8069 * {@link Ext.layout.BorderLayout.Region BorderLayout.Region}
8070 * <code>{@link Ext.layout.BorderLayout.Region#floatable floatable}</code> config option.
8073 * @cfg {Boolean} autoScroll
8074 * <code>true</code> to use overflow:'auto' on the panel's body element and show scroll bars automatically when
8075 * necessary, <code>false</code> to clip any overflowing content (defaults to <code>false</code>).
8078 * @cfg {Mixed} floating
8079 * <p>This property is used to configure the underlying {@link Ext.Layer}. Acceptable values for this
8080 * configuration property are:</p><div class="mdetail-params"><ul>
8081 * <li><b><code>false</code></b> : <b>Default.</b><div class="sub-desc">Display the panel inline where it is
8082 * rendered.</div></li>
8083 * <li><b><code>true</code></b> : <div class="sub-desc">Float the panel (absolute position it with automatic
8084 * shimming and shadow).<ul>
8085 * <div class="sub-desc">Setting floating to true will create an Ext.Layer for this panel and display the
8086 * panel at negative offsets so that it is hidden.</div>
8087 * <div class="sub-desc">Since the panel will be absolute positioned, the position must be set explicitly
8088 * <i>after</i> render (e.g., <code>myPanel.setPosition(100,100);</code>).</div>
8089 * <div class="sub-desc"><b>Note</b>: when floating a panel you should always assign a fixed width,
8090 * otherwise it will be auto width and will expand to fill to the right edge of the viewport.</div>
8092 * <li><b><code>{@link Ext.Layer object}</code></b> : <div class="sub-desc">The specified object will be used
8093 * as the configuration object for the {@link Ext.Layer} that will be created.</div></li>
8097 * @cfg {Boolean/String} shadow
8098 * <code>true</code> (or a valid Ext.Shadow {@link Ext.Shadow#mode} value) to display a shadow behind the
8099 * panel, <code>false</code> to display no shadow (defaults to <code>'sides'</code>). Note that this option
8100 * only applies when <code>{@link #floating} = true</code>.
8103 * @cfg {Number} shadowOffset
8104 * The number of pixels to offset the shadow if displayed (defaults to <code>4</code>). Note that this
8105 * option only applies when <code>{@link #floating} = true</code>.
8108 * @cfg {Boolean} shim
8109 * <code>false</code> to disable the iframe shim in browsers which need one (defaults to <code>true</code>).
8110 * Note that this option only applies when <code>{@link #floating} = true</code>.
8113 * @cfg {String/Object} html
8114 * An HTML fragment, or a {@link Ext.DomHelper DomHelper} specification to use as the panel's body
8115 * content (defaults to ''). The HTML content is added by the Panel's {@link #afterRender} method,
8116 * and so the document will not contain this HTML at the time the {@link #render} event is fired.
8117 * This content is inserted into the body <i>before</i> any configured {@link #contentEl} is appended.
8120 * @cfg {String} contentEl
8121 * <p>Optional. Specify an existing HTML element, or the <code>id</code> of an existing HTML element to use as this Panel's
8122 * <code><b>{@link #body}</b></code> content.</p>
8124 * <li><b>Description</b> :
8125 * <div class="sub-desc">This config option is used to take an existing HTML element and place it in the body
8126 * of a new panel (it simply moves the specified DOM element into the body element of the Panel
8127 * <i>after the Panel is rendered</i> to use as the content (it is not going to be the actual panel itself).</div></li>
8128 * <li><b>Notes</b> :
8129 * <div class="sub-desc">The specified HTML element is appended to the Panel's {@link #body} Element by the
8130 * Panel's <code>afterRender</code> method <i>after any configured {@link #html HTML} has
8131 * been inserted</i>, and so the document will not contain this element at the time the
8132 * {@link #render} event is fired.</div>
8133 * <div class="sub-desc">The specified HTML element used will not participate in any <code><b>{@link Ext.Container#layout layout}</b></code>
8134 * scheme that the Panel may use. It is just HTML. Layouts operate on child <code><b>{@link Ext.Container#items items}</b></code>.</div>
8135 * <div class="sub-desc">Add either the <code>x-hidden</code> or the <code>x-hide-display</code> CSS class to
8136 * prevent a brief flicker of the content before it is rendered to the panel.</div></li>
8140 * @cfg {Object/Array} keys
8141 * A {@link Ext.KeyMap} config object (in the format expected by {@link Ext.KeyMap#addBinding}
8142 * used to assign custom key handling to this panel (defaults to <code>null</code>).
8145 * @cfg {Boolean/Object} draggable
8146 * <p><code>true</code> to enable dragging of this Panel (defaults to <code>false</code>).</p>
8147 * <p>For custom drag/drop implementations, an <b>Ext.Panel.DD</b> config could also be passed
8148 * in this config instead of <code>true</code>. Ext.Panel.DD is an internal, undocumented class which
8149 * moves a proxy Element around in place of the Panel's element, but provides no other behaviour
8150 * during dragging or on drop. It is a subclass of {@link Ext.dd.DragSource}, so behaviour may be
8151 * added by implementing the interface methods of {@link Ext.dd.DragDrop} e.g.:
8157 renderTo: Ext.getBody(),
8163 // Config option of Ext.Panel.DD class.
8164 // It's a floating Panel, so do not show a placeholder proxy in the original position.
8167 // Called for each mousemove event while dragging the DD object.
8168 onDrag : function(e){
8169 // Record the x,y position of the drag proxy so that we can
8170 // position the Panel at end of drag.
8171 var pel = this.proxy.getEl();
8172 this.x = pel.getLeft(true);
8173 this.y = pel.getTop(true);
8175 // Keep the Shadow aligned if there is one.
8176 var s = this.panel.getEl().shadow;
8178 s.realign(this.x, this.y, pel.getWidth(), pel.getHeight());
8182 // Called on the mouseup event.
8183 endDrag : function(e){
8184 this.panel.setPosition(this.x, this.y);
8191 * @cfg {Boolean} disabled
8192 * Render this panel disabled (default is <code>false</code>). An important note when using the disabled
8193 * config on panels is that IE will often fail to initialize the disabled mask element correectly if
8194 * the panel's layout has not yet completed by the time the Panel is disabled during the render process.
8195 * If you experience this issue, you may need to instead use the {@link #afterlayout} event to initialize
8196 * the disabled state:
8205 single: true // important, as many layouts can occur
8212 * @cfg {Boolean} autoHeight
8213 * <code>true</code> to use height:'auto', <code>false</code> to use fixed height (defaults to <code>false</code>).
8214 * <b>Note</b>: Setting <code>autoHeight: true</code> means that the browser will manage the panel's height
8215 * based on its contents, and that Ext will not manage it at all. If the panel is within a layout that
8216 * manages dimensions (<code>fit</code>, <code>border</code>, etc.) then setting <code>autoHeight: true</code>
8217 * can cause issues with scrolling and will not generally work as expected since the panel will take
8218 * on the height of its contents rather than the height required by the Ext layout.
8223 * @cfg {String} baseCls
8224 * The base CSS class to apply to this panel's element (defaults to <code>'x-panel'</code>).
8225 * <p>Another option available by default is to specify <code>'x-plain'</code> which strips all styling
8226 * except for required attributes for Ext layouts to function (e.g. overflow:hidden).
8227 * See <code>{@link #unstyled}</code> also.</p>
8229 baseCls : 'x-panel',
8231 * @cfg {String} collapsedCls
8232 * A CSS class to add to the panel's element after it has been collapsed (defaults to
8233 * <code>'x-panel-collapsed'</code>).
8235 collapsedCls : 'x-panel-collapsed',
8237 * @cfg {Boolean} maskDisabled
8238 * <code>true</code> to mask the panel when it is {@link #disabled}, <code>false</code> to not mask it (defaults
8239 * to <code>true</code>). Either way, the panel will always tell its contained elements to disable themselves
8240 * when it is disabled, but masking the panel can provide an additional visual cue that the panel is
8243 maskDisabled : true,
8245 * @cfg {Boolean} animCollapse
8246 * <code>true</code> to animate the transition when the panel is collapsed, <code>false</code> to skip the
8247 * animation (defaults to <code>true</code> if the {@link Ext.Fx} class is available, otherwise <code>false</code>).
8249 animCollapse : Ext.enableFx,
8251 * @cfg {Boolean} headerAsText
8252 * <code>true</code> to display the panel <code>{@link #title}</code> in the <code>{@link #header}</code>,
8253 * <code>false</code> to hide it (defaults to <code>true</code>).
8255 headerAsText : true,
8257 * @cfg {String} buttonAlign
8258 * The alignment of any {@link #buttons} added to this panel. Valid values are <code>'right'</code>,
8259 * <code>'left'</code> and <code>'center'</code> (defaults to <code>'right'</code>).
8261 buttonAlign : 'right',
8263 * @cfg {Boolean} collapsed
8264 * <code>true</code> to render the panel collapsed, <code>false</code> to render it expanded (defaults to
8265 * <code>false</code>).
8269 * @cfg {Boolean} collapseFirst
8270 * <code>true</code> to make sure the collapse/expand toggle button always renders first (to the left of)
8271 * any other tools in the panel's title bar, <code>false</code> to render it last (defaults to <code>true</code>).
8273 collapseFirst : true,
8275 * @cfg {Number} minButtonWidth
8276 * Minimum width in pixels of all {@link #buttons} in this panel (defaults to <code>75</code>)
8278 minButtonWidth : 75,
8280 * @cfg {Boolean} unstyled
8281 * Overrides the <code>{@link #baseCls}</code> setting to <code>{@link #baseCls} = 'x-plain'</code> which renders
8282 * the panel unstyled except for required attributes for Ext layouts to function (e.g. overflow:hidden).
8285 * @cfg {String} elements
8286 * A comma-delimited list of panel elements to initialize when the panel is rendered. Normally, this list will be
8287 * generated automatically based on the items added to the panel at config time, but sometimes it might be useful to
8288 * make sure a structural element is rendered even if not specified at config time (for example, you may want
8289 * to add a button or toolbar dynamically after the panel has been rendered). Adding those elements to this
8290 * list will allocate the required placeholders in the panel when it is rendered. Valid values are<div class="mdetail-params"><ul>
8291 * <li><code>header</code></li>
8292 * <li><code>tbar</code> (top bar)</li>
8293 * <li><code>body</code></li>
8294 * <li><code>bbar</code> (bottom bar)</li>
8295 * <li><code>footer</code></li>
8297 * Defaults to '<code>body</code>'.
8301 * @cfg {Boolean} preventBodyReset
8302 * Defaults to <code>false</code>. When set to <code>true</code>, an extra css class <code>'x-panel-normal'</code>
8303 * will be added to the panel's element, effectively applying css styles suggested by the W3C
8304 * (see http://www.w3.org/TR/CSS21/sample.html) to the Panel's <b>body</b> element (not the header,
8307 preventBodyReset : false,
8309 /** @cfg {String} resizeEvent
8310 * The event to listen to for resizing in layouts. Defaults to <tt>'bodyresize'</tt>.
8312 resizeEvent: 'bodyresize',
8314 // protected - these could be used to customize the behavior of the window,
8315 // but changing them would not be useful without further mofifications and
8316 // could lead to unexpected or undesirable results.
8317 toolTarget : 'header',
8318 collapseEl : 'bwrap',
8322 // private, notify box this class will handle heights
8329 collapseDefaults : {
8334 initComponent : function(){
8335 Ext.Panel.superclass.initComponent.call(this);
8340 * Fires after the Panel has been resized.
8341 * @param {Ext.Panel} p the Panel which has been resized.
8342 * @param {Number} width The Panel's new width.
8343 * @param {Number} height The Panel's new height.
8347 * @event titlechange
8348 * Fires after the Panel title has been {@link #title set} or {@link #setTitle changed}.
8349 * @param {Ext.Panel} p the Panel which has had its title changed.
8350 * @param {String} The new title.
8355 * Fires after the Panel icon class has been {@link #iconCls set} or {@link #setIconClass changed}.
8356 * @param {Ext.Panel} p the Panel which has had its {@link #iconCls icon class} changed.
8357 * @param {String} The new icon class.
8358 * @param {String} The old icon class.
8363 * Fires after the Panel has been collapsed.
8364 * @param {Ext.Panel} p the Panel that has been collapsed.
8369 * Fires after the Panel has been expanded.
8370 * @param {Ext.Panel} p The Panel that has been expanded.
8374 * @event beforecollapse
8375 * Fires before the Panel is collapsed. A handler can return false to cancel the collapse.
8376 * @param {Ext.Panel} p the Panel being collapsed.
8377 * @param {Boolean} animate True if the collapse is animated, else false.
8381 * @event beforeexpand
8382 * Fires before the Panel is expanded. A handler can return false to cancel the expand.
8383 * @param {Ext.Panel} p The Panel being expanded.
8384 * @param {Boolean} animate True if the expand is animated, else false.
8388 * @event beforeclose
8389 * Fires before the Panel is closed. Note that Panels do not directly support being closed, but some
8390 * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel. This event only
8391 * applies to such subclasses.
8392 * A handler can return false to cancel the close.
8393 * @param {Ext.Panel} p The Panel being closed.
8398 * Fires after the Panel is closed. Note that Panels do not directly support being closed, but some
8399 * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel.
8400 * @param {Ext.Panel} p The Panel that has been closed.
8405 * Fires after the Panel has been visually activated.
8406 * Note that Panels do not directly support being activated, but some Panel subclasses
8407 * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
8408 * activate and deactivate events under the control of the TabPanel.
8409 * @param {Ext.Panel} p The Panel that has been activated.
8414 * Fires after the Panel has been visually deactivated.
8415 * Note that Panels do not directly support being deactivated, but some Panel subclasses
8416 * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
8417 * activate and deactivate events under the control of the TabPanel.
8418 * @param {Ext.Panel} p The Panel that has been deactivated.
8424 this.baseCls = 'x-plain';
8429 this.elements += ',tbar';
8430 if(Ext.isObject(this.tbar)){
8431 this.topToolbar = this.tbar;
8436 this.elements += ',bbar';
8437 if(Ext.isObject(this.bbar)){
8438 this.bottomToolbar = this.bbar;
8443 if(this.header === true){
8444 this.elements += ',header';
8446 }else if(this.headerCfg || (this.title && this.header !== false)){
8447 this.elements += ',header';
8450 if(this.footerCfg || this.footer === true){
8451 this.elements += ',footer';
8456 this.elements += ',footer';
8457 var btns = this.buttons;
8459 * This Panel's Array of buttons as created from the <code>{@link #buttons}</code>
8460 * config property. Read only.
8465 Ext.each(btns, function(btn){
8466 if(btn.render){ // button instance
8467 this.buttons.push(btn);
8468 }else if(btn.xtype){
8469 this.buttons.push(Ext.create(btn, 'button'));
8471 this.addButton(btn);
8476 this.elements += ',footer';
8479 this.on('render', this.doAutoLoad, this, {delay:10});
8484 createElement : function(name, pnode){
8486 pnode.appendChild(this[name].dom);
8490 if(name === 'bwrap' || this.elements.indexOf(name) != -1){
8491 if(this[name+'Cfg']){
8492 this[name] = Ext.fly(pnode).createChild(this[name+'Cfg']);
8494 var el = document.createElement('div');
8495 el.className = this[name+'Cls'];
8496 this[name] = Ext.get(pnode.appendChild(el));
8498 if(this[name+'CssClass']){
8499 this[name].addClass(this[name+'CssClass']);
8501 if(this[name+'Style']){
8502 this[name].applyStyles(this[name+'Style']);
8508 onRender : function(ct, position){
8509 Ext.Panel.superclass.onRender.call(this, ct, position);
8510 this.createClasses();
8518 if(this.collapsible && !this.hideCollapseTool){
8519 this.tools = this.tools ? this.tools.slice(0) : [];
8520 this.tools[this.collapseFirst?'unshift':'push']({
8522 handler : this.toggleCollapse,
8529 this.elements += (this.header !== false) ? ',header' : '';
8533 el.addClass(this.baseCls);
8534 if(d.firstChild){ // existing markup
8535 this.header = el.down('.'+this.headerCls);
8536 this.bwrap = el.down('.'+this.bwrapCls);
8537 var cp = this.bwrap ? this.bwrap : el;
8538 this.tbar = cp.down('.'+this.tbarCls);
8539 this.body = cp.down('.'+this.bodyCls);
8540 this.bbar = cp.down('.'+this.bbarCls);
8541 this.footer = cp.down('.'+this.footerCls);
8542 this.fromMarkup = true;
8544 if (this.preventBodyReset === true) {
8545 el.addClass('x-panel-reset');
8548 el.addClass(this.cls);
8552 this.elements += ',footer';
8555 // This block allows for maximum flexibility and performance when using existing markup
8557 // framing requires special markup
8559 el.insertHtml('afterBegin', String.format(Ext.Element.boxMarkup, this.baseCls));
8561 this.createElement('header', d.firstChild.firstChild.firstChild);
8562 this.createElement('bwrap', d);
8564 // append the mid and bottom frame to the bwrap
8565 bw = this.bwrap.dom;
8566 var ml = d.childNodes[1], bl = d.childNodes[2];
8570 var mc = bw.firstChild.firstChild.firstChild;
8571 this.createElement('tbar', mc);
8572 this.createElement('body', mc);
8573 this.createElement('bbar', mc);
8574 this.createElement('footer', bw.lastChild.firstChild.firstChild);
8577 this.bwrap.dom.lastChild.className += ' x-panel-nofooter';
8580 * Store a reference to this element so:
8581 * a) We aren't looking it up all the time
8582 * b) The last element is reported incorrectly when using a loadmask
8584 this.ft = Ext.get(this.bwrap.dom.lastChild);
8585 this.mc = Ext.get(this.bwrap.dom.firstChild.firstChild.firstChild);
8587 this.createElement('header', d);
8588 this.createElement('bwrap', d);
8590 // append the mid and bottom frame to the bwrap
8591 bw = this.bwrap.dom;
8592 this.createElement('tbar', bw);
8593 this.createElement('body', bw);
8594 this.createElement('bbar', bw);
8595 this.createElement('footer', bw);
8598 this.body.addClass(this.bodyCls + '-noheader');
8600 this.tbar.addClass(this.tbarCls + '-noheader');
8605 if(Ext.isDefined(this.padding)){
8606 this.body.setStyle('padding', this.body.addUnits(this.padding));
8609 if(this.border === false){
8610 this.el.addClass(this.baseCls + '-noborder');
8611 this.body.addClass(this.bodyCls + '-noborder');
8613 this.header.addClass(this.headerCls + '-noborder');
8616 this.footer.addClass(this.footerCls + '-noborder');
8619 this.tbar.addClass(this.tbarCls + '-noborder');
8622 this.bbar.addClass(this.bbarCls + '-noborder');
8626 if(this.bodyBorder === false){
8627 this.body.addClass(this.bodyCls + '-noborder');
8630 this.bwrap.enableDisplayMode('block');
8633 this.header.unselectable();
8635 // for tools, we need to wrap any existing header markup
8636 if(this.headerAsText){
8637 this.header.dom.innerHTML =
8638 '<span class="' + this.headerTextCls + '">'+this.header.dom.innerHTML+'</span>';
8641 this.setIconClass(this.iconCls);
8647 this.makeFloating(this.floating);
8650 if(this.collapsible && this.titleCollapse && this.header){
8651 this.mon(this.header, 'click', this.toggleCollapse, this);
8652 this.header.setStyle('cursor', 'pointer');
8655 this.addTool.apply(this, ts);
8658 if(this.buttons && this.buttons.length > 0){
8659 this.fbar = new Ext.Toolbar({
8660 items: this.buttons,
8661 toolbarCls: 'x-panel-fbar'
8666 this.fbar = Ext.create(this.fbar, 'toolbar');
8667 this.fbar.enableOverflow = false;
8668 if(this.fbar.items){
8669 this.fbar.items.each(function(c){
8670 c.minWidth = c.minWidth || this.minButtonWidth;
8673 this.fbar.toolbarCls = 'x-panel-fbar';
8675 var bct = this.footer.createChild({cls: 'x-panel-btns x-panel-btns-'+this.buttonAlign});
8676 this.fbar.ownerCt = this;
8677 this.fbar.render(bct);
8678 bct.createChild({cls:'x-clear'});
8679 this.toolbars.push(this.fbar);
8682 if(this.tbar && this.topToolbar){
8683 if(Ext.isArray(this.topToolbar)){
8684 this.topToolbar = new Ext.Toolbar(this.topToolbar);
8685 }else if(!this.topToolbar.events){
8686 this.topToolbar = Ext.create(this.topToolbar, 'toolbar');
8688 this.topToolbar.ownerCt = this;
8689 this.topToolbar.render(this.tbar);
8690 this.toolbars.push(this.topToolbar);
8692 if(this.bbar && this.bottomToolbar){
8693 if(Ext.isArray(this.bottomToolbar)){
8694 this.bottomToolbar = new Ext.Toolbar(this.bottomToolbar);
8695 }else if(!this.bottomToolbar.events){
8696 this.bottomToolbar = Ext.create(this.bottomToolbar, 'toolbar');
8698 this.bottomToolbar.ownerCt = this;
8699 this.bottomToolbar.render(this.bbar);
8700 this.toolbars.push(this.bottomToolbar);
8705 * Sets the CSS class that provides the icon image for this panel. This method will replace any existing
8706 * icon class if one has already been set and fire the {@link #iconchange} event after completion.
8707 * @param {String} cls The new CSS class name
8709 setIconClass : function(cls){
8710 var old = this.iconCls;
8712 if(this.rendered && this.header){
8714 this.header.addClass('x-panel-icon');
8715 this.header.replaceClass(old, this.iconCls);
8717 var hd = this.header,
8718 img = hd.child('img.x-panel-inline-icon');
8720 Ext.fly(img).replaceClass(old, this.iconCls);
8722 Ext.DomHelper.insertBefore(hd.dom.firstChild, {
8723 tag:'img', src: Ext.BLANK_IMAGE_URL, cls:'x-panel-inline-icon '+this.iconCls
8728 this.fireEvent('iconchange', this, cls, old);
8732 makeFloating : function(cfg){
8733 this.floating = true;
8734 this.el = new Ext.Layer(
8735 Ext.isObject(cfg) ? cfg : {
8736 shadow: Ext.isDefined(this.shadow) ? this.shadow : 'sides',
8737 shadowOffset: this.shadowOffset,
8739 shim: this.shim === false ? false : undefined
8745 * Returns the {@link Ext.Toolbar toolbar} from the top (<code>{@link #tbar}</code>) section of the panel.
8746 * @return {Ext.Toolbar} The toolbar
8748 getTopToolbar : function(){
8749 return this.topToolbar;
8753 * Returns the {@link Ext.Toolbar toolbar} from the bottom (<code>{@link #bbar}</code>) section of the panel.
8754 * @return {Ext.Toolbar} The toolbar
8756 getBottomToolbar : function(){
8757 return this.bottomToolbar;
8761 * Adds a button to this panel. Note that this method must be called prior to rendering. The preferred
8762 * approach is to add buttons via the {@link #buttons} config.
8763 * @param {String/Object} config A valid {@link Ext.Button} config. A string will become the text for a default
8764 * button config, an object will be treated as a button config object.
8765 * @param {Function} handler The function to be called on button {@link Ext.Button#click}
8766 * @param {Object} scope The scope to use for the button handler function
8767 * @return {Ext.Button} The button that was added
8769 addButton : function(config, handler, scope){
8773 minWidth: this.minButtonWidth,
8776 if(Ext.isString(config)){
8779 Ext.apply(bc, config);
8781 var btn = new Ext.Button(bc);
8785 this.buttons.push(btn);
8790 addTool : function(){
8795 Ext.each(arguments, function(arg){
8796 this.tools.push(arg)
8800 // nowhere to render tools!
8801 if(!this[this.toolTarget]){
8804 if(!this.toolTemplate){
8805 // initialize the global tool template on first use
8806 var tt = new Ext.Template(
8807 '<div class="x-tool x-tool-{id}"> </div>'
8809 tt.disableFormats = true;
8811 Ext.Panel.prototype.toolTemplate = tt;
8813 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
8815 if(!this.tools[tc.id]){
8816 var overCls = 'x-tool-'+tc.id+'-over';
8817 var t = this.toolTemplate.insertFirst((tc.align !== 'left') ? this[this.toolTarget] : this[this.toolTarget].child('span'), tc, true);
8818 this.tools[tc.id] = t;
8819 t.enableDisplayMode('block');
8820 this.mon(t, 'click', this.createToolHandler(t, tc, overCls, this));
8828 if(Ext.isObject(tc.qtip)){
8829 Ext.QuickTips.register(Ext.apply({
8833 t.dom.qtip = tc.qtip;
8836 t.addClassOnOver(overCls);
8841 onLayout : function(shallow, force){
8842 if(this.hasLayout && this.toolbars.length > 0){
8843 Ext.each(this.toolbars, function(tb){
8844 tb.doLayout(undefined, force);
8850 syncHeight : function(){
8851 var h = this.toolbarHeight,
8853 lsh = this.lastSize.height;
8855 if(this.autoHeight || !Ext.isDefined(lsh) || lsh == 'auto'){
8860 if(h != this.getToolbarHeight()){
8861 h = Math.max(0, this.adjustBodyHeight(lsh - this.getFrameHeight()));
8864 this.toolbarHeight = this.getToolbarHeight();
8865 this.onBodyResize(sz.width, sz.height);
8870 onShow : function(){
8872 return this.el.show();
8874 Ext.Panel.superclass.onShow.call(this);
8878 onHide : function(){
8880 return this.el.hide();
8882 Ext.Panel.superclass.onHide.call(this);
8886 createToolHandler : function(t, tc, overCls, panel){
8888 t.removeClass(overCls);
8889 if(tc.stopEvent !== false){
8893 tc.handler.call(tc.scope || t, e, t, panel, tc);
8899 afterRender : function(){
8900 if(this.floating && !this.hidden){
8904 this.setTitle(this.title);
8906 this.setAutoScroll();
8908 this.body.update(Ext.isObject(this.html) ?
8909 Ext.DomHelper.markup(this.html) :
8914 var ce = Ext.getDom(this.contentEl);
8915 Ext.fly(ce).removeClass(['x-hidden', 'x-hide-display']);
8916 this.body.dom.appendChild(ce);
8919 this.collapsed = false;
8920 this.collapse(false);
8922 Ext.Panel.superclass.afterRender.call(this); // do sizing calcs last
8927 setAutoScroll : function(){
8928 if(this.rendered && this.autoScroll){
8929 var el = this.body || this.el;
8931 el.setOverflow('auto');
8937 getKeyMap : function(){
8939 this.keyMap = new Ext.KeyMap(this.el, this.keys);
8945 initEvents : function(){
8950 this.initDraggable();
8952 if(this.toolbars.length > 0){
8953 Ext.each(this.toolbars, function(tb){
8957 afterlayout: this.syncHeight,
8958 remove: this.syncHeight
8968 initDraggable : function(){
8970 * <p>If this Panel is configured {@link #draggable}, this property will contain
8971 * an instance of {@link Ext.dd.DragSource} which handles dragging the Panel.</p>
8972 * The developer must provide implementations of the abstract methods of {@link Ext.dd.DragSource}
8973 * in order to supply behaviour for each stage of the drag/drop process. See {@link #draggable}.
8974 * @type Ext.dd.DragSource.
8977 this.dd = new Ext.Panel.DD(this, Ext.isBoolean(this.draggable) ? null : this.draggable);
8981 beforeEffect : function(anim){
8983 this.el.beforeAction();
8986 this.el.addClass('x-panel-animated');
8991 afterEffect : function(anim){
8994 this.el.removeClass('x-panel-animated');
8998 // private - wraps up an animation param with internal callbacks
8999 createEffect : function(a, cb, scope){
9007 }else if(!a.callback){
9009 }else { // wrap it up
9010 o.callback = function(){
9012 Ext.callback(a.callback, a.scope);
9015 return Ext.applyIf(o, a);
9019 * Collapses the panel body so that it becomes hidden. Fires the {@link #beforecollapse} event which will
9020 * cancel the collapse action if it returns false.
9021 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
9022 * {@link #animCollapse} panel config)
9023 * @return {Ext.Panel} this
9025 collapse : function(animate){
9026 if(this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforecollapse', this, animate) === false){
9029 var doAnim = animate === true || (animate !== false && this.animCollapse);
9030 this.beforeEffect(doAnim);
9031 this.onCollapse(doAnim, animate);
9036 onCollapse : function(doAnim, animArg){
9038 this[this.collapseEl].slideOut(this.slideAnchor,
9039 Ext.apply(this.createEffect(animArg||true, this.afterCollapse, this),
9040 this.collapseDefaults));
9042 this[this.collapseEl].hide();
9043 this.afterCollapse(false);
9048 afterCollapse : function(anim){
9049 this.collapsed = true;
9050 this.el.addClass(this.collapsedCls);
9051 this.afterEffect(anim);
9052 this.fireEvent('collapse', this);
9056 * Expands the panel body so that it becomes visible. Fires the {@link #beforeexpand} event which will
9057 * cancel the expand action if it returns false.
9058 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
9059 * {@link #animCollapse} panel config)
9060 * @return {Ext.Panel} this
9062 expand : function(animate){
9063 if(!this.collapsed || this.el.hasFxBlock() || this.fireEvent('beforeexpand', this, animate) === false){
9066 var doAnim = animate === true || (animate !== false && this.animCollapse);
9067 this.el.removeClass(this.collapsedCls);
9068 this.beforeEffect(doAnim);
9069 this.onExpand(doAnim, animate);
9074 onExpand : function(doAnim, animArg){
9076 this[this.collapseEl].slideIn(this.slideAnchor,
9077 Ext.apply(this.createEffect(animArg||true, this.afterExpand, this),
9078 this.expandDefaults));
9080 this[this.collapseEl].show();
9081 this.afterExpand(false);
9086 afterExpand : function(anim){
9087 this.collapsed = false;
9088 this.afterEffect(anim);
9089 if(Ext.isDefined(this.deferLayout)){
9090 this.doLayout(true);
9092 this.fireEvent('expand', this);
9096 * Shortcut for performing an {@link #expand} or {@link #collapse} based on the current state of the panel.
9097 * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
9098 * {@link #animCollapse} panel config)
9099 * @return {Ext.Panel} this
9101 toggleCollapse : function(animate){
9102 this[this.collapsed ? 'expand' : 'collapse'](animate);
9107 onDisable : function(){
9108 if(this.rendered && this.maskDisabled){
9111 Ext.Panel.superclass.onDisable.call(this);
9115 onEnable : function(){
9116 if(this.rendered && this.maskDisabled){
9119 Ext.Panel.superclass.onEnable.call(this);
9123 onResize : function(w, h){
9124 if(Ext.isDefined(w) || Ext.isDefined(h)){
9125 if(!this.collapsed){
9126 if(Ext.isNumber(w)){
9127 w = this.adjustBodyWidth(w - this.getFrameWidth());
9129 this.tbar.setWidth(w);
9130 if(this.topToolbar){
9131 this.topToolbar.setSize(w);
9135 this.bbar.setWidth(w);
9136 if(this.bottomToolbar){
9137 this.bottomToolbar.setSize(w);
9143 strict = Ext.isStrict;
9144 if(this.buttonAlign == 'left'){
9145 fWidth = w - f.container.getFrameWidth('lr');
9147 //center/right alignment off in webkit
9148 if(Ext.isIE || Ext.isWebKit){
9149 //center alignment ok on webkit.
9150 //right broken in both, center on IE
9151 if(!(this.buttonAlign == 'center' && Ext.isWebKit) && (!strict || (!Ext.isIE8 && strict))){
9153 f.setWidth(f.getEl().child('.x-toolbar-ct').getWidth());
9164 this.body.setWidth(w);
9165 }else if(w == 'auto'){
9166 this.body.setWidth(w);
9169 if(Ext.isNumber(h)){
9170 h = Math.max(0, this.adjustBodyHeight(h - this.getFrameHeight()));
9171 this.body.setHeight(h);
9172 }else if(h == 'auto'){
9173 this.body.setHeight(h);
9176 if(this.disabled && this.el._mask){
9177 this.el._mask.setSize(this.el.dom.clientWidth, this.el.getHeight());
9180 this.queuedBodySize = {width: w, height: h};
9181 if(!this.queuedExpand && this.allowQueuedExpand !== false){
9182 this.queuedExpand = true;
9183 this.on('expand', function(){
9184 delete this.queuedExpand;
9185 this.onResize(this.queuedBodySize.width, this.queuedBodySize.height);
9187 }, this, {single:true});
9190 this.onBodyResize(w, h);
9196 onBodyResize: function(w, h){
9197 this.fireEvent('bodyresize', this, w, h);
9201 getToolbarHeight: function(){
9204 Ext.each(this.toolbars, function(tb){
9205 h += tb.getHeight();
9212 adjustBodyHeight : function(h){
9217 adjustBodyWidth : function(w){
9222 onPosition : function(){
9227 * Returns the width in pixels of the framing elements of this panel (not including the body width). To
9228 * retrieve the body width see {@link #getInnerWidth}.
9229 * @return {Number} The frame width
9231 getFrameWidth : function(){
9232 var w = this.el.getFrameWidth('lr') + this.bwrap.getFrameWidth('lr');
9235 var l = this.bwrap.dom.firstChild;
9236 w += (Ext.fly(l).getFrameWidth('l') + Ext.fly(l.firstChild).getFrameWidth('r'));
9237 w += this.mc.getFrameWidth('lr');
9243 * Returns the height in pixels of the framing elements of this panel (including any top and bottom bars and
9244 * header and footer elements, but not including the body height). To retrieve the body height see {@link #getInnerHeight}.
9245 * @return {Number} The frame height
9247 getFrameHeight : function(){
9248 var h = this.el.getFrameWidth('tb') + this.bwrap.getFrameWidth('tb');
9249 h += (this.tbar ? this.tbar.getHeight() : 0) +
9250 (this.bbar ? this.bbar.getHeight() : 0);
9253 h += this.el.dom.firstChild.offsetHeight + this.ft.dom.offsetHeight + this.mc.getFrameWidth('tb');
9255 h += (this.header ? this.header.getHeight() : 0) +
9256 (this.footer ? this.footer.getHeight() : 0);
9262 * Returns the width in pixels of the body element (not including the width of any framing elements).
9263 * For the frame width see {@link #getFrameWidth}.
9264 * @return {Number} The body width
9266 getInnerWidth : function(){
9267 return this.getSize().width - this.getFrameWidth();
9271 * Returns the height in pixels of the body element (not including the height of any framing elements).
9272 * For the frame height see {@link #getFrameHeight}.
9273 * @return {Number} The body height
9275 getInnerHeight : function(){
9276 return this.getSize().height - this.getFrameHeight();
9280 syncShadow : function(){
9287 getLayoutTarget : function(){
9292 * <p>Sets the title text for the panel and optionally the {@link #iconCls icon class}.</p>
9293 * <p>In order to be able to set the title, a header element must have been created
9294 * for the Panel. This is triggered either by configuring the Panel with a non-blank <code>{@link #title}</code>,
9295 * or configuring it with <code><b>{@link #header}: true</b></code>.</p>
9296 * @param {String} title The title text to set
9297 * @param {String} iconCls (optional) {@link #iconCls iconCls} A user-defined CSS class that provides the icon image for this panel
9299 setTitle : function(title, iconCls){
9301 if(this.header && this.headerAsText){
9302 this.header.child('span').update(title);
9305 this.setIconClass(iconCls);
9307 this.fireEvent('titlechange', this, title);
9312 * Get the {@link Ext.Updater} for this panel. Enables you to perform Ajax updates of this panel's body.
9313 * @return {Ext.Updater} The Updater
9315 getUpdater : function(){
9316 return this.body.getUpdater();
9320 * Loads this content panel immediately with content returned from an XHR call.
9321 * @param {Object/String/Function} config A config object containing any of the following options:
9324 url: 'your-url.php',
9325 params: {param1: 'foo', param2: 'bar'}, // or a URL encoded string
9326 callback: yourFunction,
9327 scope: yourObject, // optional scope for the callback
9335 * The only required property is url. The optional properties nocache, text and scripts
9336 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their
9337 * associated property on this panel Updater instance.
9338 * @return {Ext.Panel} this
9341 var um = this.body.getUpdater();
9342 um.update.apply(um, arguments);
9347 beforeDestroy : function(){
9349 this.header.removeAllListeners();
9350 if(this.headerAsText){
9351 Ext.Element.uncache(this.header.child('span'));
9354 Ext.Element.uncache(
9365 for(var k in this.tools){
9366 Ext.destroy(this.tools[k]);
9370 for(var b in this.buttons){
9371 Ext.destroy(this.buttons[b]);
9375 Ext.destroy(this.toolbars);
9377 Ext.destroy(this.topToolbar, this.bottomToolbar);
9379 Ext.Panel.superclass.beforeDestroy.call(this);
9383 createClasses : function(){
9384 this.headerCls = this.baseCls + '-header';
9385 this.headerTextCls = this.baseCls + '-header-text';
9386 this.bwrapCls = this.baseCls + '-bwrap';
9387 this.tbarCls = this.baseCls + '-tbar';
9388 this.bodyCls = this.baseCls + '-body';
9389 this.bbarCls = this.baseCls + '-bbar';
9390 this.footerCls = this.baseCls + '-footer';
9394 createGhost : function(cls, useShim, appendTo){
9395 var el = document.createElement('div');
9396 el.className = 'x-panel-ghost ' + (cls ? cls : '');
9398 el.appendChild(this.el.dom.firstChild.cloneNode(true));
9400 Ext.fly(el.appendChild(document.createElement('ul'))).setHeight(this.bwrap.getHeight());
9401 el.style.width = this.el.dom.offsetWidth + 'px';;
9403 this.container.dom.appendChild(el);
9405 Ext.getDom(appendTo).appendChild(el);
9407 if(useShim !== false && this.el.useShim !== false){
9408 var layer = new Ext.Layer({shadow:false, useDisplay:true, constrain:false}, el);
9412 return new Ext.Element(el);
9417 doAutoLoad : function(){
9418 var u = this.body.getUpdater();
9420 u.setRenderer(this.renderer);
9422 u.update(Ext.isObject(this.autoLoad) ? this.autoLoad : {url: this.autoLoad});
9426 * Retrieve a tool by id.
9427 * @param {String} id
9428 * @return {Object} tool
9430 getTool : function(id) {
9431 return this.tools[id];
9435 * @cfg {String} autoEl @hide
9438 Ext.reg('panel', Ext.Panel);
9441 * @extends Ext.Component
9442 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
9444 * Create a new Editor
9445 * @param {Object} config The config object
9448 Ext.Editor = function(field, config){
9450 this.field = Ext.create(field.field, 'textfield');
9451 config = Ext.apply({}, field); // copy so we don't disturb original config
9452 delete config.field;
9456 Ext.Editor.superclass.constructor.call(this, config);
9459 Ext.extend(Ext.Editor, Ext.Component, {
9461 * @cfg {Ext.form.Field} field
9462 * The Field object (or descendant) or config object for field
9465 * @cfg {Boolean} allowBlur
9466 * True to {@link #completeEdit complete the editing process} if in edit mode when the
9467 * field is blurred. Defaults to <tt>false</tt>.
9470 * @cfg {Boolean/String} autoSize
9471 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
9472 * or "height" to adopt the height only, "none" to always use the field dimensions. (defaults to false)
9475 * @cfg {Boolean} revertInvalid
9476 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
9477 * validation fails (defaults to true)
9480 * @cfg {Boolean} ignoreNoChange
9481 * True to skip the edit completion process (no save, no events fired) if the user completes an edit and
9482 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
9483 * will never be ignored.
9486 * @cfg {Boolean} hideEl
9487 * False to keep the bound element visible while the editor is displayed (defaults to true)
9490 * @cfg {Mixed} value
9491 * The data value of the underlying field (defaults to "")
9495 * @cfg {String} alignment
9496 * The position to align to (see {@link Ext.Element#alignTo} for more details, defaults to "c-c?").
9500 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
9501 * for bottom-right shadow (defaults to "frame")
9505 * @cfg {Boolean} constrain True to constrain the editor to the viewport
9509 * @cfg {Boolean} swallowKeys Handle the keydown/keypress events so they don't propagate (defaults to true)
9513 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed. Defaults to <tt>true</tt>.
9515 completeOnEnter : true,
9517 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed. Defaults to <tt>true</tt>.
9521 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
9525 initComponent : function(){
9526 Ext.Editor.superclass.initComponent.call(this);
9529 * @event beforestartedit
9530 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
9531 * false from the handler of this event.
9532 * @param {Editor} this
9533 * @param {Ext.Element} boundEl The underlying element bound to this editor
9534 * @param {Mixed} value The field value being set
9539 * Fires when this editor is displayed
9540 * @param {Ext.Element} boundEl The underlying element bound to this editor
9541 * @param {Mixed} value The starting field value
9545 * @event beforecomplete
9546 * Fires after a change has been made to the field, but before the change is reflected in the underlying
9547 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
9548 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
9549 * event will not fire since no edit actually occurred.
9550 * @param {Editor} this
9551 * @param {Mixed} value The current field value
9552 * @param {Mixed} startValue The original field value
9557 * Fires after editing is complete and any changed value has been written to the underlying field.
9558 * @param {Editor} this
9559 * @param {Mixed} value The current field value
9560 * @param {Mixed} startValue The original field value
9565 * Fires after editing has been canceled and the editor's value has been reset.
9566 * @param {Editor} this
9567 * @param {Mixed} value The user-entered field value that was discarded
9568 * @param {Mixed} startValue The original field value that was set back into the editor after cancel
9573 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
9574 * {@link Ext.EventObject#getKey} to determine which key was pressed.
9575 * @param {Ext.form.Field} this
9576 * @param {Ext.EventObject} e The event object
9583 onRender : function(ct, position){
9584 this.el = new Ext.Layer({
9585 shadow: this.shadow,
9589 shadowOffset: this.shadowOffset || 4,
9591 constrain: this.constrain
9594 this.el.setZIndex(this.zIndex);
9596 this.el.setStyle("overflow", Ext.isGecko ? "auto" : "hidden");
9597 if(this.field.msgTarget != 'title'){
9598 this.field.msgTarget = 'qtip';
9600 this.field.inEditor = true;
9601 this.mon(this.field, {
9604 specialkey: this.onSpecialKey
9606 if(this.field.grow){
9607 this.mon(this.field, "autosize", this.el.sync, this.el, {delay:1});
9609 this.field.render(this.el).show();
9610 this.field.getEl().dom.name = '';
9611 if(this.swallowKeys){
9612 this.field.el.swallowEvent([
9613 'keypress', // *** Opera
9614 'keydown' // *** all other browsers
9620 onSpecialKey : function(field, e){
9621 var key = e.getKey(),
9622 complete = this.completeOnEnter && key == e.ENTER,
9623 cancel = this.cancelOnEsc && key == e.ESC;
9624 if(complete || cancel){
9627 this.completeEdit();
9631 if(field.triggerBlur){
9632 field.triggerBlur();
9635 this.fireEvent('specialkey', field, e);
9639 * Starts the editing process and shows the editor.
9640 * @param {Mixed} el The element to edit
9641 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
9642 * to the innerHTML of el.
9644 startEdit : function(el, value){
9646 this.completeEdit();
9648 this.boundEl = Ext.get(el);
9649 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
9651 this.render(this.parentEl || document.body);
9653 if(this.fireEvent("beforestartedit", this, this.boundEl, v) !== false){
9654 this.startValue = v;
9655 this.field.setValue(v);
9657 this.el.alignTo(this.boundEl, this.alignment);
9658 this.editing = true;
9664 doAutoSize : function(){
9666 var sz = this.boundEl.getSize(),
9667 fs = this.field.getSize();
9669 switch(this.autoSize){
9671 this.setSize(sz.width, fs.height);
9674 this.setSize(fs.width, sz.height);
9677 this.setSize(fs.width, fs.height);
9680 this.setSize(sz.width, sz.height);
9686 * Sets the height and width of this editor.
9687 * @param {Number} width The new width
9688 * @param {Number} height The new height
9690 setSize : function(w, h){
9691 delete this.field.lastSize;
9692 this.field.setSize(w, h);
9694 if(Ext.isGecko2 || Ext.isOpera){
9695 // prevent layer scrollbars
9696 this.el.setSize(w, h);
9703 * Realigns the editor to the bound field based on the current alignment config value.
9705 realign : function(){
9706 this.el.alignTo(this.boundEl, this.alignment);
9710 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
9711 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
9713 completeEdit : function(remainVisible){
9717 var v = this.getValue();
9718 if(!this.field.isValid()){
9719 if(this.revertInvalid !== false){
9720 this.cancelEdit(remainVisible);
9724 if(String(v) === String(this.startValue) && this.ignoreNoChange){
9725 this.hideEdit(remainVisible);
9728 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
9729 v = this.getValue();
9730 if(this.updateEl && this.boundEl){
9731 this.boundEl.update(v);
9733 this.hideEdit(remainVisible);
9734 this.fireEvent("complete", this, v, this.startValue);
9739 onShow : function(){
9741 if(this.hideEl !== false){
9742 this.boundEl.hide();
9744 this.field.show().focus(false, true);
9745 this.fireEvent("startedit", this.boundEl, this.startValue);
9749 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
9750 * reverted to the original starting value.
9751 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
9752 * cancel (defaults to false)
9754 cancelEdit : function(remainVisible){
9756 var v = this.getValue();
9757 this.setValue(this.startValue);
9758 this.hideEdit(remainVisible);
9759 this.fireEvent("canceledit", this, v, this.startValue);
9764 hideEdit: function(remainVisible){
9765 if(remainVisible !== true){
9766 this.editing = false;
9772 onBlur : function(){
9773 if(this.allowBlur !== true && this.editing){
9774 this.completeEdit();
9779 onHide : function(){
9781 this.completeEdit();
9785 if(this.field.collapse){
9786 this.field.collapse();
9789 if(this.hideEl !== false){
9790 this.boundEl.show();
9795 * Sets the data value of the editor
9796 * @param {Mixed} value Any valid value supported by the underlying field
9798 setValue : function(v){
9799 this.field.setValue(v);
9803 * Gets the data value of the editor
9804 * @return {Mixed} The data value
9806 getValue : function(){
9807 return this.field.getValue();
9810 beforeDestroy : function(){
9811 Ext.destroy(this.field);
9815 Ext.reg('editor', Ext.Editor);/**
9816 * @class Ext.ColorPalette
9817 * @extends Ext.Component
9818 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
9819 * Here's an example of typical usage:
9821 var cp = new Ext.ColorPalette({value:'993300'}); // initial selected color
9822 cp.render('my-div');
9824 cp.on('select', function(palette, selColor){
9825 // do something with selColor
9829 * Create a new ColorPalette
9830 * @param {Object} config The config object
9831 * @xtype colorpalette
9833 Ext.ColorPalette = function(config){
9834 Ext.ColorPalette.superclass.constructor.call(this, config);
9838 * Fires when a color is selected
9839 * @param {ColorPalette} this
9840 * @param {String} color The 6-digit color hex code (without the # symbol)
9846 this.on('select', this.handler, this.scope, true);
9849 Ext.extend(Ext.ColorPalette, Ext.Component, {
9851 * @cfg {String} tpl An existing XTemplate instance to be used in place of the default template for rendering the component.
9854 * @cfg {String} itemCls
9855 * The CSS class to apply to the containing element (defaults to 'x-color-palette')
9857 itemCls : 'x-color-palette',
9859 * @cfg {String} value
9860 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
9861 * the hex codes are case-sensitive.
9864 clickEvent :'click',
9866 ctype : 'Ext.ColorPalette',
9869 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the {@link #select} event
9871 allowReselect : false,
9874 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
9875 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
9876 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9877 * of colors with the width setting until the box is symmetrical.</p>
9878 * <p>You can override individual colors if needed:</p>
9880 var cp = new Ext.ColorPalette();
9881 cp.colors[0] = 'FF0000'; // change the first box to red
9884 Or you can provide a custom array of your own for complete control:
9886 var cp = new Ext.ColorPalette();
9887 cp.colors = ['000000', '993300', '333300'];
9892 '000000', '993300', '333300', '003300', '003366', '000080', '333399', '333333',
9893 '800000', 'FF6600', '808000', '008000', '008080', '0000FF', '666699', '808080',
9894 'FF0000', 'FF9900', '99CC00', '339966', '33CCCC', '3366FF', '800080', '969696',
9895 'FF00FF', 'FFCC00', 'FFFF00', '00FF00', '00FFFF', '00CCFF', '993366', 'C0C0C0',
9896 'FF99CC', 'FFCC99', 'FFFF99', 'CCFFCC', 'CCFFFF', '99CCFF', 'CC99FF', 'FFFFFF'
9900 * @cfg {Function} handler
9901 * Optional. A function that will handle the select event of this palette.
9902 * The handler is passed the following parameters:<div class="mdetail-params"><ul>
9903 * <li><code>palette</code> : ColorPalette<div class="sub-desc">The {@link #palette Ext.ColorPalette}.</div></li>
9904 * <li><code>color</code> : String<div class="sub-desc">The 6-digit color hex code (without the # symbol).</div></li>
9908 * @cfg {Object} scope
9909 * The scope (<tt><b>this</b></tt> reference) in which the <code>{@link #handler}</code>
9910 * function will be called. Defaults to this ColorPalette instance.
9914 onRender : function(container, position){
9915 var t = this.tpl || new Ext.XTemplate(
9916 '<tpl for="."><a href="#" class="color-{.}" hidefocus="on"><em><span style="background:#{.}" unselectable="on"> </span></em></a></tpl>'
9918 var el = document.createElement('div');
9919 el.id = this.getId();
9920 el.className = this.itemCls;
9921 t.overwrite(el, this.colors);
9922 container.dom.insertBefore(el, position);
9923 this.el = Ext.get(el);
9924 this.mon(this.el, this.clickEvent, this.handleClick, this, {delegate: 'a'});
9925 if(this.clickEvent != 'click'){
9926 this.mon(this.el, 'click', Ext.emptyFn, this, {delegate: 'a', preventDefault: true});
9931 afterRender : function(){
9932 Ext.ColorPalette.superclass.afterRender.call(this);
9941 handleClick : function(e, t){
9944 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
9945 this.select(c.toUpperCase());
9950 * Selects the specified color in the palette (fires the {@link #select} event)
9951 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
9953 select : function(color){
9954 color = color.replace('#', '');
9955 if(color != this.value || this.allowReselect){
9958 el.child('a.color-'+this.value).removeClass('x-color-palette-sel');
9960 el.child('a.color-'+color).addClass('x-color-palette-sel');
9962 this.fireEvent('select', this, color);
9967 * @cfg {String} autoEl @hide
9970 Ext.reg('colorpalette', Ext.ColorPalette);
9972 * @class Ext.DatePicker
\r
9973 * @extends Ext.Component
\r
9974 * Simple date picker class.
\r
9976 * Create a new DatePicker
\r
9977 * @param {Object} config The config object
\r
9978 * @xtype datepicker
\r
9980 Ext.DatePicker = Ext.extend(Ext.BoxComponent, {
\r
9982 * @cfg {String} todayText
\r
9983 * The text to display on the button that selects the current date (defaults to <tt>'Today'</tt>)
\r
9985 todayText : 'Today',
\r
9987 * @cfg {String} okText
\r
9988 * The text to display on the ok button (defaults to <tt>' OK '</tt> to give the user extra clicking room)
\r
9990 okText : ' OK ',
\r
9992 * @cfg {String} cancelText
\r
9993 * The text to display on the cancel button (defaults to <tt>'Cancel'</tt>)
\r
9995 cancelText : 'Cancel',
\r
9997 * @cfg {Function} handler
\r
9998 * Optional. A function that will handle the select event of this picker.
\r
9999 * The handler is passed the following parameters:<div class="mdetail-params"><ul>
\r
10000 * <li><code>picker</code> : DatePicker<div class="sub-desc">The Ext.DatePicker.</div></li>
\r
10001 * <li><code>date</code> : Date<div class="sub-desc">The selected date.</div></li>
\r
10005 * @cfg {Object} scope
\r
10006 * The scope (<tt><b>this</b></tt> reference) in which the <code>{@link #handler}</code>
\r
10007 * function will be called. Defaults to this DatePicker instance.
\r
10010 * @cfg {String} todayTip
\r
10011 * The tooltip to display for the button that selects the current date (defaults to <tt>'{current date} (Spacebar)'</tt>)
\r
10013 todayTip : '{0} (Spacebar)',
\r
10015 * @cfg {String} minText
\r
10016 * The error text to display if the minDate validation fails (defaults to <tt>'This date is before the minimum date'</tt>)
\r
10018 minText : 'This date is before the minimum date',
\r
10020 * @cfg {String} maxText
\r
10021 * The error text to display if the maxDate validation fails (defaults to <tt>'This date is after the maximum date'</tt>)
\r
10023 maxText : 'This date is after the maximum date',
\r
10025 * @cfg {String} format
\r
10026 * The default date format string which can be overriden for localization support. The format must be
\r
10027 * valid according to {@link Date#parseDate} (defaults to <tt>'m/d/y'</tt>).
\r
10029 format : 'm/d/y',
\r
10031 * @cfg {String} disabledDaysText
\r
10032 * The tooltip to display when the date falls on a disabled day (defaults to <tt>'Disabled'</tt>)
\r
10034 disabledDaysText : 'Disabled',
\r
10036 * @cfg {String} disabledDatesText
\r
10037 * The tooltip text to display when the date falls on a disabled date (defaults to <tt>'Disabled'</tt>)
\r
10039 disabledDatesText : 'Disabled',
\r
10041 * @cfg {Array} monthNames
\r
10042 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
\r
10044 monthNames : Date.monthNames,
\r
10046 * @cfg {Array} dayNames
\r
10047 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
\r
10049 dayNames : Date.dayNames,
\r
10051 * @cfg {String} nextText
\r
10052 * The next month navigation button tooltip (defaults to <tt>'Next Month (Control+Right)'</tt>)
\r
10054 nextText : 'Next Month (Control+Right)',
\r
10056 * @cfg {String} prevText
\r
10057 * The previous month navigation button tooltip (defaults to <tt>'Previous Month (Control+Left)'</tt>)
\r
10059 prevText : 'Previous Month (Control+Left)',
\r
10061 * @cfg {String} monthYearText
\r
10062 * The header month selector tooltip (defaults to <tt>'Choose a month (Control+Up/Down to move years)'</tt>)
\r
10064 monthYearText : 'Choose a month (Control+Up/Down to move years)',
\r
10066 * @cfg {Number} startDay
\r
10067 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
\r
10071 * @cfg {Boolean} showToday
\r
10072 * False to hide the footer area containing the Today button and disable the keyboard handler for spacebar
\r
10073 * that selects the current date (defaults to <tt>true</tt>).
\r
10075 showToday : true,
\r
10077 * @cfg {Date} minDate
\r
10078 * Minimum allowable date (JavaScript date object, defaults to null)
\r
10081 * @cfg {Date} maxDate
\r
10082 * Maximum allowable date (JavaScript date object, defaults to null)
\r
10085 * @cfg {Array} disabledDays
\r
10086 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
\r
10089 * @cfg {RegExp} disabledDatesRE
\r
10090 * JavaScript regular expression used to disable a pattern of dates (defaults to null). The {@link #disabledDates}
\r
10091 * config will generate this regex internally, but if you specify disabledDatesRE it will take precedence over the
\r
10092 * disabledDates value.
\r
10095 * @cfg {Array} disabledDates
\r
10096 * An array of 'dates' to disable, as strings. These strings will be used to build a dynamic regular
\r
10097 * expression so they are very powerful. Some examples:
\r
10099 * <li>['03/08/2003', '09/16/2003'] would disable those exact dates</li>
\r
10100 * <li>['03/08', '09/16'] would disable those days for every year</li>
\r
10101 * <li>['^03/08'] would only match the beginning (useful if you are using short years)</li>
\r
10102 * <li>['03/../2006'] would disable every day in March 2006</li>
\r
10103 * <li>['^03'] would disable every day in every March</li>
\r
10105 * Note that the format of the dates included in the array should exactly match the {@link #format} config.
\r
10106 * In order to support regular expressions, if you are using a date format that has '.' in it, you will have to
\r
10107 * escape the dot when restricting dates. For example: ['03\\.08\\.03'].
\r
10111 initComponent : function(){
\r
10112 Ext.DatePicker.superclass.initComponent.call(this);
\r
10114 this.value = this.value ?
\r
10115 this.value.clearTime(true) : new Date().clearTime();
\r
10120 * Fires when a date is selected
\r
10121 * @param {DatePicker} this
\r
10122 * @param {Date} date The selected date
\r
10127 if(this.handler){
\r
10128 this.on('select', this.handler, this.scope || this);
\r
10131 this.initDisabledDays();
\r
10135 initDisabledDays : function(){
\r
10136 if(!this.disabledDatesRE && this.disabledDates){
\r
10137 var dd = this.disabledDates,
\r
10138 len = dd.length - 1,
\r
10141 Ext.each(dd, function(d, i){
\r
10142 re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i];
\r
10147 this.disabledDatesRE = new RegExp(re + ')');
\r
10152 * Replaces any existing disabled dates with new values and refreshes the DatePicker.
\r
10153 * @param {Array/RegExp} disabledDates An array of date strings (see the {@link #disabledDates} config
\r
10154 * for details on supported values), or a JavaScript regular expression used to disable a pattern of dates.
\r
10156 setDisabledDates : function(dd){
\r
10157 if(Ext.isArray(dd)){
\r
10158 this.disabledDates = dd;
\r
10159 this.disabledDatesRE = null;
\r
10161 this.disabledDatesRE = dd;
\r
10163 this.initDisabledDays();
\r
10164 this.update(this.value, true);
\r
10168 * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.
\r
10169 * @param {Array} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config
\r
10170 * for details on supported values.
\r
10172 setDisabledDays : function(dd){
\r
10173 this.disabledDays = dd;
\r
10174 this.update(this.value, true);
\r
10178 * Replaces any existing {@link #minDate} with the new value and refreshes the DatePicker.
\r
10179 * @param {Date} value The minimum date that can be selected
\r
10181 setMinDate : function(dt){
\r
10182 this.minDate = dt;
\r
10183 this.update(this.value, true);
\r
10187 * Replaces any existing {@link #maxDate} with the new value and refreshes the DatePicker.
\r
10188 * @param {Date} value The maximum date that can be selected
\r
10190 setMaxDate : function(dt){
\r
10191 this.maxDate = dt;
\r
10192 this.update(this.value, true);
\r
10196 * Sets the value of the date field
\r
10197 * @param {Date} value The date to set
\r
10199 setValue : function(value){
\r
10200 this.value = value.clearTime(true);
\r
10201 this.update(this.value);
\r
10205 * Gets the current selected value of the date field
\r
10206 * @return {Date} The selected date
\r
10208 getValue : function(){
\r
10209 return this.value;
\r
10213 focus : function(){
\r
10214 this.update(this.activeDate);
\r
10218 onEnable: function(initial){
\r
10219 Ext.DatePicker.superclass.onEnable.call(this);
\r
10220 this.doDisabled(false);
\r
10221 this.update(initial ? this.value : this.activeDate);
\r
10223 this.el.repaint();
\r
10229 onDisable : function(){
\r
10230 Ext.DatePicker.superclass.onDisable.call(this);
\r
10231 this.doDisabled(true);
\r
10232 if(Ext.isIE && !Ext.isIE8){
\r
10233 /* Really strange problem in IE6/7, when disabled, have to explicitly
\r
10234 * repaint each of the nodes to get them to display correctly, simply
\r
10235 * calling repaint on the main element doesn't appear to be enough.
\r
10237 Ext.each([].concat(this.textNodes, this.el.query('th span')), function(el){
\r
10238 Ext.fly(el).repaint();
\r
10244 doDisabled : function(disabled){
\r
10245 this.keyNav.setDisabled(disabled);
\r
10246 this.prevRepeater.setDisabled(disabled);
\r
10247 this.nextRepeater.setDisabled(disabled);
\r
10248 if(this.showToday){
\r
10249 this.todayKeyListener.setDisabled(disabled);
\r
10250 this.todayBtn.setDisabled(disabled);
\r
10255 onRender : function(container, position){
\r
10257 '<table cellspacing="0">',
\r
10258 '<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>',
\r
10259 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'],
\r
10260 dn = this.dayNames,
\r
10262 for(i = 0; i < 7; i++){
\r
10263 var d = this.startDay+i;
\r
10267 m.push('<th><span>', dn[d].substr(0,1), '</span></th>');
\r
10269 m[m.length] = '</tr></thead><tbody><tr>';
\r
10270 for(i = 0; i < 42; i++) {
\r
10271 if(i % 7 === 0 && i !== 0){
\r
10272 m[m.length] = '</tr><tr>';
\r
10274 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
\r
10276 m.push('</tr></tbody></table></td></tr>',
\r
10277 this.showToday ? '<tr><td colspan="3" class="x-date-bottom" align="center"></td></tr>' : '',
\r
10278 '</table><div class="x-date-mp"></div>');
\r
10280 var el = document.createElement('div');
\r
10281 el.className = 'x-date-picker';
\r
10282 el.innerHTML = m.join('');
\r
10284 container.dom.insertBefore(el, position);
\r
10286 this.el = Ext.get(el);
\r
10287 this.eventEl = Ext.get(el.firstChild);
\r
10289 this.prevRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-left a'), {
\r
10290 handler: this.showPrevMonth,
\r
10292 preventDefault:true,
\r
10296 this.nextRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-right a'), {
\r
10297 handler: this.showNextMonth,
\r
10299 preventDefault:true,
\r
10303 this.monthPicker = this.el.down('div.x-date-mp');
\r
10304 this.monthPicker.enableDisplayMode('block');
\r
10306 this.keyNav = new Ext.KeyNav(this.eventEl, {
\r
10307 'left' : function(e){
\r
10309 this.showPrevMonth();
\r
10311 this.update(this.activeDate.add('d', -1));
\r
10315 'right' : function(e){
\r
10317 this.showNextMonth();
\r
10319 this.update(this.activeDate.add('d', 1));
\r
10323 'up' : function(e){
\r
10325 this.showNextYear();
\r
10327 this.update(this.activeDate.add('d', -7));
\r
10331 'down' : function(e){
\r
10333 this.showPrevYear();
\r
10335 this.update(this.activeDate.add('d', 7));
\r
10339 'pageUp' : function(e){
\r
10340 this.showNextMonth();
\r
10343 'pageDown' : function(e){
\r
10344 this.showPrevMonth();
\r
10347 'enter' : function(e){
\r
10348 e.stopPropagation();
\r
10355 this.el.unselectable();
\r
10357 this.cells = this.el.select('table.x-date-inner tbody td');
\r
10358 this.textNodes = this.el.query('table.x-date-inner tbody span');
\r
10360 this.mbtn = new Ext.Button({
\r
10362 tooltip: this.monthYearText,
\r
10363 renderTo: this.el.child('td.x-date-middle', true)
\r
10365 this.mbtn.el.child('em').addClass('x-btn-arrow');
\r
10367 if(this.showToday){
\r
10368 this.todayKeyListener = this.eventEl.addKeyListener(Ext.EventObject.SPACE, this.selectToday, this);
\r
10369 var today = (new Date()).dateFormat(this.format);
\r
10370 this.todayBtn = new Ext.Button({
\r
10371 renderTo: this.el.child('td.x-date-bottom', true),
\r
10372 text: String.format(this.todayText, today),
\r
10373 tooltip: String.format(this.todayTip, today),
\r
10374 handler: this.selectToday,
\r
10378 this.mon(this.eventEl, 'mousewheel', this.handleMouseWheel, this);
\r
10379 this.mon(this.eventEl, 'click', this.handleDateClick, this, {delegate: 'a.x-date-date'});
\r
10380 this.mon(this.mbtn, 'click', this.showMonthPicker, this);
\r
10381 this.onEnable(true);
\r
10385 createMonthPicker : function(){
\r
10386 if(!this.monthPicker.dom.firstChild){
\r
10387 var buf = ['<table border="0" cellspacing="0">'];
\r
10388 for(var i = 0; i < 6; i++){
\r
10390 '<tr><td class="x-date-mp-month"><a href="#">', Date.getShortMonthName(i), '</a></td>',
\r
10391 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', Date.getShortMonthName(i + 6), '</a></td>',
\r
10393 '<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>' :
\r
10394 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
\r
10398 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
\r
10400 '</button><button type="button" class="x-date-mp-cancel">',
\r
10402 '</button></td></tr>',
\r
10405 this.monthPicker.update(buf.join(''));
\r
10407 this.mon(this.monthPicker, 'click', this.onMonthClick, this);
\r
10408 this.mon(this.monthPicker, 'dblclick', this.onMonthDblClick, this);
\r
10410 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
\r
10411 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
\r
10413 this.mpMonths.each(function(m, a, i){
\r
10416 m.dom.xmonth = 5 + Math.round(i * 0.5);
\r
10418 m.dom.xmonth = Math.round((i-1) * 0.5);
\r
10425 showMonthPicker : function(){
\r
10426 if(!this.disabled){
\r
10427 this.createMonthPicker();
\r
10428 var size = this.el.getSize();
\r
10429 this.monthPicker.setSize(size);
\r
10430 this.monthPicker.child('table').setSize(size);
\r
10432 this.mpSelMonth = (this.activeDate || this.value).getMonth();
\r
10433 this.updateMPMonth(this.mpSelMonth);
\r
10434 this.mpSelYear = (this.activeDate || this.value).getFullYear();
\r
10435 this.updateMPYear(this.mpSelYear);
\r
10437 this.monthPicker.slideIn('t', {duration:0.2});
\r
10442 updateMPYear : function(y){
\r
10444 var ys = this.mpYears.elements;
\r
10445 for(var i = 1; i <= 10; i++){
\r
10446 var td = ys[i-1], y2;
\r
10448 y2 = y + Math.round(i * 0.5);
\r
10449 td.firstChild.innerHTML = y2;
\r
10452 y2 = y - (5-Math.round(i * 0.5));
\r
10453 td.firstChild.innerHTML = y2;
\r
10456 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
\r
10461 updateMPMonth : function(sm){
\r
10462 this.mpMonths.each(function(m, a, i){
\r
10463 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
\r
10468 selectMPMonth : function(m){
\r
10473 onMonthClick : function(e, t){
\r
10475 var el = new Ext.Element(t), pn;
\r
10476 if(el.is('button.x-date-mp-cancel')){
\r
10477 this.hideMonthPicker();
\r
10479 else if(el.is('button.x-date-mp-ok')){
\r
10480 var d = new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate());
\r
10481 if(d.getMonth() != this.mpSelMonth){
\r
10482 // 'fix' the JS rolling date conversion if needed
\r
10483 d = new Date(this.mpSelYear, this.mpSelMonth, 1).getLastDateOfMonth();
\r
10486 this.hideMonthPicker();
\r
10488 else if((pn = el.up('td.x-date-mp-month', 2))){
\r
10489 this.mpMonths.removeClass('x-date-mp-sel');
\r
10490 pn.addClass('x-date-mp-sel');
\r
10491 this.mpSelMonth = pn.dom.xmonth;
\r
10493 else if((pn = el.up('td.x-date-mp-year', 2))){
\r
10494 this.mpYears.removeClass('x-date-mp-sel');
\r
10495 pn.addClass('x-date-mp-sel');
\r
10496 this.mpSelYear = pn.dom.xyear;
\r
10498 else if(el.is('a.x-date-mp-prev')){
\r
10499 this.updateMPYear(this.mpyear-10);
\r
10501 else if(el.is('a.x-date-mp-next')){
\r
10502 this.updateMPYear(this.mpyear+10);
\r
10507 onMonthDblClick : function(e, t){
\r
10509 var el = new Ext.Element(t), pn;
\r
10510 if((pn = el.up('td.x-date-mp-month', 2))){
\r
10511 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
\r
10512 this.hideMonthPicker();
\r
10514 else if((pn = el.up('td.x-date-mp-year', 2))){
\r
10515 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
\r
10516 this.hideMonthPicker();
\r
10521 hideMonthPicker : function(disableAnim){
\r
10522 if(this.monthPicker){
\r
10523 if(disableAnim === true){
\r
10524 this.monthPicker.hide();
\r
10526 this.monthPicker.slideOut('t', {duration:0.2});
\r
10532 showPrevMonth : function(e){
\r
10533 this.update(this.activeDate.add('mo', -1));
\r
10537 showNextMonth : function(e){
\r
10538 this.update(this.activeDate.add('mo', 1));
\r
10542 showPrevYear : function(){
\r
10543 this.update(this.activeDate.add('y', -1));
\r
10547 showNextYear : function(){
\r
10548 this.update(this.activeDate.add('y', 1));
\r
10552 handleMouseWheel : function(e){
\r
10554 if(!this.disabled){
\r
10555 var delta = e.getWheelDelta();
\r
10557 this.showPrevMonth();
\r
10558 } else if(delta < 0){
\r
10559 this.showNextMonth();
\r
10565 handleDateClick : function(e, t){
\r
10567 if(!this.disabled && t.dateValue && !Ext.fly(t.parentNode).hasClass('x-date-disabled')){
\r
10568 this.setValue(new Date(t.dateValue));
\r
10569 this.fireEvent('select', this, this.value);
\r
10574 selectToday : function(){
\r
10575 if(this.todayBtn && !this.todayBtn.disabled){
\r
10576 this.setValue(new Date().clearTime());
\r
10577 this.fireEvent('select', this, this.value);
\r
10582 update : function(date, forceRefresh){
\r
10583 if(this.rendered){
\r
10584 var vd = this.activeDate, vis = this.isVisible();
\r
10585 this.activeDate = date;
\r
10586 if(!forceRefresh && vd && this.el){
\r
10587 var t = date.getTime();
\r
10588 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
\r
10589 this.cells.removeClass('x-date-selected');
\r
10590 this.cells.each(function(c){
\r
10591 if(c.dom.firstChild.dateValue == t){
\r
10592 c.addClass('x-date-selected');
\r
10594 Ext.fly(c.dom.firstChild).focus(50);
\r
10602 var days = date.getDaysInMonth(),
\r
10603 firstOfMonth = date.getFirstDateOfMonth(),
\r
10604 startingPos = firstOfMonth.getDay()-this.startDay;
\r
10606 if(startingPos < 0){
\r
10607 startingPos += 7;
\r
10609 days += startingPos;
\r
10611 var pm = date.add('mo', -1),
\r
10612 prevStart = pm.getDaysInMonth()-startingPos,
\r
10613 cells = this.cells.elements,
\r
10614 textEls = this.textNodes,
\r
10615 // convert everything to numbers so it's fast
\r
10617 d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime(),
\r
10618 today = new Date().clearTime().getTime(),
\r
10619 sel = date.clearTime(true).getTime(),
\r
10620 min = this.minDate ? this.minDate.clearTime(true) : Number.NEGATIVE_INFINITY,
\r
10621 max = this.maxDate ? this.maxDate.clearTime(true) : Number.POSITIVE_INFINITY,
\r
10622 ddMatch = this.disabledDatesRE,
\r
10623 ddText = this.disabledDatesText,
\r
10624 ddays = this.disabledDays ? this.disabledDays.join('') : false,
\r
10625 ddaysText = this.disabledDaysText,
\r
10626 format = this.format;
\r
10628 if(this.showToday){
\r
10629 var td = new Date().clearTime(),
\r
10630 disable = (td < min || td > max ||
\r
10631 (ddMatch && format && ddMatch.test(td.dateFormat(format))) ||
\r
10632 (ddays && ddays.indexOf(td.getDay()) != -1));
\r
10634 if(!this.disabled){
\r
10635 this.todayBtn.setDisabled(disable);
\r
10636 this.todayKeyListener[disable ? 'disable' : 'enable']();
\r
10640 var setCellClass = function(cal, cell){
\r
10642 var t = d.getTime();
\r
10643 cell.firstChild.dateValue = t;
\r
10645 cell.className += ' x-date-today';
\r
10646 cell.title = cal.todayText;
\r
10649 cell.className += ' x-date-selected';
\r
10651 Ext.fly(cell.firstChild).focus(50);
\r
10656 cell.className = ' x-date-disabled';
\r
10657 cell.title = cal.minText;
\r
10661 cell.className = ' x-date-disabled';
\r
10662 cell.title = cal.maxText;
\r
10666 if(ddays.indexOf(d.getDay()) != -1){
\r
10667 cell.title = ddaysText;
\r
10668 cell.className = ' x-date-disabled';
\r
10671 if(ddMatch && format){
\r
10672 var fvalue = d.dateFormat(format);
\r
10673 if(ddMatch.test(fvalue)){
\r
10674 cell.title = ddText.replace('%0', fvalue);
\r
10675 cell.className = ' x-date-disabled';
\r
10681 for(; i < startingPos; i++) {
\r
10682 textEls[i].innerHTML = (++prevStart);
\r
10683 d.setDate(d.getDate()+1);
\r
10684 cells[i].className = 'x-date-prevday';
\r
10685 setCellClass(this, cells[i]);
\r
10687 for(; i < days; i++){
\r
10688 var intDay = i - startingPos + 1;
\r
10689 textEls[i].innerHTML = (intDay);
\r
10690 d.setDate(d.getDate()+1);
\r
10691 cells[i].className = 'x-date-active';
\r
10692 setCellClass(this, cells[i]);
\r
10694 var extraDays = 0;
\r
10695 for(; i < 42; i++) {
\r
10696 textEls[i].innerHTML = (++extraDays);
\r
10697 d.setDate(d.getDate()+1);
\r
10698 cells[i].className = 'x-date-nextday';
\r
10699 setCellClass(this, cells[i]);
\r
10702 this.mbtn.setText(this.monthNames[date.getMonth()] + ' ' + date.getFullYear());
\r
10704 if(!this.internalRender){
\r
10705 var main = this.el.dom.firstChild,
\r
10706 w = main.offsetWidth;
\r
10707 this.el.setWidth(w + this.el.getBorderWidth('lr'));
\r
10708 Ext.fly(main).setWidth(w);
\r
10709 this.internalRender = true;
\r
10710 // opera does not respect the auto grow header center column
\r
10711 // then, after it gets a width opera refuses to recalculate
\r
10712 // without a second pass
\r
10713 if(Ext.isOpera && !this.secondPass){
\r
10714 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + 'px';
\r
10715 this.secondPass = true;
\r
10716 this.update.defer(10, this, [date]);
\r
10723 beforeDestroy : function() {
\r
10724 if(this.rendered){
\r
10725 this.keyNav.disable();
\r
10726 this.keyNav = null;
\r
10728 this.leftClickRpt,
\r
10729 this.rightClickRpt,
\r
10730 this.monthPicker,
\r
10739 * @cfg {String} autoEl @hide
\r
10743 Ext.reg('datepicker', Ext.DatePicker);
\r
10745 * @class Ext.LoadMask
10746 * A simple utility class for generically masking elements while loading data. If the {@link #store}
10747 * config option is specified, the masking will be automatically synchronized with the store's loading
10748 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
10749 * element's Updater load indicator and will be destroyed after the initial load.
10750 * <p>Example usage:</p>
10753 var myMask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait..."});
10757 * Create a new LoadMask
10758 * @param {Mixed} el The element or DOM node, or its id
10759 * @param {Object} config The config object
10761 Ext.LoadMask = function(el, config){
10762 this.el = Ext.get(el);
10763 Ext.apply(this, config);
10765 this.store.on('beforeload', this.onBeforeLoad, this);
10766 this.store.on('load', this.onLoad, this);
10767 this.store.on('exception', this.onLoad, this);
10768 this.removeMask = Ext.value(this.removeMask, false);
10770 var um = this.el.getUpdater();
10771 um.showLoadIndicator = false; // disable the default indicator
10772 um.on('beforeupdate', this.onBeforeLoad, this);
10773 um.on('update', this.onLoad, this);
10774 um.on('failure', this.onLoad, this);
10775 this.removeMask = Ext.value(this.removeMask, true);
10779 Ext.LoadMask.prototype = {
10781 * @cfg {Ext.data.Store} store
10782 * Optional Store to which the mask is bound. The mask is displayed when a load request is issued, and
10783 * hidden on either load sucess, or load fail.
10786 * @cfg {Boolean} removeMask
10787 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
10788 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
10791 * @cfg {String} msg
10792 * The text to display in a centered loading message box (defaults to 'Loading...')
10794 msg : 'Loading...',
10796 * @cfg {String} msgCls
10797 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
10799 msgCls : 'x-mask-loading',
10802 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
10808 * Disables the mask to prevent it from being displayed
10810 disable : function(){
10811 this.disabled = true;
10815 * Enables the mask so that it can be displayed
10817 enable : function(){
10818 this.disabled = false;
10822 onLoad : function(){
10823 this.el.unmask(this.removeMask);
10827 onBeforeLoad : function(){
10828 if(!this.disabled){
10829 this.el.mask(this.msg, this.msgCls);
10834 * Show this LoadMask over the configured Element.
10837 this.onBeforeLoad();
10841 * Hide this LoadMask.
10848 destroy : function(){
10850 this.store.un('beforeload', this.onBeforeLoad, this);
10851 this.store.un('load', this.onLoad, this);
10852 this.store.un('exception', this.onLoad, this);
10854 var um = this.el.getUpdater();
10855 um.un('beforeupdate', this.onBeforeLoad, this);
10856 um.un('update', this.onLoad, this);
10857 um.un('failure', this.onLoad, this);
10861 * @class Ext.Slider
\r
10862 * @extends Ext.BoxComponent
\r
10863 * Slider which supports vertical or horizontal orientation, keyboard adjustments,
\r
10864 * configurable snapping, axis clicking and animation. Can be added as an item to
\r
10865 * any container. Example usage:
\r
10868 renderTo: Ext.getBody(),
\r
10877 Ext.Slider = Ext.extend(Ext.BoxComponent, {
\r
10879 * @cfg {Number} value The value to initialize the slider with. Defaults to minValue.
\r
10882 * @cfg {Boolean} vertical Orient the Slider vertically rather than horizontally, defaults to false.
\r
10886 * @cfg {Number} minValue The minimum value for the Slider. Defaults to 0.
\r
10890 * @cfg {Number} maxValue The maximum value for the Slider. Defaults to 100.
\r
10894 * @cfg {Number/Boolean} decimalPrecision.
\r
10895 * <p>The number of decimal places to which to round the Slider's value. Defaults to 0.</p>
\r
10896 * <p>To disable rounding, configure as <tt><b>false</b></tt>.</p>
\r
10898 decimalPrecision: 0,
\r
10900 * @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
10904 * @cfg {Number} increment How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'.
\r
10908 clickRange: [5,15],
\r
10910 * @cfg {Boolean} clickToChange Determines whether or not clicking on the Slider axis will change the slider. Defaults to true
\r
10912 clickToChange : true,
\r
10914 * @cfg {Boolean} animate Turn on or off animation. Defaults to true
\r
10919 * True while the thumb is in a drag operation
\r
10924 // private override
\r
10925 initComponent : function(){
\r
10926 if(!Ext.isDefined(this.value)){
\r
10927 this.value = this.minValue;
\r
10929 Ext.Slider.superclass.initComponent.call(this);
\r
10930 this.keyIncrement = Math.max(this.increment, this.keyIncrement);
\r
10933 * @event beforechange
\r
10934 * Fires before the slider value is changed. By returning false from an event handler,
\r
10935 * you can cancel the event and prevent the slider from changing.
\r
10936 * @param {Ext.Slider} slider The slider
\r
10937 * @param {Number} newValue The new value which the slider is being changed to.
\r
10938 * @param {Number} oldValue The old value which the slider was previously.
\r
10943 * Fires when the slider value is changed.
\r
10944 * @param {Ext.Slider} slider The slider
\r
10945 * @param {Number} newValue The new value which the slider has been changed to.
\r
10949 * @event changecomplete
\r
10950 * Fires when the slider value is changed by the user and any drag operations have completed.
\r
10951 * @param {Ext.Slider} slider The slider
\r
10952 * @param {Number} newValue The new value which the slider has been changed to.
\r
10954 'changecomplete',
\r
10956 * @event dragstart
\r
10957 * Fires after a drag operation has started.
\r
10958 * @param {Ext.Slider} slider The slider
\r
10959 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
\r
10964 * Fires continuously during the drag operation while the mouse is moving.
\r
10965 * @param {Ext.Slider} slider The slider
\r
10966 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
\r
10971 * Fires after the drag operation has completed.
\r
10972 * @param {Ext.Slider} slider The slider
\r
10973 * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
\r
10978 if(this.vertical){
\r
10979 Ext.apply(this, Ext.Slider.Vertical);
\r
10983 // private override
\r
10984 onRender : function(){
\r
10986 cls: 'x-slider ' + (this.vertical ? 'x-slider-vert' : 'x-slider-horz'),
\r
10987 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
10989 Ext.Slider.superclass.onRender.apply(this, arguments);
\r
10990 this.endEl = this.el.first();
\r
10991 this.innerEl = this.endEl.first();
\r
10992 this.thumb = this.innerEl.first();
\r
10993 this.halfThumb = (this.vertical ? this.thumb.getHeight() : this.thumb.getWidth())/2;
\r
10994 this.focusEl = this.thumb.next();
\r
10995 this.initEvents();
\r
10998 // private override
\r
10999 initEvents : function(){
\r
11000 this.thumb.addClassOnOver('x-slider-thumb-over');
\r
11001 this.mon(this.el, {
\r
11003 mousedown: this.onMouseDown,
\r
11004 keydown: this.onKeyDown
\r
11007 this.focusEl.swallowEvent("click", true);
\r
11009 this.tracker = new Ext.dd.DragTracker({
\r
11010 onBeforeStart: this.onBeforeDragStart.createDelegate(this),
\r
11011 onStart: this.onDragStart.createDelegate(this),
\r
11012 onDrag: this.onDrag.createDelegate(this),
\r
11013 onEnd: this.onDragEnd.createDelegate(this),
\r
11017 this.tracker.initEl(this.thumb);
\r
11018 this.on('beforedestroy', this.tracker.destroy, this.tracker);
\r
11021 // private override
\r
11022 onMouseDown : function(e){
\r
11023 if(this.disabled) {return;}
\r
11024 if(this.clickToChange && e.target != this.thumb.dom){
\r
11025 var local = this.innerEl.translatePoints(e.getXY());
\r
11026 this.onClickChange(local);
\r
11032 onClickChange : function(local){
\r
11033 if(local.top > this.clickRange[0] && local.top < this.clickRange[1]){
\r
11034 this.setValue(Ext.util.Format.round(this.reverseValue(local.left), this.decimalPrecision), undefined, true);
\r
11039 onKeyDown : function(e){
\r
11040 if(this.disabled){e.preventDefault();return;}
\r
11041 var k = e.getKey();
\r
11047 this.setValue(this.maxValue, undefined, true);
\r
11049 this.setValue(this.value+this.keyIncrement, undefined, true);
\r
11056 this.setValue(this.minValue, undefined, true);
\r
11058 this.setValue(this.value-this.keyIncrement, undefined, true);
\r
11062 e.preventDefault();
\r
11067 doSnap : function(value){
\r
11068 if(!this.increment || this.increment == 1 || !value) {
\r
11071 var newValue = value, inc = this.increment;
\r
11072 var m = value % inc;
\r
11077 }else if(m * 2 < -inc){
\r
11081 return newValue.constrain(this.minValue, this.maxValue);
\r
11085 afterRender : function(){
\r
11086 Ext.Slider.superclass.afterRender.apply(this, arguments);
\r
11087 if(this.value !== undefined){
\r
11088 var v = this.normalizeValue(this.value);
\r
11089 if(v !== this.value){
\r
11090 delete this.value;
\r
11091 this.setValue(v, false);
\r
11093 this.moveThumb(this.translateValue(v), false);
\r
11099 getRatio : function(){
\r
11100 var w = this.innerEl.getWidth();
\r
11101 var v = this.maxValue - this.minValue;
\r
11102 return v == 0 ? w : (w/v);
\r
11106 normalizeValue : function(v){
\r
11107 v = this.doSnap(v);
\r
11108 v = Ext.util.Format.round(v, this.decimalPrecision);
\r
11109 v = v.constrain(this.minValue, this.maxValue);
\r
11114 * Programmatically sets the value of the Slider. Ensures that the value is constrained within
\r
11115 * the minValue and maxValue.
\r
11116 * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
\r
11117 * @param {Boolean} animate Turn on or off animation, defaults to true
\r
11119 setValue : function(v, animate, changeComplete){
\r
11120 v = this.normalizeValue(v);
\r
11121 if(v !== this.value && this.fireEvent('beforechange', this, v, this.value) !== false){
\r
11123 this.moveThumb(this.translateValue(v), animate !== false);
\r
11124 this.fireEvent('change', this, v);
\r
11125 if(changeComplete){
\r
11126 this.fireEvent('changecomplete', this, v);
\r
11132 translateValue : function(v){
\r
11133 var ratio = this.getRatio();
\r
11134 return (v * ratio)-(this.minValue * ratio)-this.halfThumb;
\r
11137 reverseValue : function(pos){
\r
11138 var ratio = this.getRatio();
\r
11139 return (pos+this.halfThumb+(this.minValue * ratio))/ratio;
\r
11143 moveThumb: function(v, animate){
\r
11144 if(!animate || this.animate === false){
\r
11145 this.thumb.setLeft(v);
\r
11147 this.thumb.shift({left: v, stopFx: true, duration:.35});
\r
11152 focus : function(){
\r
11153 this.focusEl.focus(10);
\r
11157 onBeforeDragStart : function(e){
\r
11158 return !this.disabled;
\r
11162 onDragStart: function(e){
\r
11163 this.thumb.addClass('x-slider-thumb-drag');
\r
11164 this.dragging = true;
\r
11165 this.dragStartValue = this.value;
\r
11166 this.fireEvent('dragstart', this, e);
\r
11170 onDrag: function(e){
\r
11171 var pos = this.innerEl.translatePoints(this.tracker.getXY());
\r
11172 this.setValue(Ext.util.Format.round(this.reverseValue(pos.left), this.decimalPrecision), false);
\r
11173 this.fireEvent('drag', this, e);
\r
11177 onDragEnd: function(e){
\r
11178 this.thumb.removeClass('x-slider-thumb-drag');
\r
11179 this.dragging = false;
\r
11180 this.fireEvent('dragend', this, e);
\r
11181 if(this.dragStartValue != this.value){
\r
11182 this.fireEvent('changecomplete', this, this.value);
\r
11187 onResize : function(w, h){
\r
11188 this.innerEl.setWidth(w - (this.el.getPadding('l') + this.endEl.getPadding('r')));
\r
11189 this.syncThumb();
\r
11193 onDisable: function(){
\r
11194 Ext.Slider.superclass.onDisable.call(this);
\r
11195 this.thumb.addClass(this.disabledClass);
\r
11197 //IE breaks when using overflow visible and opacity other than 1.
\r
11198 //Create a place holder for the thumb and display it.
\r
11199 var xy = this.thumb.getXY();
\r
11200 this.thumb.hide();
\r
11201 this.innerEl.addClass(this.disabledClass).dom.disabled = true;
\r
11202 if (!this.thumbHolder){
\r
11203 this.thumbHolder = this.endEl.createChild({cls: 'x-slider-thumb ' + this.disabledClass});
\r
11205 this.thumbHolder.show().setXY(xy);
\r
11210 onEnable: function(){
\r
11211 Ext.Slider.superclass.onEnable.call(this);
\r
11212 this.thumb.removeClass(this.disabledClass);
\r
11214 this.innerEl.removeClass(this.disabledClass).dom.disabled = false;
\r
11215 if (this.thumbHolder){
\r
11216 this.thumbHolder.hide();
\r
11218 this.thumb.show();
\r
11219 this.syncThumb();
\r
11224 * Synchronizes the thumb position to the proper proportion of the total component width based
\r
11225 * on the current slider {@link #value}. This will be called automatically when the Slider
\r
11226 * is resized by a layout, but if it is rendered auto width, this method can be called from
\r
11227 * another resize handler to sync the Slider if necessary.
\r
11229 syncThumb : function(){
\r
11230 if(this.rendered){
\r
11231 this.moveThumb(this.translateValue(this.value));
\r
11236 * Returns the current value of the slider
\r
11237 * @return {Number} The current value of the slider
\r
11239 getValue : function(){
\r
11240 return this.value;
\r
11243 Ext.reg('slider', Ext.Slider);
\r
11245 // private class to support vertical sliders
\r
11246 Ext.Slider.Vertical = {
\r
11247 onResize : function(w, h){
\r
11248 this.innerEl.setHeight(h - (this.el.getPadding('t') + this.endEl.getPadding('b')));
\r
11249 this.syncThumb();
\r
11252 getRatio : function(){
\r
11253 var h = this.innerEl.getHeight();
\r
11254 var v = this.maxValue - this.minValue;
\r
11258 moveThumb: function(v, animate){
\r
11259 if(!animate || this.animate === false){
\r
11260 this.thumb.setBottom(v);
\r
11262 this.thumb.shift({bottom: v, stopFx: true, duration:.35});
\r
11266 onDrag: function(e){
\r
11267 var pos = this.innerEl.translatePoints(this.tracker.getXY());
\r
11268 var bottom = this.innerEl.getHeight()-pos.top;
\r
11269 this.setValue(this.minValue + Ext.util.Format.round(bottom/this.getRatio(), this.decimalPrecision), false);
\r
11270 this.fireEvent('drag', this, e);
\r
11273 onClickChange : function(local){
\r
11274 if(local.left > this.clickRange[0] && local.left < this.clickRange[1]){
\r
11275 var bottom = this.innerEl.getHeight()-local.top;
\r
11276 this.setValue(this.minValue + Ext.util.Format.round(bottom/this.getRatio(), this.decimalPrecision), undefined, true);
\r
11280 * @class Ext.ProgressBar
\r
11281 * @extends Ext.BoxComponent
\r
11282 * <p>An updateable progress bar component. The progress bar supports two different modes: manual and automatic.</p>
\r
11283 * <p>In manual mode, you are responsible for showing, updating (via {@link #updateProgress}) and clearing the
\r
11284 * progress bar as needed from your own code. This method is most appropriate when you want to show progress
\r
11285 * throughout an operation that has predictable points of interest at which you can update the control.</p>
\r
11286 * <p>In automatic mode, you simply call {@link #wait} and let the progress bar run indefinitely, only clearing it
\r
11287 * once the operation is complete. You can optionally have the progress bar wait for a specific amount of time
\r
11288 * and then clear itself. Automatic mode is most appropriate for timed operations or asynchronous operations in
\r
11289 * which you have no need for indicating intermediate progress.</p>
\r
11290 * @cfg {Float} value A floating point value between 0 and 1 (e.g., .5, defaults to 0)
\r
11291 * @cfg {String} text The progress bar text (defaults to '')
\r
11292 * @cfg {Mixed} textEl The element to render the progress text to (defaults to the progress
\r
11293 * bar's internal text element)
\r
11294 * @cfg {String} id The progress bar element's id (defaults to an auto-generated id)
\r
11295 * @xtype progress
\r
11297 Ext.ProgressBar = Ext.extend(Ext.BoxComponent, {
\r
11299 * @cfg {String} baseCls
\r
11300 * The base CSS class to apply to the progress bar's wrapper element (defaults to 'x-progress')
\r
11302 baseCls : 'x-progress',
\r
11305 * @cfg {Boolean} animate
\r
11306 * True to animate the progress bar during transitions (defaults to false)
\r
11311 waitTimer : null,
\r
11314 initComponent : function(){
\r
11315 Ext.ProgressBar.superclass.initComponent.call(this);
\r
11319 * Fires after each update interval
\r
11320 * @param {Ext.ProgressBar} this
\r
11321 * @param {Number} The current progress value
\r
11322 * @param {String} The current progress text
\r
11329 onRender : function(ct, position){
\r
11330 var tpl = new Ext.Template(
\r
11331 '<div class="{cls}-wrap">',
\r
11332 '<div class="{cls}-inner">',
\r
11333 '<div class="{cls}-bar">',
\r
11334 '<div class="{cls}-text">',
\r
11335 '<div> </div>',
\r
11338 '<div class="{cls}-text {cls}-text-back">',
\r
11339 '<div> </div>',
\r
11345 this.el = position ? tpl.insertBefore(position, {cls: this.baseCls}, true)
\r
11346 : tpl.append(ct, {cls: this.baseCls}, true);
\r
11349 this.el.dom.id = this.id;
\r
11351 var inner = this.el.dom.firstChild;
\r
11352 this.progressBar = Ext.get(inner.firstChild);
\r
11355 //use an external text el
\r
11356 this.textEl = Ext.get(this.textEl);
\r
11357 delete this.textTopEl;
\r
11359 //setup our internal layered text els
\r
11360 this.textTopEl = Ext.get(this.progressBar.dom.firstChild);
\r
11361 var textBackEl = Ext.get(inner.childNodes[1]);
\r
11362 this.textTopEl.setStyle("z-index", 99).addClass('x-hidden');
\r
11363 this.textEl = new Ext.CompositeElement([this.textTopEl.dom.firstChild, textBackEl.dom.firstChild]);
\r
11364 this.textEl.setWidth(inner.offsetWidth);
\r
11366 this.progressBar.setHeight(inner.offsetHeight);
\r
11370 afterRender : function(){
\r
11371 Ext.ProgressBar.superclass.afterRender.call(this);
\r
11373 this.updateProgress(this.value, this.text);
\r
11375 this.updateText(this.text);
\r
11380 * Updates the progress bar value, and optionally its text. If the text argument is not specified,
\r
11381 * any existing text value will be unchanged. To blank out existing text, pass ''. Note that even
\r
11382 * if the progress bar value exceeds 1, it will never automatically reset -- you are responsible for
\r
11383 * determining when the progress is complete and calling {@link #reset} to clear and/or hide the control.
\r
11384 * @param {Float} value (optional) A floating point value between 0 and 1 (e.g., .5, defaults to 0)
\r
11385 * @param {String} text (optional) The string to display in the progress text element (defaults to '')
\r
11386 * @param {Boolean} animate (optional) Whether to animate the transition of the progress bar. If this value is
\r
11387 * not specified, the default for the class is used (default to false)
\r
11388 * @return {Ext.ProgressBar} this
\r
11390 updateProgress : function(value, text, animate){
\r
11391 this.value = value || 0;
\r
11393 this.updateText(text);
\r
11395 if(this.rendered){
\r
11396 var w = Math.floor(value*this.el.dom.firstChild.offsetWidth);
\r
11397 this.progressBar.setWidth(w, animate === true || (animate !== false && this.animate));
\r
11398 if(this.textTopEl){
\r
11399 //textTopEl should be the same width as the bar so overflow will clip as the bar moves
\r
11400 this.textTopEl.removeClass('x-hidden').setWidth(w);
\r
11403 this.fireEvent('update', this, value, text);
\r
11408 * Initiates an auto-updating progress bar. A duration can be specified, in which case the progress
\r
11409 * bar will automatically reset after a fixed amount of time and optionally call a callback function
\r
11410 * if specified. If no duration is passed in, then the progress bar will run indefinitely and must
\r
11411 * be manually cleared by calling {@link #reset}. The wait method accepts a config object with
\r
11412 * the following properties:
\r
11414 Property Type Description
\r
11415 ---------- ------------ ----------------------------------------------------------------------
\r
11416 duration Number The length of time in milliseconds that the progress bar should
\r
11417 run before resetting itself (defaults to undefined, in which case it
\r
11418 will run indefinitely until reset is called)
\r
11419 interval Number The length of time in milliseconds between each progress update
\r
11420 (defaults to 1000 ms)
\r
11421 animate Boolean Whether to animate the transition of the progress bar. If this value is
\r
11422 not specified, the default for the class is used.
\r
11423 increment Number The number of progress update segments to display within the progress
\r
11424 bar (defaults to 10). If the bar reaches the end and is still
\r
11425 updating, it will automatically wrap back to the beginning.
\r
11426 text String Optional text to display in the progress bar element (defaults to '').
\r
11427 fn Function A callback function to execute after the progress bar finishes auto-
\r
11428 updating. The function will be called with no arguments. This function
\r
11429 will be ignored if duration is not specified since in that case the
\r
11430 progress bar can only be stopped programmatically, so any required function
\r
11431 should be called by the same code after it resets the progress bar.
\r
11432 scope Object The scope that is passed to the callback function (only applies when
\r
11433 duration and fn are both passed).
\r
11438 var p = new Ext.ProgressBar({
\r
11439 renderTo: 'my-el'
\r
11442 //Wait for 5 seconds, then update the status el (progress bar will auto-reset)
\r
11444 interval: 100, //bar will move fast!
\r
11447 text: 'Updating...',
\r
11450 Ext.fly('status').update('Done!');
\r
11454 //Or update indefinitely until some async action completes, then reset manually
\r
11456 myAction.on('complete', function(){
\r
11458 Ext.fly('status').update('Done!');
\r
11461 * @param {Object} config (optional) Configuration options
\r
11462 * @return {Ext.ProgressBar} this
\r
11464 wait : function(o){
\r
11465 if(!this.waitTimer){
\r
11466 var scope = this;
\r
11468 this.updateText(o.text);
\r
11469 this.waitTimer = Ext.TaskMgr.start({
\r
11470 run: function(i){
\r
11471 var inc = o.increment || 10;
\r
11473 this.updateProgress(((((i+inc)%inc)+1)*(100/inc))*0.01, null, o.animate);
\r
11475 interval: o.interval || 1000,
\r
11476 duration: o.duration,
\r
11477 onStop: function(){
\r
11479 o.fn.apply(o.scope || this);
\r
11490 * Returns true if the progress bar is currently in a {@link #wait} operation
\r
11491 * @return {Boolean} True if waiting, else false
\r
11493 isWaiting : function(){
\r
11494 return this.waitTimer !== null;
\r
11498 * Updates the progress bar text. If specified, textEl will be updated, otherwise the progress
\r
11499 * bar itself will display the updated text.
\r
11500 * @param {String} text (optional) The string to display in the progress text element (defaults to '')
\r
11501 * @return {Ext.ProgressBar} this
\r
11503 updateText : function(text){
\r
11504 this.text = text || ' ';
\r
11505 if(this.rendered){
\r
11506 this.textEl.update(this.text);
\r
11512 * Synchronizes the inner bar width to the proper proportion of the total componet width based
\r
11513 * on the current progress {@link #value}. This will be called automatically when the ProgressBar
\r
11514 * is resized by a layout, but if it is rendered auto width, this method can be called from
\r
11515 * another resize handler to sync the ProgressBar if necessary.
\r
11517 syncProgressBar : function(){
\r
11519 this.updateProgress(this.value, this.text);
\r
11525 * Sets the size of the progress bar.
\r
11526 * @param {Number} width The new width in pixels
\r
11527 * @param {Number} height The new height in pixels
\r
11528 * @return {Ext.ProgressBar} this
\r
11530 setSize : function(w, h){
\r
11531 Ext.ProgressBar.superclass.setSize.call(this, w, h);
\r
11532 if(this.textTopEl){
\r
11533 var inner = this.el.dom.firstChild;
\r
11534 this.textEl.setSize(inner.offsetWidth, inner.offsetHeight);
\r
11536 this.syncProgressBar();
\r
11541 * Resets the progress bar value to 0 and text to empty string. If hide = true, the progress
\r
11542 * bar will also be hidden (using the {@link #hideMode} property internally).
\r
11543 * @param {Boolean} hide (optional) True to hide the progress bar (defaults to false)
\r
11544 * @return {Ext.ProgressBar} this
\r
11546 reset : function(hide){
\r
11547 this.updateProgress(0);
\r
11548 if(this.textTopEl){
\r
11549 this.textTopEl.addClass('x-hidden');
\r
11551 if(this.waitTimer){
\r
11552 this.waitTimer.onStop = null; //prevent recursion
\r
11553 Ext.TaskMgr.stop(this.waitTimer);
\r
11554 this.waitTimer = null;
\r
11556 if(hide === true){
\r
11562 Ext.reg('progress', Ext.ProgressBar);