Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / Component.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.Component
17  * @extends Ext.AbstractComponent
18  * <p>Base class for all Ext components.  All subclasses of Component may participate in the automated
19  * Ext component lifecycle of creation, rendering and destruction which is provided by the {@link Ext.container.Container Container} class.
20  * Components may be added to a Container through the {@link Ext.container.Container#items items} config option at the time the Container is created,
21  * or they may be added dynamically via the {@link Ext.container.Container#add add} method.</p>
22  * <p>The Component base class has built-in support for basic hide/show and enable/disable and size control behavior.</p>
23  * <p>All Components are registered with the {@link Ext.ComponentManager} on construction so that they can be referenced at any time via
24  * {@link Ext#getCmp Ext.getCmp}, passing the {@link #id}.</p>
25  * <p>All user-developed visual widgets that are required to participate in automated lifecycle and size management should subclass Component.</p>
26  * <p>See the <a href="http://sencha.com/learn/Tutorial:Creating_new_UI_controls">Creating new UI controls</a> tutorial for details on how
27  * and to either extend or augment ExtJs base classes to create custom Components.</p>
28  * <p>Every component has a specific xtype, which is its Ext-specific type name, along with methods for checking the
29  * xtype like {@link #getXType} and {@link #isXType}. This is the list of all valid xtypes:</p>
30  * <pre>
31 xtype            Class
32 -------------    ------------------
33 button           {@link Ext.button.Button}
34 buttongroup      {@link Ext.container.ButtonGroup}
35 colorpalette     {@link Ext.picker.Color}
36 component        {@link Ext.Component}
37 container        {@link Ext.container.Container}
38 cycle            {@link Ext.button.Cycle}
39 dataview         {@link Ext.view.View}
40 datepicker       {@link Ext.picker.Date}
41 editor           {@link Ext.Editor}
42 editorgrid       {@link Ext.grid.plugin.Editing}
43 grid             {@link Ext.grid.Panel}
44 multislider      {@link Ext.slider.Multi}
45 panel            {@link Ext.panel.Panel}
46 progress         {@link Ext.ProgressBar}
47 slider           {@link Ext.slider.Single}
48 spacer           {@link Ext.toolbar.Spacer}
49 splitbutton      {@link Ext.button.Split}
50 tabpanel         {@link Ext.tab.Panel}
51 treepanel        {@link Ext.tree.Panel}
52 viewport         {@link Ext.container.Viewport}
53 window           {@link Ext.window.Window}
54
55 Toolbar components
56 ---------------------------------------
57 paging           {@link Ext.toolbar.Paging}
58 toolbar          {@link Ext.toolbar.Toolbar}
59 tbfill           {@link Ext.toolbar.Fill}
60 tbitem           {@link Ext.toolbar.Item}
61 tbseparator      {@link Ext.toolbar.Separator}
62 tbspacer         {@link Ext.toolbar.Spacer}
63 tbtext           {@link Ext.toolbar.TextItem}
64
65 Menu components
66 ---------------------------------------
67 menu             {@link Ext.menu.Menu}
68 menucheckitem    {@link Ext.menu.CheckItem}
69 menuitem         {@link Ext.menu.Item}
70 menuseparator    {@link Ext.menu.Separator}
71 menutextitem     {@link Ext.menu.Item}
72
73 Form components
74 ---------------------------------------
75 form             {@link Ext.form.Panel}
76 checkbox         {@link Ext.form.field.Checkbox}
77 combo            {@link Ext.form.field.ComboBox}
78 datefield        {@link Ext.form.field.Date}
79 displayfield     {@link Ext.form.field.Display}
80 field            {@link Ext.form.field.Base}
81 fieldset         {@link Ext.form.FieldSet}
82 hidden           {@link Ext.form.field.Hidden}
83 htmleditor       {@link Ext.form.field.HtmlEditor}
84 label            {@link Ext.form.Label}
85 numberfield      {@link Ext.form.field.Number}
86 radio            {@link Ext.form.field.Radio}
87 radiogroup       {@link Ext.form.RadioGroup}
88 textarea         {@link Ext.form.field.TextArea}
89 textfield        {@link Ext.form.field.Text}
90 timefield        {@link Ext.form.field.Time}
91 trigger          {@link Ext.form.field.Trigger}
92
93 Chart components
94 ---------------------------------------
95 chart            {@link Ext.chart.Chart}
96 barchart         {@link Ext.chart.series.Bar}
97 columnchart      {@link Ext.chart.series.Column}
98 linechart        {@link Ext.chart.series.Line}
99 piechart         {@link Ext.chart.series.Pie}
100
101 </pre><p>
102  * It should not usually be necessary to instantiate a Component because there are provided subclasses which implement specialized Component
103  * use cases which over most application needs. However it is possible to instantiate a base Component, and it will be renderable,
104  * or will particpate in layouts as the child item of a Container:
105 {@img Ext.Component/Ext.Component.png Ext.Component component}
106 <pre><code>
107     Ext.create('Ext.Component', {
108         html: 'Hello world!',
109         width: 300,
110         height: 200,
111         padding: 20,
112         style: {
113             color: '#FFFFFF',
114             backgroundColor:'#000000'
115         },
116         renderTo: Ext.getBody()
117     });
118 </code></pre>
119  *</p>
120  *<p>The Component above creates its encapsulating <code>div</code> upon render, and use the configured HTML as content. More complex
121  * internal structure may be created using the {@link #renderTpl} configuration, although to display database-derived mass
122  * data, it is recommended that an ExtJS data-backed Component such as a {@link Ext.view.View View}, or
123  * {@link Ext.grid.Panel GridPanel}, or {@link Ext.tree.Panel TreePanel} be used.</p>
124  * @constructor
125  * Creates new Component.
126  * @param {Ext.core.Element/String/Object} config The configuration options may be specified as either:
127  * <div class="mdetail-params"><ul>
128  * <li><b>an element</b> :
129  * <p class="sub-desc">it is set as the internal element and its id used as the component id</p></li>
130  * <li><b>a string</b> :
131  * <p class="sub-desc">it is assumed to be the id of an existing element and is used as the component id</p></li>
132  * <li><b>anything else</b> :
133  * <p class="sub-desc">it is assumed to be a standard config object and is applied to the component</p></li>
134  * </ul></div>
135  */
136
137 Ext.define('Ext.Component', {
138
139     /* Begin Definitions */
140
141     alias: ['widget.component', 'widget.box'],
142
143     extend: 'Ext.AbstractComponent',
144
145     requires: [
146         'Ext.util.DelayedTask'
147     ],
148
149     uses: [
150         'Ext.Layer',
151         'Ext.resizer.Resizer',
152         'Ext.util.ComponentDragger'
153     ],
154
155     mixins: {
156         floating: 'Ext.util.Floating'
157     },
158
159     statics: {
160         // Collapse/expand directions
161         DIRECTION_TOP: 'top',
162         DIRECTION_RIGHT: 'right',
163         DIRECTION_BOTTOM: 'bottom',
164         DIRECTION_LEFT: 'left',
165
166         VERTICAL_DIRECTION: /^(?:top|bottom)$/
167     },
168
169     /* End Definitions */
170
171     /**
172      * @cfg {Mixed} resizable
173      * <p>Specify as <code>true</code> to apply a {@link Ext.resizer.Resizer Resizer} to this Component
174      * after rendering.</p>
175      * <p>May also be specified as a config object to be passed to the constructor of {@link Ext.resizer.Resizer Resizer}
176      * to override any defaults. By default the Component passes its minimum and maximum size, and uses
177      * <code>{@link Ext.resizer.Resizer#dynamic}: false</code></p>
178      */
179
180     /**
181      * @cfg {String} resizeHandles
182      * A valid {@link Ext.resizer.Resizer} handles config string (defaults to 'all').  Only applies when resizable = true.
183      */
184     resizeHandles: 'all',
185
186     /**
187      * @cfg {Boolean} autoScroll
188      * <code>true</code> to use overflow:'auto' on the components layout element and show scroll bars automatically when
189      * necessary, <code>false</code> to clip any overflowing content (defaults to <code>false</code>).
190      */
191
192     /**
193      * @cfg {Boolean} floating
194      * <p>Specify as true to float the Component outside of the document flow using CSS absolute positioning.</p>
195      * <p>Components such as {@link Ext.window.Window Window}s and {@link Ext.menu.Menu Menu}s are floating
196      * by default.</p>
197      * <p>Floating Components that are programatically {@link Ext.Component#render rendered} will register themselves with the global
198      * {@link Ext.WindowManager ZIndexManager}</p>
199      * <h3 class="pa">Floating Components as child items of a Container</h3>
200      * <p>A floating Component may be used as a child item of a Container. This just allows the floating Component to seek a ZIndexManager by
201      * examining the ownerCt chain.</p>
202      * <p>When configured as floating, Components acquire, at render time, a {@link Ext.ZIndexManager ZIndexManager} which manages a stack
203      * of related floating Components. The ZIndexManager brings a single floating Component to the top of its stack when
204      * the Component's {@link #toFront} method is called.</p>
205      * <p>The ZIndexManager is found by traversing up the {@link #ownerCt} chain to find an ancestor which itself is floating. This is so that
206      * descendant floating Components of floating <i>Containers</i> (Such as a ComboBox dropdown within a Window) can have its zIndex managed relative
207      * to any siblings, but always <b>above</b> that floating ancestor Container.</p>
208      * <p>If no floating ancestor is found, a floating Component registers itself with the default {@link Ext.WindowManager ZIndexManager}.</p>
209      * <p>Floating components <i>do not participate in the Container's layout</i>. Because of this, they are not rendered until you explicitly
210      * {@link #show} them.</p>
211      * <p>After rendering, the ownerCt reference is deleted, and the {@link #floatParent} property is set to the found floating ancestor Container.
212      * If no floating ancestor Container was found the {@link #floatParent} property will not be set.</p>
213      */
214     floating: false,
215
216     /**
217      * @cfg {Boolean} toFrontOnShow
218      * <p>True to automatically call {@link #toFront} when the {@link #show} method is called
219      * on an already visible, floating component (default is <code>true</code>).</p>
220      */
221     toFrontOnShow: true,
222
223     /**
224      * <p>Optional. Only present for {@link #floating} Components after they have been rendered.</p>
225      * <p>A reference to the ZIndexManager which is managing this Component's z-index.</p>
226      * <p>The {@link Ext.ZIndexManager ZIndexManager} maintains a stack of floating Component z-indices, and also provides a single modal
227      * mask which is insert just beneath the topmost visible modal floating Component.</p>
228      * <p>Floating Components may be {@link #toFront brought to the front} or {@link #toBack sent to the back} of the z-index stack.</p>
229      * <p>This defaults to the global {@link Ext.WindowManager ZIndexManager} for floating Components that are programatically
230      * {@link Ext.Component#render rendered}.</p>
231      * <p>For {@link #floating} Components which are added to a Container, the ZIndexManager is acquired from the first ancestor Container found
232      * which is floating, or if not found the global {@link Ext.WindowManager ZIndexManager} is used.</p>
233      * <p>See {@link #floating} and {@link #floatParent}</p>
234      * @property zIndexManager
235      * @type Ext.ZIndexManager
236      */
237
238      /**
239       * <p>Optional. Only present for {@link #floating} Components which were inserted as descendant items of floating Containers.</p>
240       * <p>Floating Components that are programatically {@link Ext.Component#render rendered} will not have a <code>floatParent</code> property.</p>
241       * <p>For {@link #floating} Components which are child items of a Container, the floatParent will be the floating ancestor Container which is
242       * responsible for the base z-index value of all its floating descendants. It provides a {@link Ext.ZIndexManager ZIndexManager} which provides
243       * z-indexing services for all its descendant floating Components.</p>
244       * <p>For example, the dropdown {@link Ext.view.BoundList BoundList} of a ComboBox which is in a Window will have the Window as its
245       * <code>floatParent</code></p>
246       * <p>See {@link #floating} and {@link #zIndexManager}</p>
247       * @property floatParent
248       * @type Ext.Container
249       */
250
251     /**
252      * @cfg {Mixed} draggable
253      * <p>Specify as true to make a {@link #floating} Component draggable using the Component's encapsulating element as the drag handle.</p>
254      * <p>This may also be specified as a config object for the {@link Ext.util.ComponentDragger ComponentDragger} which is instantiated to perform dragging.</p>
255      * <p>For example to create a Component which may only be dragged around using a certain internal element as the drag handle,
256      * use the delegate option:</p>
257      * <code><pre>
258 new Ext.Component({
259     constrain: true,
260     floating:true,
261     style: {
262         backgroundColor: '#fff',
263         border: '1px solid black'
264     },
265     html: '&lt;h1 style="cursor:move"&gt;The title&lt;/h1&gt;&lt;p&gt;The content&lt;/p&gt;',
266     draggable: {
267         delegate: 'h1'
268     }
269 }).show();
270 </pre></code>
271      */
272
273     /**
274      * @cfg {Boolean} maintainFlex
275      * <p><b>Only valid when a sibling element of a {@link Ext.resizer.Splitter Splitter} within a {@link Ext.layout.container.VBox VBox} or
276      * {@link Ext.layout.container.HBox HBox} layout.</b></p>
277      * <p>Specifies that if an immediate sibling Splitter is moved, the Component on the <i>other</i> side is resized, and this
278      * Component maintains its configured {@link Ext.layout.container.Box#flex flex} value.</p>
279      */
280
281     hideMode: 'display',
282     // Deprecate 5.0
283     hideParent: false,
284
285     ariaRole: 'presentation',
286
287     bubbleEvents: [],
288
289     actionMode: 'el',
290     monPropRe: /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/,
291
292     //renderTpl: new Ext.XTemplate(
293     //    '<div id="{id}" class="{baseCls} {cls} {cmpCls}<tpl if="typeof ui !== \'undefined\'"> {uiBase}-{ui}</tpl>"<tpl if="typeof style !== \'undefined\'"> style="{style}"</tpl>></div>', {
294     //        compiled: true,
295     //        disableFormats: true
296     //    }
297     //),
298     constructor: function(config) {
299         config = config || {};
300         if (config.initialConfig) {
301
302             // Being initialized from an Ext.Action instance...
303             if (config.isAction) {
304                 this.baseAction = config;
305             }
306             config = config.initialConfig;
307             // component cloning / action set up
308         }
309         else if (config.tagName || config.dom || Ext.isString(config)) {
310             // element object
311             config = {
312                 applyTo: config,
313                 id: config.id || config
314             };
315         }
316
317         this.callParent([config]);
318
319         // If we were configured from an instance of Ext.Action, (or configured with a baseAction option),
320         // register this Component as one of its items
321         if (this.baseAction){
322             this.baseAction.addComponent(this);
323         }
324     },
325
326     initComponent: function() {
327         var me = this;
328
329         if (me.listeners) {
330             me.on(me.listeners);
331             delete me.listeners;
332         }
333         me.enableBubble(me.bubbleEvents);
334         me.mons = [];
335     },
336
337     // private
338     afterRender: function() {
339         var me = this,
340             resizable = me.resizable;
341
342         if (me.floating) {
343             me.makeFloating(me.floating);
344         } else {
345             me.el.setVisibilityMode(Ext.core.Element[me.hideMode.toUpperCase()]);
346         }
347
348         if (Ext.isDefined(me.autoScroll)) {
349             me.setAutoScroll(me.autoScroll);
350         }
351         me.callParent();
352
353         if (!(me.x && me.y) && (me.pageX || me.pageY)) {
354             me.setPagePosition(me.pageX, me.pageY);
355         }
356
357         if (resizable) {
358             me.initResizable(resizable);
359         }
360
361         if (me.draggable) {
362             me.initDraggable();
363         }
364
365         me.initAria();
366     },
367
368     initAria: function() {
369         var actionEl = this.getActionEl(),
370             role = this.ariaRole;
371         if (role) {
372             actionEl.dom.setAttribute('role', role);
373         }
374     },
375
376     /**
377      * Sets the overflow on the content element of the component.
378      * @param {Boolean} scroll True to allow the Component to auto scroll.
379      * @return {Ext.Component} this
380      */
381     setAutoScroll : function(scroll){
382         var me = this,
383             targetEl;
384         scroll = !!scroll;
385         if (me.rendered) {
386             targetEl = me.getTargetEl();
387             targetEl.setStyle('overflow', scroll ? 'auto' : '');
388             if (scroll && (Ext.isIE6 || Ext.isIE7)) {
389                 // The scrollable container element must be non-statically positioned or IE6/7 will make
390                 // positioned children stay in place rather than scrolling with the rest of the content
391                 targetEl.position();
392             }
393         }
394         me.autoScroll = scroll;
395         return me;
396     },
397
398     // private
399     makeFloating : function(cfg){
400         this.mixins.floating.constructor.call(this, cfg);
401     },
402
403     initResizable: function(resizable) {
404         resizable = Ext.apply({
405             target: this,
406             dynamic: false,
407             constrainTo: this.constrainTo,
408             handles: this.resizeHandles
409         }, resizable);
410         resizable.target = this;
411         this.resizer = Ext.create('Ext.resizer.Resizer', resizable);
412     },
413
414     getDragEl: function() {
415         return this.el;
416     },
417
418     initDraggable: function() {
419         var me = this,
420             ddConfig = Ext.applyIf({
421                 el: this.getDragEl(),
422                 constrainTo: me.constrainTo || (me.floatParent ? me.floatParent.getTargetEl() : me.el.dom.parentNode)
423             }, this.draggable);
424
425         // Add extra configs if Component is specified to be constrained
426         if (me.constrain || me.constrainDelegate) {
427             ddConfig.constrain = me.constrain;
428             ddConfig.constrainDelegate = me.constrainDelegate;
429         }
430
431         this.dd = Ext.create('Ext.util.ComponentDragger', this, ddConfig);
432     },
433
434     /**
435      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
436      * This method fires the {@link #move} event.
437      * @param {Number} left The new left
438      * @param {Number} top The new top
439      * @param {Mixed} animate If true, the Component is <i>animated</i> into its new position. You may also pass an animation configuration.
440      * @return {Ext.Component} this
441      */
442     setPosition: function(x, y, animate) {
443         var me = this,
444             el = me.el,
445             to = {},
446             adj, adjX, adjY, xIsNumber, yIsNumber;
447
448         if (Ext.isArray(x)) {
449             animate = y;
450             y = x[1];
451             x = x[0];
452         }
453         me.x = x;
454         me.y = y;
455
456         if (!me.rendered) {
457             return me;
458         }
459
460         adj = me.adjustPosition(x, y);
461         adjX = adj.x;
462         adjY = adj.y;
463         xIsNumber = Ext.isNumber(adjX);
464         yIsNumber = Ext.isNumber(adjY);
465
466         if (xIsNumber || yIsNumber) {
467             if (animate) {
468                 if (xIsNumber) {
469                     to.left = adjX;
470                 }
471                 if (yIsNumber) {
472                     to.top = adjY;
473                 }
474
475                 me.stopAnimation();
476                 me.animate(Ext.apply({
477                     duration: 1000,
478                     listeners: {
479                         afteranimate: Ext.Function.bind(me.afterSetPosition, me, [adjX, adjY])
480                     },
481                     to: to
482                 }, animate));
483             }
484             else {
485                 if (!xIsNumber) {
486                     el.setTop(adjY);
487                 }
488                 else if (!yIsNumber) {
489                     el.setLeft(adjX);
490                 }
491                 else {
492                     el.setLeftTop(adjX, adjY);
493                 }
494                 me.afterSetPosition(adjX, adjY);
495             }
496         }
497         return me;
498     },
499
500     /**
501      * @private Template method called after a Component has been positioned.
502      */
503     afterSetPosition: function(ax, ay) {
504         this.onPosition(ax, ay);
505         this.fireEvent('move', this, ax, ay);
506     },
507
508     showAt: function(x, y, animate) {
509         // A floating Component is positioned relative to its ownerCt if any.
510         if (this.floating) {
511             this.setPosition(x, y, animate);
512         } else {
513             this.setPagePosition(x, y, animate);
514         }
515         this.show();
516     },
517
518     /**
519      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
520      * This method fires the {@link #move} event.
521      * @param {Number} x The new x position
522      * @param {Number} y The new y position
523      * @param {Mixed} animate If passed, the Component is <i>animated</i> into its new position. If this parameter
524      * is a number, it is used as the animation duration in milliseconds.
525      * @return {Ext.Component} this
526      */
527     setPagePosition: function(x, y, animate) {
528         var me = this,
529             p;
530
531         if (Ext.isArray(x)) {
532             y = x[1];
533             x = x[0];
534         }
535         me.pageX = x;
536         me.pageY = y;
537         if (me.floating && me.floatParent) {
538             // Floating Components being positioned in their ownerCt have to be made absolute
539             p = me.floatParent.getTargetEl().getViewRegion();
540             if (Ext.isNumber(x) && Ext.isNumber(p.left)) {
541                 x -= p.left;
542             }
543             if (Ext.isNumber(y) && Ext.isNumber(p.top)) {
544                 y -= p.top;
545             }
546             me.setPosition(x, y, animate);
547         }
548         else {
549             p = me.el.translatePoints(x, y);
550             me.setPosition(p.left, p.top, animate);
551         }
552         return me;
553     },
554
555     /**
556      * Gets the current box measurements of the component's underlying element.
557      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
558      * @return {Object} box An object in the format {x, y, width, height}
559      */
560     getBox : function(local){
561         var pos = this.getPosition(local);
562         var s = this.getSize();
563         s.x = pos[0];
564         s.y = pos[1];
565         return s;
566     },
567
568     /**
569      * Sets the current box measurements of the component's underlying element.
570      * @param {Object} box An object in the format {x, y, width, height}
571      * @return {Ext.Component} this
572      */
573     updateBox : function(box){
574         this.setSize(box.width, box.height);
575         this.setPagePosition(box.x, box.y);
576         return this;
577     },
578
579     // Include margins
580     getOuterSize: function() {
581         var el = this.el;
582         return {
583             width: el.getWidth() + el.getMargin('lr'),
584             height: el.getHeight() + el.getMargin('tb')
585         };
586     },
587
588     // private
589     adjustSize: function(w, h) {
590         if (this.autoWidth) {
591             w = 'auto';
592         }
593
594         if (this.autoHeight) {
595             h = 'auto';
596         }
597
598         return {
599             width: w,
600             height: h
601         };
602     },
603
604     // private
605     adjustPosition: function(x, y) {
606
607         // Floating Components being positioned in their ownerCt have to be made absolute
608         if (this.floating && this.floatParent) {
609             var o = this.floatParent.getTargetEl().getViewRegion();
610             x += o.left;
611             y += o.top;
612         }
613
614         return {
615             x: x,
616             y: y
617         };
618     },
619
620     /**
621      * Gets the current XY position of the component's underlying element.
622      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
623      * @return {Array} The XY position of the element (e.g., [100, 200])
624      */
625     getPosition: function(local) {
626         var el = this.el,
627             xy;
628
629         if (local === true) {
630             return [el.getLeft(true), el.getTop(true)];
631         }
632         xy = this.xy || el.getXY();
633
634         // Floating Components in an ownerCt have to have their positions made relative
635         if (this.floating && this.floatParent) {
636             var o = this.floatParent.getTargetEl().getViewRegion();
637             xy[0] -= o.left;
638             xy[1] -= o.top;
639         }
640         return xy;
641     },
642
643     // Todo: add in xtype prefix support
644     getId: function() {
645         return this.id || (this.id = (this.getXType() || 'ext-comp') + '-' + this.getAutoId());
646     },
647
648     onEnable: function() {
649         var actionEl = this.getActionEl();
650         actionEl.dom.removeAttribute('aria-disabled');
651         actionEl.dom.disabled = false;
652         this.callParent();
653     },
654
655     onDisable: function() {
656         var actionEl = this.getActionEl();
657         actionEl.dom.setAttribute('aria-disabled', true);
658         actionEl.dom.disabled = true;
659         this.callParent();
660     },
661
662     /**
663      * <p>Shows this Component, rendering it first if {@link #autoRender} or {@link #floating} are <code>true</code>.</p>
664      * <p>After being shown, a {@link #floating} Component (such as a {@link Ext.window.Window}), is activated it and brought to the front of
665      * its {@link #zIndexManager z-index stack}.</p>
666      * @param {String/Element} animateTarget Optional, and <b>only valid for {@link #floating} Components such as
667      * {@link Ext.window.Window Window}s or {@link Ext.tip.ToolTip ToolTip}s, or regular Components which have been configured
668      * with <code>floating: true</code>.</b> The target from which the Component should
669      * animate from while opening (defaults to null with no animation)
670      * @param {Function} callback (optional) A callback function to call after the Component is displayed. Only necessary if animation was specified.
671      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this Component.
672      * @return {Component} this
673      */
674     show: function(animateTarget, cb, scope) {
675         if (this.rendered && this.isVisible()) {
676             if (this.toFrontOnShow && this.floating) {
677                 this.toFront();
678             }
679         } else if (this.fireEvent('beforeshow', this) !== false) {
680             this.hidden = false;
681
682             // Render on first show if there is an autoRender config, or if this is a floater (Window, Menu, BoundList etc).
683             if (!this.rendered && (this.autoRender || this.floating)) {
684                 this.doAutoRender();
685             }
686             if (this.rendered) {
687                 this.beforeShow();
688                 this.onShow.apply(this, arguments);
689
690                 // Notify any owning Container unless it's suspended.
691                 // Floating Components do not participate in layouts.
692                 if (this.ownerCt && !this.floating && !(this.ownerCt.suspendLayout || this.ownerCt.layout.layoutBusy)) {
693                     this.ownerCt.doLayout();
694                 }
695                 this.afterShow.apply(this, arguments);
696             }
697         }
698         return this;
699     },
700
701     beforeShow: Ext.emptyFn,
702
703     // Private. Override in subclasses where more complex behaviour is needed.
704     onShow: function() {
705         var me = this;
706
707         me.el.show();
708         if (this.floating && this.constrain) {
709             this.doConstrain();
710         }
711         me.callParent(arguments);
712     },
713
714     afterShow: function(animateTarget, cb, scope) {
715         var me = this,
716             fromBox,
717             toBox,
718             ghostPanel;
719
720         // Default to configured animate target if none passed
721         animateTarget = animateTarget || me.animateTarget;
722
723         // Need to be able to ghost the Component
724         if (!me.ghost) {
725             animateTarget = null;
726         }
727         // If we're animating, kick of an animation of the ghost from the target to the *Element* current box
728         if (animateTarget) {
729             animateTarget = animateTarget.el ? animateTarget.el : Ext.get(animateTarget);
730             toBox = me.el.getBox();
731             fromBox = animateTarget.getBox();
732             fromBox.width += 'px';
733             fromBox.height += 'px';
734             toBox.width += 'px';
735             toBox.height += 'px';
736             me.el.addCls(Ext.baseCSSPrefix + 'hide-offsets');
737             ghostPanel = me.ghost();
738             ghostPanel.el.stopAnimation();
739
740             ghostPanel.el.animate({
741                 from: fromBox,
742                 to: toBox,
743                 listeners: {
744                     afteranimate: function() {
745                         delete ghostPanel.componentLayout.lastComponentSize;
746                         me.unghost();
747                         me.el.removeCls(Ext.baseCSSPrefix + 'hide-offsets');
748                         if (me.floating) {
749                             me.toFront();
750                         }
751                         Ext.callback(cb, scope || me);
752                     }
753                 }
754             });
755         }
756         else {
757             if (me.floating) {
758                 me.toFront();
759             }
760             Ext.callback(cb, scope || me);
761         }
762         me.fireEvent('show', me);
763     },
764
765     /**
766      * Hides this Component, setting it to invisible using the configured {@link #hideMode}.
767      * @param {String/Element/Component} animateTarget Optional, and <b>only valid for {@link #floating} Components such as
768      * {@link Ext.window.Window Window}s or {@link Ext.tip.ToolTip ToolTip}s, or regular Components which have been configured
769      * with <code>floating: true</code>.</b>.
770      * The target to which the Component should animate while hiding (defaults to null with no animation)
771      * @param {Function} callback (optional) A callback function to call after the Component is hidden.
772      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this Component.
773      * @return {Ext.Component} this
774      */
775     hide: function() {
776
777         // Clear the flag which is set if a floatParent was hidden while this is visible.
778         // If a hide operation was subsequently called, that pending show must be hidden.
779         this.showOnParentShow = false;
780
781         if (!(this.rendered && !this.isVisible()) && this.fireEvent('beforehide', this) !== false) {
782             this.hidden = true;
783             if (this.rendered) {
784                 this.onHide.apply(this, arguments);
785
786                 // Notify any owning Container unless it's suspended.
787                 // Floating Components do not participate in layouts.
788                 if (this.ownerCt && !this.floating && !(this.ownerCt.suspendLayout || this.ownerCt.layout.layoutBusy)) {
789                     this.ownerCt.doLayout();
790                 }
791             }
792         }
793         return this;
794     },
795
796     // Possibly animate down to a target element.
797     onHide: function(animateTarget, cb, scope) {
798         var me = this,
799             ghostPanel,
800             toBox;
801
802         // Default to configured animate target if none passed
803         animateTarget = animateTarget || me.animateTarget;
804
805         // Need to be able to ghost the Component
806         if (!me.ghost) {
807             animateTarget = null;
808         }
809         // If we're animating, kick off an animation of the ghost down to the target
810         if (animateTarget) {
811             animateTarget = animateTarget.el ? animateTarget.el : Ext.get(animateTarget);
812             ghostPanel = me.ghost();
813             ghostPanel.el.stopAnimation();
814             toBox = animateTarget.getBox();
815             toBox.width += 'px';
816             toBox.height += 'px';
817             ghostPanel.el.animate({
818                 to: toBox,
819                 listeners: {
820                     afteranimate: function() {
821                         delete ghostPanel.componentLayout.lastComponentSize;
822                         ghostPanel.el.hide();
823                         me.afterHide(cb, scope);
824                     }
825                 }
826             });
827         }
828         me.el.hide();
829         if (!animateTarget) {
830             me.afterHide(cb, scope);
831         }
832     },
833
834     afterHide: function(cb, scope) {
835         Ext.callback(cb, scope || this);
836         this.fireEvent('hide', this);
837     },
838
839     /**
840      * @private
841      * Template method to contribute functionality at destroy time.
842      */
843     onDestroy: function() {
844         var me = this;
845
846         // Ensure that any ancillary components are destroyed.
847         if (me.rendered) {
848             Ext.destroy(
849                 me.proxy,
850                 me.resizer
851             );
852             // Different from AbstractComponent
853             if (me.actionMode == 'container' || me.removeMode == 'container') {
854                 me.container.remove();
855             }
856         }
857         delete me.focusTask;
858         me.callParent();
859     },
860
861     deleteMembers: function() {
862         var args = arguments,
863             len = args.length,
864             i = 0;
865         for (; i < len; ++i) {
866             delete this[args[i]];
867         }
868     },
869
870     /**
871      * Try to focus this component.
872      * @param {Boolean} selectText (optional) If applicable, true to also select the text in this component
873      * @param {Boolean/Number} delay (optional) Delay the focus this number of milliseconds (true for 10 milliseconds).
874      * @return {Ext.Component} this
875      */
876     focus: function(selectText, delay) {
877         var me = this,
878                 focusEl;
879
880         if (delay) {
881             if (!me.focusTask) {
882                 me.focusTask = Ext.create('Ext.util.DelayedTask', me.focus);
883             }
884             me.focusTask.delay(Ext.isNumber(delay) ? delay : 10, null, me, [selectText, false]);
885             return me;
886         }
887
888         if (me.rendered && !me.isDestroyed) {
889             // getFocusEl could return a Component.
890             focusEl = me.getFocusEl();
891             focusEl.focus();
892             if (focusEl.dom && selectText === true) {
893                 focusEl.dom.select();
894             }
895
896             // Focusing a floating Component brings it to the front of its stack.
897             // this is performed by its zIndexManager. Pass preventFocus true to avoid recursion.
898             if (me.floating) {
899                 me.toFront(true);
900             }
901         }
902         return me;
903     },
904
905     /**
906      * @private
907      * Returns the focus holder element associated with this Component. By default, this is the Component's encapsulating
908      * element. Subclasses which use embedded focusable elements (such as Window and Button) should override this for use
909      * by the {@link #focus} method.
910      * @returns {Ext.core.Element} the focus holing element.
911      */
912     getFocusEl: function() {
913         return this.el;
914     },
915
916     // private
917     blur: function() {
918         if (this.rendered) {
919             this.getFocusEl().blur();
920         }
921         return this;
922     },
923
924     getEl: function() {
925         return this.el;
926     },
927
928     // Deprecate 5.0
929     getResizeEl: function() {
930         return this.el;
931     },
932
933     // Deprecate 5.0
934     getPositionEl: function() {
935         return this.el;
936     },
937
938     // Deprecate 5.0
939     getActionEl: function() {
940         return this.el;
941     },
942
943     // Deprecate 5.0
944     getVisibilityEl: function() {
945         return this.el;
946     },
947
948     // Deprecate 5.0
949     onResize: Ext.emptyFn,
950
951     // private
952     getBubbleTarget: function() {
953         return this.ownerCt;
954     },
955
956     // private
957     getContentTarget: function() {
958         return this.el;
959     },
960
961     /**
962      * Clone the current component using the original config values passed into this instance by default.
963      * @param {Object} overrides A new config containing any properties to override in the cloned version.
964      * An id property can be passed on this object, otherwise one will be generated to avoid duplicates.
965      * @return {Ext.Component} clone The cloned copy of this component
966      */
967     cloneConfig: function(overrides) {
968         overrides = overrides || {};
969         var id = overrides.id || Ext.id();
970         var cfg = Ext.applyIf(overrides, this.initialConfig);
971         cfg.id = id;
972
973         var self = Ext.getClass(this);
974
975         // prevent dup id
976         return new self(cfg);
977     },
978
979     /**
980      * Gets the xtype for this component as registered with {@link Ext.ComponentManager}. For a list of all
981      * available xtypes, see the {@link Ext.Component} header. Example usage:
982      * <pre><code>
983 var t = new Ext.form.field.Text();
984 alert(t.getXType());  // alerts 'textfield'
985 </code></pre>
986      * @return {String} The xtype
987      */
988     getXType: function() {
989         return this.self.xtype;
990     },
991
992     /**
993      * Find a container above this component at any level by a custom function. If the passed function returns
994      * true, the container will be returned.
995      * @param {Function} fn The custom function to call with the arguments (container, this component).
996      * @return {Ext.container.Container} The first Container for which the custom function returns true
997      */
998     findParentBy: function(fn) {
999         var p;
1000
1001         // Iterate up the ownerCt chain until there's no ownerCt, or we find an ancestor which matches using the selector function.
1002         for (p = this.ownerCt; p && !fn(p, this); p = p.ownerCt);
1003         return p || null;
1004     },
1005
1006     /**
1007      * <p>Find a container above this component at any level by xtype or class</p>
1008      * <p>See also the {@link Ext.Component#up up} method.</p>
1009      * @param {String/Class} xtype The xtype string for a component, or the class of the component directly
1010      * @return {Ext.container.Container} The first Container which matches the given xtype or class
1011      */
1012     findParentByType: function(xtype) {
1013         return Ext.isFunction(xtype) ?
1014             this.findParentBy(function(p) {
1015                 return p.constructor === xtype;
1016             })
1017         :
1018             this.up(xtype);
1019     },
1020
1021     /**
1022      * Bubbles up the component/container heirarchy, calling the specified function with each component. The scope (<i>this</i>) of
1023      * function call will be the scope provided or the current component. The arguments to the function
1024      * will be the args provided or the current component. If the function returns false at any point,
1025      * the bubble is stopped.
1026      * @param {Function} fn The function to call
1027      * @param {Object} scope (optional) The scope of the function (defaults to current node)
1028      * @param {Array} args (optional) The args to call the function with (default to passing the current component)
1029      * @return {Ext.Component} this
1030      */
1031     bubble: function(fn, scope, args) {
1032         var p = this;
1033         while (p) {
1034             if (fn.apply(scope || p, args || [p]) === false) {
1035                 break;
1036             }
1037             p = p.ownerCt;
1038         }
1039         return this;
1040     },
1041
1042     getProxy: function() {
1043         if (!this.proxy) {
1044             this.proxy = this.el.createProxy(Ext.baseCSSPrefix + 'proxy-el', Ext.getBody(), true);
1045         }
1046         return this.proxy;
1047     }
1048
1049 });
1050