Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / AbstractComponent.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  * An abstract base class which provides shared methods for Components across the Sencha product line.
17  *
18  * Please refer to sub class's documentation
19  * @private
20  */
21 Ext.define('Ext.AbstractComponent', {
22
23     /* Begin Definitions */
24     requires: [
25         'Ext.ComponentQuery',
26         'Ext.ComponentManager'
27     ],
28
29     mixins: {
30         observable: 'Ext.util.Observable',
31         animate: 'Ext.util.Animate',
32         state: 'Ext.state.Stateful'
33     },
34
35     // The "uses" property specifies class which are used in an instantiated AbstractComponent.
36     // They do *not* have to be loaded before this class may be defined - that is what "requires" is for.
37     uses: [
38         'Ext.PluginManager',
39         'Ext.ComponentManager',
40         'Ext.Element',
41         'Ext.DomHelper',
42         'Ext.XTemplate',
43         'Ext.ComponentQuery',
44         'Ext.ComponentLoader',
45         'Ext.EventManager',
46         'Ext.layout.Layout',
47         'Ext.layout.component.Auto',
48         'Ext.LoadMask',
49         'Ext.ZIndexManager'
50     ],
51
52     statics: {
53         AUTO_ID: 1000
54     },
55
56     /* End Definitions */
57
58     isComponent: true,
59
60     getAutoId: function() {
61         return ++Ext.AbstractComponent.AUTO_ID;
62     },
63
64
65     /**
66      * @cfg {String} id
67      * The **unique id of this component instance.**
68      *
69      * It should not be necessary to use this configuration except for singleton objects in your application. Components
70      * created with an id may be accessed globally using {@link Ext#getCmp Ext.getCmp}.
71      *
72      * Instead of using assigned ids, use the {@link #itemId} config, and {@link Ext.ComponentQuery ComponentQuery}
73      * which provides selector-based searching for Sencha Components analogous to DOM querying. The {@link
74      * Ext.container.Container Container} class contains {@link Ext.container.Container#down shortcut methods} to query
75      * its descendant Components by selector.
76      *
77      * Note that this id will also be used as the element id for the containing HTML element that is rendered to the
78      * page for this component. This allows you to write id-based CSS rules to style the specific instance of this
79      * component uniquely, and also to select sub-elements using this component's id as the parent.
80      *
81      * **Note**: to avoid complications imposed by a unique id also see `{@link #itemId}`.
82      *
83      * **Note**: to access the container of a Component see `{@link #ownerCt}`.
84      *
85      * Defaults to an {@link #getId auto-assigned id}.
86      */
87
88     /**
89      * @cfg {String} itemId
90      * An itemId can be used as an alternative way to get a reference to a component when no object reference is
91      * available. Instead of using an `{@link #id}` with {@link Ext}.{@link Ext#getCmp getCmp}, use `itemId` with
92      * {@link Ext.container.Container}.{@link Ext.container.Container#getComponent getComponent} which will retrieve
93      * `itemId`'s or {@link #id}'s. Since `itemId`'s are an index to the container's internal MixedCollection, the
94      * `itemId` is scoped locally to the container -- avoiding potential conflicts with {@link Ext.ComponentManager}
95      * which requires a **unique** `{@link #id}`.
96      *
97      *     var c = new Ext.panel.Panel({ //
98      *         {@link Ext.Component#height height}: 300,
99      *         {@link #renderTo}: document.body,
100      *         {@link Ext.container.Container#layout layout}: 'auto',
101      *         {@link Ext.container.Container#items items}: [
102      *             {
103      *                 itemId: 'p1',
104      *                 {@link Ext.panel.Panel#title title}: 'Panel 1',
105      *                 {@link Ext.Component#height height}: 150
106      *             },
107      *             {
108      *                 itemId: 'p2',
109      *                 {@link Ext.panel.Panel#title title}: 'Panel 2',
110      *                 {@link Ext.Component#height height}: 150
111      *             }
112      *         ]
113      *     })
114      *     p1 = c.{@link Ext.container.Container#getComponent getComponent}('p1'); // not the same as {@link Ext#getCmp Ext.getCmp()}
115      *     p2 = p1.{@link #ownerCt}.{@link Ext.container.Container#getComponent getComponent}('p2'); // reference via a sibling
116      *
117      * Also see {@link #id}, `{@link Ext.container.Container#query}`, `{@link Ext.container.Container#down}` and
118      * `{@link Ext.container.Container#child}`.
119      *
120      * **Note**: to access the container of an item see {@link #ownerCt}.
121      */
122
123     /**
124      * @property {Ext.Container} ownerCt
125      * This Component's owner {@link Ext.container.Container Container} (is set automatically
126      * when this Component is added to a Container). Read-only.
127      *
128      * **Note**: to access items within the Container see {@link #itemId}.
129      */
130
131     /**
132      * @property {Boolean} layoutManagedWidth
133      * @private
134      * Flag set by the container layout to which this Component is added.
135      * If the layout manages this Component's width, it sets the value to 1.
136      * If it does NOT manage the width, it sets it to 2.
137      * If the layout MAY affect the width, but only if the owning Container has a fixed width, this is set to 0.
138      */
139
140     /**
141      * @property {Boolean} layoutManagedHeight
142      * @private
143      * Flag set by the container layout to which this Component is added.
144      * If the layout manages this Component's height, it sets the value to 1.
145      * If it does NOT manage the height, it sets it to 2.
146      * If the layout MAY affect the height, but only if the owning Container has a fixed height, this is set to 0.
147      */
148
149     /**
150      * @cfg {String/Object} autoEl
151      * A tag name or {@link Ext.DomHelper DomHelper} spec used to create the {@link #getEl Element} which will
152      * encapsulate this Component.
153      *
154      * You do not normally need to specify this. For the base classes {@link Ext.Component} and
155      * {@link Ext.container.Container}, this defaults to **'div'**. The more complex Sencha classes use a more
156      * complex DOM structure specified by their own {@link #renderTpl}s.
157      *
158      * This is intended to allow the developer to create application-specific utility Components encapsulated by
159      * different DOM elements. Example usage:
160      *
161      *     {
162      *         xtype: 'component',
163      *         autoEl: {
164      *             tag: 'img',
165      *             src: 'http://www.example.com/example.jpg'
166      *         }
167      *     }, {
168      *         xtype: 'component',
169      *         autoEl: {
170      *             tag: 'blockquote',
171      *             html: 'autoEl is cool!'
172      *         }
173      *     }, {
174      *         xtype: 'container',
175      *         autoEl: 'ul',
176      *         cls: 'ux-unordered-list',
177      *         items: {
178      *             xtype: 'component',
179      *             autoEl: 'li',
180      *             html: 'First list item'
181      *         }
182      *     }
183      */
184
185     /**
186      * @cfg {Ext.XTemplate/String/String[]} renderTpl
187      * An {@link Ext.XTemplate XTemplate} used to create the internal structure inside this Component's encapsulating
188      * {@link #getEl Element}.
189      *
190      * You do not normally need to specify this. For the base classes {@link Ext.Component} and
191      * {@link Ext.container.Container}, this defaults to **`null`** which means that they will be initially rendered
192      * with no internal structure; they render their {@link #getEl Element} empty. The more specialized ExtJS and Touch
193      * classes which use a more complex DOM structure, provide their own template definitions.
194      *
195      * This is intended to allow the developer to create application-specific utility Components with customized
196      * internal structure.
197      *
198      * Upon rendering, any created child elements may be automatically imported into object properties using the
199      * {@link #renderSelectors} and {@link #childEls} options.
200      */
201     renderTpl: null,
202
203     /**
204      * @cfg {Object} renderData
205      *
206      * The data used by {@link #renderTpl} in addition to the following property values of the component:
207      *
208      * - id
209      * - ui
210      * - uiCls
211      * - baseCls
212      * - componentCls
213      * - frame
214      *
215      * See {@link #renderSelectors} and {@link #childEls} for usage examples.
216      */
217
218     /**
219      * @cfg {Object} renderSelectors
220      * An object containing properties specifying {@link Ext.DomQuery DomQuery} selectors which identify child elements
221      * created by the render process.
222      *
223      * After the Component's internal structure is rendered according to the {@link #renderTpl}, this object is iterated through,
224      * and the found Elements are added as properties to the Component using the `renderSelector` property name.
225      *
226      * For example, a Component which renderes a title and description into its element:
227      *
228      *     Ext.create('Ext.Component', {
229      *         renderTo: Ext.getBody(),
230      *         renderTpl: [
231      *             '<h1 class="title">{title}</h1>',
232      *             '<p>{desc}</p>'
233      *         ],
234      *         renderData: {
235      *             title: "Error",
236      *             desc: "Something went wrong"
237      *         },
238      *         renderSelectors: {
239      *             titleEl: 'h1.title',
240      *             descEl: 'p'
241      *         },
242      *         listeners: {
243      *             afterrender: function(cmp){
244      *                 // After rendering the component will have a titleEl and descEl properties
245      *                 cmp.titleEl.setStyle({color: "red"});
246      *             }
247      *         }
248      *     });
249      *
250      * For a faster, but less flexible, alternative that achieves the same end result (properties for child elements on the
251      * Component after render), see {@link #childEls} and {@link #addChildEls}.
252      */
253
254     /**
255      * @cfg {Object[]} childEls
256      * An array describing the child elements of the Component. Each member of the array
257      * is an object with these properties:
258      *
259      * - `name` - The property name on the Component for the child element.
260      * - `itemId` - The id to combine with the Component's id that is the id of the child element.
261      * - `id` - The id of the child element.
262      *
263      * If the array member is a string, it is equivalent to `{ name: m, itemId: m }`.
264      *
265      * For example, a Component which renders a title and body text:
266      *
267      *     Ext.create('Ext.Component', {
268      *         renderTo: Ext.getBody(),
269      *         renderTpl: [
270      *             '<h1 id="{id}-title">{title}</h1>',
271      *             '<p>{msg}</p>',
272      *         ],
273      *         renderData: {
274      *             title: "Error",
275      *             msg: "Something went wrong"
276      *         },
277      *         childEls: ["title"],
278      *         listeners: {
279      *             afterrender: function(cmp){
280      *                 // After rendering the component will have a title property
281      *                 cmp.title.setStyle({color: "red"});
282      *             }
283      *         }
284      *     });
285      *
286      * A more flexible, but somewhat slower, approach is {@link #renderSelectors}.
287      */
288
289     /**
290      * @cfg {String/HTMLElement/Ext.Element} renderTo
291      * Specify the id of the element, a DOM element or an existing Element that this component will be rendered into.
292      *
293      * **Notes:**
294      *
295      * Do *not* use this option if the Component is to be a child item of a {@link Ext.container.Container Container}.
296      * It is the responsibility of the {@link Ext.container.Container Container}'s
297      * {@link Ext.container.Container#layout layout manager} to render and manage its child items.
298      *
299      * When using this config, a call to render() is not required.
300      *
301      * See `{@link #render}` also.
302      */
303
304     /**
305      * @cfg {Boolean} frame
306      * Specify as `true` to have the Component inject framing elements within the Component at render time to provide a
307      * graphical rounded frame around the Component content.
308      *
309      * This is only necessary when running on outdated, or non standard-compliant browsers such as Microsoft's Internet
310      * Explorer prior to version 9 which do not support rounded corners natively.
311      *
312      * The extra space taken up by this framing is available from the read only property {@link #frameSize}.
313      */
314
315     /**
316      * @property {Object} frameSize
317      * Read-only property indicating the width of any framing elements which were added within the encapsulating element
318      * to provide graphical, rounded borders. See the {@link #frame} config.
319      *
320      * This is an object containing the frame width in pixels for all four sides of the Component containing the
321      * following properties:
322      *
323      * @property {Number} frameSize.top The width of the top framing element in pixels.
324      * @property {Number} frameSize.right The width of the right framing element in pixels.
325      * @property {Number} frameSize.bottom The width of the bottom framing element in pixels.
326      * @property {Number} frameSize.left The width of the left framing element in pixels.
327      */
328
329     /**
330      * @cfg {String/Object} componentLayout
331      * The sizing and positioning of a Component's internal Elements is the responsibility of the Component's layout
332      * manager which sizes a Component's internal structure in response to the Component being sized.
333      *
334      * Generally, developers will not use this configuration as all provided Components which need their internal
335      * elements sizing (Such as {@link Ext.form.field.Base input fields}) come with their own componentLayout managers.
336      *
337      * The {@link Ext.layout.container.Auto default layout manager} will be used on instances of the base Ext.Component
338      * class which simply sizes the Component's encapsulating element to the height and width specified in the
339      * {@link #setSize} method.
340      */
341
342     /**
343      * @cfg {Ext.XTemplate/Ext.Template/String/String[]} tpl
344      * An {@link Ext.Template}, {@link Ext.XTemplate} or an array of strings to form an Ext.XTemplate. Used in
345      * conjunction with the `{@link #data}` and `{@link #tplWriteMode}` configurations.
346      */
347
348     /**
349      * @cfg {Object} data
350      * The initial set of data to apply to the `{@link #tpl}` to update the content area of the Component.
351      */
352
353     /**
354      * @cfg {String} xtype
355      * The `xtype` configuration option can be used to optimize Component creation and rendering. It serves as a
356      * shortcut to the full componet name. For example, the component `Ext.button.Button` has an xtype of `button`.
357      *
358      * You can define your own xtype on a custom {@link Ext.Component component} by specifying the
359      * {@link Ext.Class#alias alias} config option with a prefix of `widget`. For example:
360      *
361      *     Ext.define('PressMeButton', {
362      *         extend: 'Ext.button.Button',
363      *         alias: 'widget.pressmebutton',
364      *         text: 'Press Me'
365      *     })
366      *
367      * Any Component can be created implicitly as an object config with an xtype specified, allowing it to be
368      * declared and passed into the rendering pipeline without actually being instantiated as an object. Not only is
369      * rendering deferred, but the actual creation of the object itself is also deferred, saving memory and resources
370      * until they are actually needed. In complex, nested layouts containing many Components, this can make a
371      * noticeable improvement in performance.
372      *
373      *     // Explicit creation of contained Components:
374      *     var panel = new Ext.Panel({
375      *        ...
376      *        items: [
377      *           Ext.create('Ext.button.Button', {
378      *              text: 'OK'
379      *           })
380      *        ]
381      *     };
382      *
383      *     // Implicit creation using xtype:
384      *     var panel = new Ext.Panel({
385      *        ...
386      *        items: [{
387      *           xtype: 'button',
388      *           text: 'OK'
389      *        }]
390      *     };
391      *
392      * In the first example, the button will always be created immediately during the panel's initialization. With
393      * many added Components, this approach could potentially slow the rendering of the page. In the second example,
394      * the button will not be created or rendered until the panel is actually displayed in the browser. If the panel
395      * is never displayed (for example, if it is a tab that remains hidden) then the button will never be created and
396      * will never consume any resources whatsoever.
397      */
398
399     /**
400      * @cfg {String} tplWriteMode
401      * The Ext.(X)Template method to use when updating the content area of the Component.
402      * See `{@link Ext.XTemplate#overwrite}` for information on default mode.
403      */
404     tplWriteMode: 'overwrite',
405
406     /**
407      * @cfg {String} [baseCls='x-component']
408      * The base CSS class to apply to this components's element. This will also be prepended to elements within this
409      * component like Panel's body will get a class x-panel-body. This means that if you create a subclass of Panel, and
410      * you want it to get all the Panels styling for the element and the body, you leave the baseCls x-panel and use
411      * componentCls to add specific styling for this component.
412      */
413     baseCls: Ext.baseCSSPrefix + 'component',
414
415     /**
416      * @cfg {String} componentCls
417      * CSS Class to be added to a components root level element to give distinction to it via styling.
418      */
419
420     /**
421      * @cfg {String} [cls='']
422      * An optional extra CSS class that will be added to this component's Element. This can be useful
423      * for adding customized styles to the component or any of its children using standard CSS rules.
424      */
425
426     /**
427      * @cfg {String} [overCls='']
428      * An optional extra CSS class that will be added to this component's Element when the mouse moves over the Element,
429      * and removed when the mouse moves out. This can be useful for adding customized 'active' or 'hover' styles to the
430      * component or any of its children using standard CSS rules.
431      */
432
433     /**
434      * @cfg {String} [disabledCls='x-item-disabled']
435      * CSS class to add when the Component is disabled. Defaults to 'x-item-disabled'.
436      */
437     disabledCls: Ext.baseCSSPrefix + 'item-disabled',
438
439     /**
440      * @cfg {String/String[]} ui
441      * A set style for a component. Can be a string or an Array of multiple strings (UIs)
442      */
443     ui: 'default',
444
445     /**
446      * @cfg {String[]} uiCls
447      * An array of of classNames which are currently applied to this component
448      * @private
449      */
450     uiCls: [],
451
452     /**
453      * @cfg {String} style
454      * A custom style specification to be applied to this component's Element. Should be a valid argument to
455      * {@link Ext.Element#applyStyles}.
456      *
457      *     new Ext.panel.Panel({
458      *         title: 'Some Title',
459      *         renderTo: Ext.getBody(),
460      *         width: 400, height: 300,
461      *         layout: 'form',
462      *         items: [{
463      *             xtype: 'textarea',
464      *             style: {
465      *                 width: '95%',
466      *                 marginBottom: '10px'
467      *             }
468      *         },
469      *         new Ext.button.Button({
470      *             text: 'Send',
471      *             minWidth: '100',
472      *             style: {
473      *                 marginBottom: '10px'
474      *             }
475      *         })
476      *         ]
477      *     });
478      */
479
480     /**
481      * @cfg {Number} width
482      * The width of this component in pixels.
483      */
484
485     /**
486      * @cfg {Number} height
487      * The height of this component in pixels.
488      */
489
490     /**
491      * @cfg {Number/String} border
492      * Specifies the border for this component. The border can be a single numeric value to apply to all sides or it can
493      * be a CSS style specification for each style, for example: '10 5 3 10'.
494      */
495
496     /**
497      * @cfg {Number/String} padding
498      * Specifies the padding for this component. The padding can be a single numeric value to apply to all sides or it
499      * can be a CSS style specification for each style, for example: '10 5 3 10'.
500      */
501
502     /**
503      * @cfg {Number/String} margin
504      * Specifies the margin for this component. The margin can be a single numeric value to apply to all sides or it can
505      * be a CSS style specification for each style, for example: '10 5 3 10'.
506      */
507
508     /**
509      * @cfg {Boolean} hidden
510      * True to hide the component.
511      */
512     hidden: false,
513
514     /**
515      * @cfg {Boolean} disabled
516      * True to disable the component.
517      */
518     disabled: false,
519
520     /**
521      * @cfg {Boolean} [draggable=false]
522      * Allows the component to be dragged.
523      */
524
525     /**
526      * @property {Boolean} draggable
527      * Read-only property indicating whether or not the component can be dragged
528      */
529     draggable: false,
530
531     /**
532      * @cfg {Boolean} floating
533      * Create the Component as a floating and use absolute positioning.
534      *
535      * The z-index of floating Components is handled by a ZIndexManager. If you simply render a floating Component into the DOM, it will be managed
536      * by the global {@link Ext.WindowManager WindowManager}.
537      *
538      * If you include a floating Component as a child item of a Container, then upon render, ExtJS will seek an ancestor floating Component to house a new
539      * ZIndexManager instance to manage its descendant floaters. If no floating ancestor can be found, the global WindowManager will be used.
540      *
541      * When a floating Component which has a ZindexManager managing descendant floaters is destroyed, those descendant floaters will also be destroyed.
542      */
543     floating: false,
544
545     /**
546      * @cfg {String} hideMode
547      * A String which specifies how this Component's encapsulating DOM element will be hidden. Values may be:
548      *
549      *   - `'display'` : The Component will be hidden using the `display: none` style.
550      *   - `'visibility'` : The Component will be hidden using the `visibility: hidden` style.
551      *   - `'offsets'` : The Component will be hidden by absolutely positioning it out of the visible area of the document.
552      *     This is useful when a hidden Component must maintain measurable dimensions. Hiding using `display` results in a
553      *     Component having zero dimensions.
554      */
555     hideMode: 'display',
556
557     /**
558      * @cfg {String} contentEl
559      * Specify an existing HTML element, or the `id` of an existing HTML element to use as the content for this component.
560      *
561      * This config option is used to take an existing HTML element and place it in the layout element of a new component
562      * (it simply moves the specified DOM element _after the Component is rendered_ to use as the content.
563      *
564      * **Notes:**
565      *
566      * The specified HTML element is appended to the layout element of the component _after any configured
567      * {@link #html HTML} has been inserted_, and so the document will not contain this element at the time
568      * the {@link #render} event is fired.
569      *
570      * The specified HTML element used will not participate in any **`{@link Ext.container.Container#layout layout}`**
571      * scheme that the Component may use. It is just HTML. Layouts operate on child
572      * **`{@link Ext.container.Container#items items}`**.
573      *
574      * Add either the `x-hidden` or the `x-hide-display` CSS class to prevent a brief flicker of the content before it
575      * is rendered to the panel.
576      */
577
578     /**
579      * @cfg {String/Object} [html='']
580      * An HTML fragment, or a {@link Ext.DomHelper DomHelper} specification to use as the layout element content.
581      * The HTML content is added after the component is rendered, so the document will not contain this HTML at the time
582      * the {@link #render} event is fired. This content is inserted into the body _before_ any configured {@link #contentEl}
583      * is appended.
584      */
585
586     /**
587      * @cfg {Boolean} styleHtmlContent
588      * True to automatically style the html inside the content target of this component (body for panels).
589      */
590     styleHtmlContent: false,
591
592     /**
593      * @cfg {String} [styleHtmlCls='x-html']
594      * The class that is added to the content target when you set styleHtmlContent to true.
595      */
596     styleHtmlCls: Ext.baseCSSPrefix + 'html',
597
598     /**
599      * @cfg {Number} minHeight
600      * The minimum value in pixels which this Component will set its height to.
601      *
602      * **Warning:** This will override any size management applied by layout managers.
603      */
604     /**
605      * @cfg {Number} minWidth
606      * The minimum value in pixels which this Component will set its width to.
607      *
608      * **Warning:** This will override any size management applied by layout managers.
609      */
610     /**
611      * @cfg {Number} maxHeight
612      * The maximum value in pixels which this Component will set its height to.
613      *
614      * **Warning:** This will override any size management applied by layout managers.
615      */
616     /**
617      * @cfg {Number} maxWidth
618      * The maximum value in pixels which this Component will set its width to.
619      *
620      * **Warning:** This will override any size management applied by layout managers.
621      */
622
623     /**
624      * @cfg {Ext.ComponentLoader/Object} loader
625      * A configuration object or an instance of a {@link Ext.ComponentLoader} to load remote content for this Component.
626      */
627
628     /**
629      * @cfg {Boolean} autoShow
630      * True to automatically show the component upon creation. This config option may only be used for
631      * {@link #floating} components or components that use {@link #autoRender}. Defaults to false.
632      */
633     autoShow: false,
634
635     /**
636      * @cfg {Boolean/String/HTMLElement/Ext.Element} autoRender
637      * This config is intended mainly for non-{@link #floating} Components which may or may not be shown. Instead of using
638      * {@link #renderTo} in the configuration, and rendering upon construction, this allows a Component to render itself
639      * upon first _{@link #show}_. If {@link #floating} is true, the value of this config is omited as if it is `true`.
640      *
641      * Specify as `true` to have this Component render to the document body upon first show.
642      *
643      * Specify as an element, or the ID of an element to have this Component render to a specific element upon first
644      * show.
645      *
646      * **This defaults to `true` for the {@link Ext.window.Window Window} class.**
647      */
648     autoRender: false,
649
650     needsLayout: false,
651
652     // @private
653     allowDomMove: true,
654
655     /**
656      * @cfg {Object/Object[]} plugins
657      * An object or array of objects that will provide custom functionality for this component. The only requirement for
658      * a valid plugin is that it contain an init method that accepts a reference of type Ext.Component. When a component
659      * is created, if any plugins are available, the component will call the init method on each plugin, passing a
660      * reference to itself. Each plugin can then call methods or respond to events on the component as needed to provide
661      * its functionality.
662      */
663
664     /**
665      * @property {Boolean} rendered
666      * Read-only property indicating whether or not the component has been rendered.
667      */
668     rendered: false,
669
670     /**
671      * @property {Number} componentLayoutCounter
672      * @private
673      * The number of component layout calls made on this object.
674      */
675     componentLayoutCounter: 0,
676
677     weight: 0,
678
679     trimRe: /^\s+|\s+$/g,
680     spacesRe: /\s+/,
681
682
683     /**
684      * @property {Boolean} maskOnDisable
685      * This is an internal flag that you use when creating custom components. By default this is set to true which means
686      * that every component gets a mask when its disabled. Components like FieldContainer, FieldSet, Field, Button, Tab
687      * override this property to false since they want to implement custom disable logic.
688      */
689     maskOnDisable: true,
690
691     /**
692      * Creates new Component.
693      * @param {Object} config  (optional) Config object.
694      */
695     constructor : function(config) {
696         var me = this,
697             i, len;
698
699         config = config || {};
700         me.initialConfig = config;
701         Ext.apply(me, config);
702
703         me.addEvents(
704             /**
705              * @event beforeactivate
706              * Fires before a Component has been visually activated. Returning false from an event listener can prevent
707              * the activate from occurring.
708              * @param {Ext.Component} this
709              */
710             'beforeactivate',
711             /**
712              * @event activate
713              * Fires after a Component has been visually activated.
714              * @param {Ext.Component} this
715              */
716             'activate',
717             /**
718              * @event beforedeactivate
719              * Fires before a Component has been visually deactivated. Returning false from an event listener can
720              * prevent the deactivate from occurring.
721              * @param {Ext.Component} this
722              */
723             'beforedeactivate',
724             /**
725              * @event deactivate
726              * Fires after a Component has been visually deactivated.
727              * @param {Ext.Component} this
728              */
729             'deactivate',
730             /**
731              * @event added
732              * Fires after a Component had been added to a Container.
733              * @param {Ext.Component} this
734              * @param {Ext.container.Container} container Parent Container
735              * @param {Number} pos position of Component
736              */
737             'added',
738             /**
739              * @event disable
740              * Fires after the component is disabled.
741              * @param {Ext.Component} this
742              */
743             'disable',
744             /**
745              * @event enable
746              * Fires after the component is enabled.
747              * @param {Ext.Component} this
748              */
749             'enable',
750             /**
751              * @event beforeshow
752              * Fires before the component is shown when calling the {@link #show} method. Return false from an event
753              * handler to stop the show.
754              * @param {Ext.Component} this
755              */
756             'beforeshow',
757             /**
758              * @event show
759              * Fires after the component is shown when calling the {@link #show} method.
760              * @param {Ext.Component} this
761              */
762             'show',
763             /**
764              * @event beforehide
765              * Fires before the component is hidden when calling the {@link #hide} method. Return false from an event
766              * handler to stop the hide.
767              * @param {Ext.Component} this
768              */
769             'beforehide',
770             /**
771              * @event hide
772              * Fires after the component is hidden. Fires after the component is hidden when calling the {@link #hide}
773              * method.
774              * @param {Ext.Component} this
775              */
776             'hide',
777             /**
778              * @event removed
779              * Fires when a component is removed from an Ext.container.Container
780              * @param {Ext.Component} this
781              * @param {Ext.container.Container} ownerCt Container which holds the component
782              */
783             'removed',
784             /**
785              * @event beforerender
786              * Fires before the component is {@link #rendered}. Return false from an event handler to stop the
787              * {@link #render}.
788              * @param {Ext.Component} this
789              */
790             'beforerender',
791             /**
792              * @event render
793              * Fires after the component markup is {@link #rendered}.
794              * @param {Ext.Component} this
795              */
796             'render',
797             /**
798              * @event afterrender
799              * Fires after the component rendering is finished.
800              *
801              * The afterrender event is fired after this Component has been {@link #rendered}, been postprocesed by any
802              * afterRender method defined for the Component.
803              * @param {Ext.Component} this
804              */
805             'afterrender',
806             /**
807              * @event beforedestroy
808              * Fires before the component is {@link #destroy}ed. Return false from an event handler to stop the
809              * {@link #destroy}.
810              * @param {Ext.Component} this
811              */
812             'beforedestroy',
813             /**
814              * @event destroy
815              * Fires after the component is {@link #destroy}ed.
816              * @param {Ext.Component} this
817              */
818             'destroy',
819             /**
820              * @event resize
821              * Fires after the component is resized.
822              * @param {Ext.Component} this
823              * @param {Number} adjWidth The box-adjusted width that was set
824              * @param {Number} adjHeight The box-adjusted height that was set
825              */
826             'resize',
827             /**
828              * @event move
829              * Fires after the component is moved.
830              * @param {Ext.Component} this
831              * @param {Number} x The new x position
832              * @param {Number} y The new y position
833              */
834             'move'
835         );
836
837         me.getId();
838
839         me.mons = [];
840         me.additionalCls = [];
841         me.renderData = me.renderData || {};
842         me.renderSelectors = me.renderSelectors || {};
843
844         if (me.plugins) {
845             me.plugins = [].concat(me.plugins);
846             me.constructPlugins();
847         }
848
849         me.initComponent();
850
851         // ititComponent gets a chance to change the id property before registering
852         Ext.ComponentManager.register(me);
853
854         // Dont pass the config so that it is not applied to 'this' again
855         me.mixins.observable.constructor.call(me);
856         me.mixins.state.constructor.call(me, config);
857
858         // Save state on resize.
859         this.addStateEvents('resize');
860
861         // Move this into Observable?
862         if (me.plugins) {
863             me.plugins = [].concat(me.plugins);
864             for (i = 0, len = me.plugins.length; i < len; i++) {
865                 me.plugins[i] = me.initPlugin(me.plugins[i]);
866             }
867         }
868
869         me.loader = me.getLoader();
870
871         if (me.renderTo) {
872             me.render(me.renderTo);
873             // EXTJSIV-1935 - should be a way to do afterShow or something, but that
874             // won't work. Likewise, rendering hidden and then showing (w/autoShow) has
875             // implications to afterRender so we cannot do that.
876         }
877
878         if (me.autoShow) {
879             me.show();
880         }
881
882         //<debug>
883         if (Ext.isDefined(me.disabledClass)) {
884             if (Ext.isDefined(Ext.global.console)) {
885                 Ext.global.console.warn('Ext.Component: disabledClass has been deprecated. Please use disabledCls.');
886             }
887             me.disabledCls = me.disabledClass;
888             delete me.disabledClass;
889         }
890         //</debug>
891     },
892
893     initComponent: function () {
894         // This is called again here to allow derived classes to add plugin configs to the
895         // plugins array before calling down to this, the base initComponent.
896         this.constructPlugins();
897     },
898
899     /**
900      * The supplied default state gathering method for the AbstractComponent class.
901      *
902      * This method returns dimension settings such as `flex`, `anchor`, `width` and `height` along with `collapsed`
903      * state.
904      *
905      * Subclasses which implement more complex state should call the superclass's implementation, and apply their state
906      * to the result if this basic state is to be saved.
907      *
908      * Note that Component state will only be saved if the Component has a {@link #stateId} and there as a StateProvider
909      * configured for the document.
910      *
911      * @return {Object}
912      */
913     getState: function() {
914         var me = this,
915             layout = me.ownerCt ? (me.shadowOwnerCt || me.ownerCt).getLayout() : null,
916             state = {
917                 collapsed: me.collapsed
918             },
919             width = me.width,
920             height = me.height,
921             cm = me.collapseMemento,
922             anchors;
923
924         // If a Panel-local collapse has taken place, use remembered values as the dimensions.
925         // TODO: remove this coupling with Panel's privates! All collapse/expand logic should be refactored into one place.
926         if (me.collapsed && cm) {
927             if (Ext.isDefined(cm.data.width)) {
928                 width = cm.width;
929             }
930             if (Ext.isDefined(cm.data.height)) {
931                 height = cm.height;
932             }
933         }
934
935         // If we have flex, only store the perpendicular dimension.
936         if (layout && me.flex) {
937             state.flex = me.flex;
938             if (layout.perpendicularPrefix) {
939                 state[layout.perpendicularPrefix] = me['get' + layout.perpendicularPrefixCap]();
940             } else {
941                 //<debug>
942                 if (Ext.isDefined(Ext.global.console)) {
943                     Ext.global.console.warn('Ext.Component: Specified a flex value on a component not inside a Box layout');
944                 }
945                 //</debug>
946             }
947         }
948         // If we have anchor, only store dimensions which are *not* being anchored
949         else if (layout && me.anchor) {
950             state.anchor = me.anchor;
951             anchors = me.anchor.split(' ').concat(null);
952             if (!anchors[0]) {
953                 if (me.width) {
954                     state.width = width;
955                 }
956             }
957             if (!anchors[1]) {
958                 if (me.height) {
959                     state.height = height;
960                 }
961             }
962         }
963         // Store dimensions.
964         else {
965             if (me.width) {
966                 state.width = width;
967             }
968             if (me.height) {
969                 state.height = height;
970             }
971         }
972
973         // Don't save dimensions if they are unchanged from the original configuration.
974         if (state.width == me.initialConfig.width) {
975             delete state.width;
976         }
977         if (state.height == me.initialConfig.height) {
978             delete state.height;
979         }
980
981         // If a Box layout was managing the perpendicular dimension, don't save that dimension
982         if (layout && layout.align && (layout.align.indexOf('stretch') !== -1)) {
983             delete state[layout.perpendicularPrefix];
984         }
985         return state;
986     },
987
988     show: Ext.emptyFn,
989
990     animate: function(animObj) {
991         var me = this,
992             to;
993
994         animObj = animObj || {};
995         to = animObj.to || {};
996
997         if (Ext.fx.Manager.hasFxBlock(me.id)) {
998             return me;
999         }
1000         // Special processing for animating Component dimensions.
1001         if (!animObj.dynamic && (to.height || to.width)) {
1002             var curWidth = me.getWidth(),
1003                 w = curWidth,
1004                 curHeight = me.getHeight(),
1005                 h = curHeight,
1006                 needsResize = false;
1007
1008             if (to.height && to.height > curHeight) {
1009                 h = to.height;
1010                 needsResize = true;
1011             }
1012             if (to.width && to.width > curWidth) {
1013                 w = to.width;
1014                 needsResize = true;
1015             }
1016
1017             // If any dimensions are being increased, we must resize the internal structure
1018             // of the Component, but then clip it by sizing its encapsulating element back to original dimensions.
1019             // The animation will then progressively reveal the larger content.
1020             if (needsResize) {
1021                 var clearWidth = !Ext.isNumber(me.width),
1022                     clearHeight = !Ext.isNumber(me.height);
1023
1024                 me.componentLayout.childrenChanged = true;
1025                 me.setSize(w, h, me.ownerCt);
1026                 me.el.setSize(curWidth, curHeight);
1027                 if (clearWidth) {
1028                     delete me.width;
1029                 }
1030                 if (clearHeight) {
1031                     delete me.height;
1032                 }
1033             }
1034         }
1035         return me.mixins.animate.animate.apply(me, arguments);
1036     },
1037
1038     /**
1039      * This method finds the topmost active layout who's processing will eventually determine the size and position of
1040      * this Component.
1041      *
1042      * This method is useful when dynamically adding Components into Containers, and some processing must take place
1043      * after the final sizing and positioning of the Component has been performed.
1044      *
1045      * @return {Ext.Component}
1046      */
1047     findLayoutController: function() {
1048         return this.findParentBy(function(c) {
1049             // Return true if we are at the root of the Container tree
1050             // or this Container's layout is busy but the next one up is not.
1051             return !c.ownerCt || (c.layout.layoutBusy && !c.ownerCt.layout.layoutBusy);
1052         });
1053     },
1054
1055     onShow : function() {
1056         // Layout if needed
1057         var needsLayout = this.needsLayout;
1058         if (Ext.isObject(needsLayout)) {
1059             this.doComponentLayout(needsLayout.width, needsLayout.height, needsLayout.isSetSize, needsLayout.ownerCt);
1060         }
1061     },
1062
1063     constructPlugin: function(plugin) {
1064         if (plugin.ptype && typeof plugin.init != 'function') {
1065             plugin.cmp = this;
1066             plugin = Ext.PluginManager.create(plugin);
1067         }
1068         else if (typeof plugin == 'string') {
1069             plugin = Ext.PluginManager.create({
1070                 ptype: plugin,
1071                 cmp: this
1072             });
1073         }
1074         return plugin;
1075     },
1076
1077     /**
1078      * Ensures that the plugins array contains fully constructed plugin instances. This converts any configs into their
1079      * appropriate instances.
1080      */
1081     constructPlugins: function() {
1082         var me = this,
1083             plugins = me.plugins,
1084             i, len;
1085
1086         if (plugins) {
1087             for (i = 0, len = plugins.length; i < len; i++) {
1088                 // this just returns already-constructed plugin instances...
1089                 plugins[i] = me.constructPlugin(plugins[i]);
1090             }
1091         }
1092     },
1093
1094     // @private
1095     initPlugin : function(plugin) {
1096         plugin.init(this);
1097
1098         return plugin;
1099     },
1100
1101     /**
1102      * Handles autoRender. Floating Components may have an ownerCt. If they are asking to be constrained, constrain them
1103      * within that ownerCt, and have their z-index managed locally. Floating Components are always rendered to
1104      * document.body
1105      */
1106     doAutoRender: function() {
1107         var me = this;
1108         if (me.floating) {
1109             me.render(document.body);
1110         } else {
1111             me.render(Ext.isBoolean(me.autoRender) ? Ext.getBody() : me.autoRender);
1112         }
1113     },
1114
1115     // @private
1116     render : function(container, position) {
1117         var me = this;
1118
1119         if (!me.rendered && me.fireEvent('beforerender', me) !== false) {
1120
1121             // Flag set during the render process.
1122             // It can be used to inhibit event-driven layout calls during the render phase
1123             me.rendering = true;
1124
1125             // If this.el is defined, we want to make sure we are dealing with
1126             // an Ext Element.
1127             if (me.el) {
1128                 me.el = Ext.get(me.el);
1129             }
1130
1131             // Perform render-time processing for floating Components
1132             if (me.floating) {
1133                 me.onFloatRender();
1134             }
1135
1136             container = me.initContainer(container);
1137
1138             me.onRender(container, position);
1139
1140             // Tell the encapsulating element to hide itself in the way the Component is configured to hide
1141             // This means DISPLAY, VISIBILITY or OFFSETS.
1142             me.el.setVisibilityMode(Ext.Element[me.hideMode.toUpperCase()]);
1143
1144             if (me.overCls) {
1145                 me.el.hover(me.addOverCls, me.removeOverCls, me);
1146             }
1147
1148             me.fireEvent('render', me);
1149
1150             me.initContent();
1151
1152             me.afterRender(container);
1153             me.fireEvent('afterrender', me);
1154
1155             me.initEvents();
1156
1157             if (me.hidden) {
1158                 // Hiding during the render process should not perform any ancillary
1159                 // actions that the full hide process does; It is not hiding, it begins in a hidden state.'
1160                 // So just make the element hidden according to the configured hideMode
1161                 me.el.hide();
1162             }
1163
1164             if (me.disabled) {
1165                 // pass silent so the event doesn't fire the first time.
1166                 me.disable(true);
1167             }
1168
1169             // Delete the flag once the rendering is done.
1170             delete me.rendering;
1171         }
1172         return me;
1173     },
1174
1175     // @private
1176     onRender : function(container, position) {
1177         var me = this,
1178             el = me.el,
1179             styles = me.initStyles(),
1180             renderTpl, renderData, i;
1181
1182         position = me.getInsertPosition(position);
1183
1184         if (!el) {
1185             if (position) {
1186                 el = Ext.DomHelper.insertBefore(position, me.getElConfig(), true);
1187             }
1188             else {
1189                 el = Ext.DomHelper.append(container, me.getElConfig(), true);
1190             }
1191         }
1192         else if (me.allowDomMove !== false) {
1193             if (position) {
1194                 container.dom.insertBefore(el.dom, position);
1195             } else {
1196                 container.dom.appendChild(el.dom);
1197             }
1198         }
1199
1200         if (Ext.scopeResetCSS && !me.ownerCt) {
1201             // If this component's el is the body element, we add the reset class to the html tag
1202             if (el.dom == Ext.getBody().dom) {
1203                 el.parent().addCls(Ext.baseCSSPrefix + 'reset');
1204             }
1205             else {
1206                 // Else we wrap this element in an element that adds the reset class.
1207                 me.resetEl = el.wrap({
1208                     cls: Ext.baseCSSPrefix + 'reset'
1209                 });
1210             }
1211         }
1212
1213         me.setUI(me.ui);
1214
1215         el.addCls(me.initCls());
1216         el.setStyle(styles);
1217
1218         // Here we check if the component has a height set through style or css.
1219         // If it does then we set the this.height to that value and it won't be
1220         // considered an auto height component
1221         // if (this.height === undefined) {
1222         //     var height = el.getHeight();
1223         //     // This hopefully means that the panel has an explicit height set in style or css
1224         //     if (height - el.getPadding('tb') - el.getBorderWidth('tb') > 0) {
1225         //         this.height = height;
1226         //     }
1227         // }
1228
1229         me.el = el;
1230
1231         me.initFrame();
1232
1233         renderTpl = me.initRenderTpl();
1234         if (renderTpl) {
1235             renderData = me.initRenderData();
1236             renderTpl.append(me.getTargetEl(), renderData);
1237         }
1238
1239         me.applyRenderSelectors();
1240
1241         me.rendered = true;
1242     },
1243
1244     // @private
1245     afterRender : function() {
1246         var me = this,
1247             pos,
1248             xy;
1249
1250         me.getComponentLayout();
1251
1252         // Set the size if a size is configured, or if this is the outermost Container.
1253         // Also, if this is a collapsed Panel, it needs an initial component layout
1254         // to lay out its header so that it can have a height determined.
1255         if (me.collapsed || (!me.ownerCt || (me.height || me.width))) {
1256             me.setSize(me.width, me.height);
1257         } else {
1258             // It is expected that child items be rendered before this method returns and
1259             // the afterrender event fires. Since we aren't going to do the layout now, we
1260             // must render the child items. This is handled implicitly above in the layout
1261             // caused by setSize.
1262             me.renderChildren();
1263         }
1264
1265         // For floaters, calculate x and y if they aren't defined by aligning
1266         // the sized element to the center of either the container or the ownerCt
1267         if (me.floating && (me.x === undefined || me.y === undefined)) {
1268             if (me.floatParent) {
1269                 xy = me.el.getAlignToXY(me.floatParent.getTargetEl(), 'c-c');
1270                 pos = me.floatParent.getTargetEl().translatePoints(xy[0], xy[1]);
1271             } else {
1272                 xy = me.el.getAlignToXY(me.container, 'c-c');
1273                 pos = me.container.translatePoints(xy[0], xy[1]);
1274             }
1275             me.x = me.x === undefined ? pos.left: me.x;
1276             me.y = me.y === undefined ? pos.top: me.y;
1277         }
1278
1279         if (Ext.isDefined(me.x) || Ext.isDefined(me.y)) {
1280             me.setPosition(me.x, me.y);
1281         }
1282
1283         if (me.styleHtmlContent) {
1284             me.getTargetEl().addCls(me.styleHtmlCls);
1285         }
1286     },
1287
1288     /**
1289      * @private
1290      * Called by Component#doAutoRender
1291      *
1292      * Register a Container configured `floating: true` with this Component's {@link Ext.ZIndexManager ZIndexManager}.
1293      *
1294      * Components added in ths way will not participate in any layout, but will be rendered
1295      * upon first show in the way that {@link Ext.window.Window Window}s are.
1296      */
1297     registerFloatingItem: function(cmp) {
1298         var me = this;
1299         if (!me.floatingItems) {
1300             me.floatingItems = Ext.create('Ext.ZIndexManager', me);
1301         }
1302         me.floatingItems.register(cmp);
1303     },
1304
1305     renderChildren: function () {
1306         var me = this,
1307             layout = me.getComponentLayout();
1308
1309         me.suspendLayout = true;
1310         layout.renderChildren();
1311         delete me.suspendLayout;
1312     },
1313
1314     frameCls: Ext.baseCSSPrefix + 'frame',
1315
1316     frameIdRegex: /[-]frame\d+[TMB][LCR]$/,
1317
1318     frameElementCls: {
1319         tl: [],
1320         tc: [],
1321         tr: [],
1322         ml: [],
1323         mc: [],
1324         mr: [],
1325         bl: [],
1326         bc: [],
1327         br: []
1328     },
1329
1330     frameTpl: [
1331         '<tpl if="top">',
1332             '<tpl if="left"><div id="{fgid}TL" class="{frameCls}-tl {baseCls}-tl {baseCls}-{ui}-tl<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tl</tpl></tpl>" style="background-position: {tl}; padding-left: {frameWidth}px" role="presentation"></tpl>',
1333                 '<tpl if="right"><div id="{fgid}TR" class="{frameCls}-tr {baseCls}-tr {baseCls}-{ui}-tr<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tr</tpl></tpl>" style="background-position: {tr}; padding-right: {frameWidth}px" role="presentation"></tpl>',
1334                     '<div id="{fgid}TC" class="{frameCls}-tc {baseCls}-tc {baseCls}-{ui}-tc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tc</tpl></tpl>" style="background-position: {tc}; height: {frameWidth}px" role="presentation"></div>',
1335                 '<tpl if="right"></div></tpl>',
1336             '<tpl if="left"></div></tpl>',
1337         '</tpl>',
1338         '<tpl if="left"><div id="{fgid}ML" class="{frameCls}-ml {baseCls}-ml {baseCls}-{ui}-ml<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-ml</tpl></tpl>" style="background-position: {ml}; padding-left: {frameWidth}px" role="presentation"></tpl>',
1339             '<tpl if="right"><div id="{fgid}MR" class="{frameCls}-mr {baseCls}-mr {baseCls}-{ui}-mr<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mr</tpl></tpl>" style="background-position: {mr}; padding-right: {frameWidth}px" role="presentation"></tpl>',
1340                 '<div id="{fgid}MC" class="{frameCls}-mc {baseCls}-mc {baseCls}-{ui}-mc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mc</tpl></tpl>" role="presentation"></div>',
1341             '<tpl if="right"></div></tpl>',
1342         '<tpl if="left"></div></tpl>',
1343         '<tpl if="bottom">',
1344             '<tpl if="left"><div id="{fgid}BL" class="{frameCls}-bl {baseCls}-bl {baseCls}-{ui}-bl<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bl</tpl></tpl>" style="background-position: {bl}; padding-left: {frameWidth}px" role="presentation"></tpl>',
1345                 '<tpl if="right"><div id="{fgid}BR" class="{frameCls}-br {baseCls}-br {baseCls}-{ui}-br<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-br</tpl></tpl>" style="background-position: {br}; padding-right: {frameWidth}px" role="presentation"></tpl>',
1346                     '<div id="{fgid}BC" class="{frameCls}-bc {baseCls}-bc {baseCls}-{ui}-bc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bc</tpl></tpl>" style="background-position: {bc}; height: {frameWidth}px" role="presentation"></div>',
1347                 '<tpl if="right"></div></tpl>',
1348             '<tpl if="left"></div></tpl>',
1349         '</tpl>'
1350     ],
1351
1352     frameTableTpl: [
1353         '<table><tbody>',
1354             '<tpl if="top">',
1355                 '<tr>',
1356                     '<tpl if="left"><td id="{fgid}TL" class="{frameCls}-tl {baseCls}-tl {baseCls}-{ui}-tl<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tl</tpl></tpl>" style="background-position: {tl}; padding-left:{frameWidth}px" role="presentation"></td></tpl>',
1357                     '<td id="{fgid}TC" class="{frameCls}-tc {baseCls}-tc {baseCls}-{ui}-tc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tc</tpl></tpl>" style="background-position: {tc}; height: {frameWidth}px" role="presentation"></td>',
1358                     '<tpl if="right"><td id="{fgid}TR" class="{frameCls}-tr {baseCls}-tr {baseCls}-{ui}-tr<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tr</tpl></tpl>" style="background-position: {tr}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
1359                 '</tr>',
1360             '</tpl>',
1361             '<tr>',
1362                 '<tpl if="left"><td id="{fgid}ML" class="{frameCls}-ml {baseCls}-ml {baseCls}-{ui}-ml<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-ml</tpl></tpl>" style="background-position: {ml}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
1363                 '<td id="{fgid}MC" class="{frameCls}-mc {baseCls}-mc {baseCls}-{ui}-mc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mc</tpl></tpl>" style="background-position: 0 0;" role="presentation"></td>',
1364                 '<tpl if="right"><td id="{fgid}MR" class="{frameCls}-mr {baseCls}-mr {baseCls}-{ui}-mr<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mr</tpl></tpl>" style="background-position: {mr}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
1365             '</tr>',
1366             '<tpl if="bottom">',
1367                 '<tr>',
1368                     '<tpl if="left"><td id="{fgid}BL" class="{frameCls}-bl {baseCls}-bl {baseCls}-{ui}-bl<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bl</tpl></tpl>" style="background-position: {bl}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
1369                     '<td id="{fgid}BC" class="{frameCls}-bc {baseCls}-bc {baseCls}-{ui}-bc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bc</tpl></tpl>" style="background-position: {bc}; height: {frameWidth}px" role="presentation"></td>',
1370                     '<tpl if="right"><td id="{fgid}BR" class="{frameCls}-br {baseCls}-br {baseCls}-{ui}-br<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-br</tpl></tpl>" style="background-position: {br}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
1371                 '</tr>',
1372             '</tpl>',
1373         '</tbody></table>'
1374     ],
1375
1376     /**
1377      * @private
1378      */
1379     initFrame : function() {
1380         if (Ext.supports.CSS3BorderRadius) {
1381             return false;
1382         }
1383
1384         var me = this,
1385             frameInfo = me.getFrameInfo(),
1386             frameWidth = frameInfo.width,
1387             frameTpl = me.getFrameTpl(frameInfo.table),
1388             frameGenId;
1389
1390         if (me.frame) {
1391             // since we render id's into the markup and id's NEED to be unique, we have a
1392             // simple strategy for numbering their generations.
1393             me.frameGenId = frameGenId = (me.frameGenId || 0) + 1;
1394             frameGenId = me.id + '-frame' + frameGenId;
1395
1396             // Here we render the frameTpl to this component. This inserts the 9point div or the table framing.
1397             frameTpl.insertFirst(me.el, Ext.apply({}, {
1398                 fgid:       frameGenId,
1399                 ui:         me.ui,
1400                 uiCls:      me.uiCls,
1401                 frameCls:   me.frameCls,
1402                 baseCls:    me.baseCls,
1403                 frameWidth: frameWidth,
1404                 top:        !!frameInfo.top,
1405                 left:       !!frameInfo.left,
1406                 right:      !!frameInfo.right,
1407                 bottom:     !!frameInfo.bottom
1408             }, me.getFramePositions(frameInfo)));
1409
1410             // The frameBody is returned in getTargetEl, so that layouts render items to the correct target.=
1411             me.frameBody = me.el.down('.' + me.frameCls + '-mc');
1412
1413             // Clean out the childEls for the old frame elements (the majority of the els)
1414             me.removeChildEls(function (c) {
1415                 return c.id && me.frameIdRegex.test(c.id);
1416             });
1417
1418             // Add the childEls for each of the new frame elements
1419             Ext.each(['TL','TC','TR','ML','MC','MR','BL','BC','BR'], function (suffix) {
1420                 me.childEls.push({ name: 'frame' + suffix, id: frameGenId + suffix });
1421             });
1422         }
1423     },
1424
1425     updateFrame: function() {
1426         if (Ext.supports.CSS3BorderRadius) {
1427             return false;
1428         }
1429
1430         var me = this,
1431             wasTable = this.frameSize && this.frameSize.table,
1432             oldFrameTL = this.frameTL,
1433             oldFrameBL = this.frameBL,
1434             oldFrameML = this.frameML,
1435             oldFrameMC = this.frameMC,
1436             newMCClassName;
1437
1438         this.initFrame();
1439
1440         if (oldFrameMC) {
1441             if (me.frame) {
1442                 // Reapply render selectors
1443                 delete me.frameTL;
1444                 delete me.frameTC;
1445                 delete me.frameTR;
1446                 delete me.frameML;
1447                 delete me.frameMC;
1448                 delete me.frameMR;
1449                 delete me.frameBL;
1450                 delete me.frameBC;
1451                 delete me.frameBR;
1452                 this.applyRenderSelectors();
1453
1454                 // Store the class names set on the new mc
1455                 newMCClassName = this.frameMC.dom.className;
1456
1457                 // Replace the new mc with the old mc
1458                 oldFrameMC.insertAfter(this.frameMC);
1459                 this.frameMC.remove();
1460
1461                 // Restore the reference to the old frame mc as the framebody
1462                 this.frameBody = this.frameMC = oldFrameMC;
1463
1464                 // Apply the new mc classes to the old mc element
1465                 oldFrameMC.dom.className = newMCClassName;
1466
1467                 // Remove the old framing
1468                 if (wasTable) {
1469                     me.el.query('> table')[1].remove();
1470                 }
1471                 else {
1472                     if (oldFrameTL) {
1473                         oldFrameTL.remove();
1474                     }
1475                     if (oldFrameBL) {
1476                         oldFrameBL.remove();
1477                     }
1478                     oldFrameML.remove();
1479                 }
1480             }
1481             else {
1482                 // We were framed but not anymore. Move all content from the old frame to the body
1483
1484             }
1485         }
1486         else if (me.frame) {
1487             this.applyRenderSelectors();
1488         }
1489     },
1490
1491     getFrameInfo: function() {
1492         if (Ext.supports.CSS3BorderRadius) {
1493             return false;
1494         }
1495
1496         var me = this,
1497             left = me.el.getStyle('background-position-x'),
1498             top = me.el.getStyle('background-position-y'),
1499             info, frameInfo = false, max;
1500
1501         // Some browsers dont support background-position-x and y, so for those
1502         // browsers let's split background-position into two parts.
1503         if (!left && !top) {
1504             info = me.el.getStyle('background-position').split(' ');
1505             left = info[0];
1506             top = info[1];
1507         }
1508
1509         // We actually pass a string in the form of '[type][tl][tr]px [type][br][bl]px' as
1510         // the background position of this.el from the css to indicate to IE that this component needs
1511         // framing. We parse it here and change the markup accordingly.
1512         if (parseInt(left, 10) >= 1000000 && parseInt(top, 10) >= 1000000) {
1513             max = Math.max;
1514
1515             frameInfo = {
1516                 // Table markup starts with 110, div markup with 100.
1517                 table: left.substr(0, 3) == '110',
1518
1519                 // Determine if we are dealing with a horizontal or vertical component
1520                 vertical: top.substr(0, 3) == '110',
1521
1522                 // Get and parse the different border radius sizes
1523                 top:    max(left.substr(3, 2), left.substr(5, 2)),
1524                 right:  max(left.substr(5, 2), top.substr(3, 2)),
1525                 bottom: max(top.substr(3, 2), top.substr(5, 2)),
1526                 left:   max(top.substr(5, 2), left.substr(3, 2))
1527             };
1528
1529             frameInfo.width = max(frameInfo.top, frameInfo.right, frameInfo.bottom, frameInfo.left);
1530
1531             // Just to be sure we set the background image of the el to none.
1532             me.el.setStyle('background-image', 'none');
1533         }
1534
1535         // This happens when you set frame: true explicitly without using the x-frame mixin in sass.
1536         // This way IE can't figure out what sizes to use and thus framing can't work.
1537         if (me.frame === true && !frameInfo) {
1538             //<debug error>
1539             Ext.Error.raise("You have set frame: true explicity on this component while it doesn't have any " +
1540                             "framing defined in the CSS template. In this case IE can't figure out what sizes " +
1541                             "to use and thus framing on this component will be disabled.");
1542             //</debug>
1543         }
1544
1545         me.frame = me.frame || !!frameInfo;
1546         me.frameSize = frameInfo || false;
1547
1548         return frameInfo;
1549     },
1550
1551     getFramePositions: function(frameInfo) {
1552         var me = this,
1553             frameWidth = frameInfo.width,
1554             dock = me.dock,
1555             positions, tc, bc, ml, mr;
1556
1557         if (frameInfo.vertical) {
1558             tc = '0 -' + (frameWidth * 0) + 'px';
1559             bc = '0 -' + (frameWidth * 1) + 'px';
1560
1561             if (dock && dock == "right") {
1562                 tc = 'right -' + (frameWidth * 0) + 'px';
1563                 bc = 'right -' + (frameWidth * 1) + 'px';
1564             }
1565
1566             positions = {
1567                 tl: '0 -' + (frameWidth * 0) + 'px',
1568                 tr: '0 -' + (frameWidth * 1) + 'px',
1569                 bl: '0 -' + (frameWidth * 2) + 'px',
1570                 br: '0 -' + (frameWidth * 3) + 'px',
1571
1572                 ml: '-' + (frameWidth * 1) + 'px 0',
1573                 mr: 'right 0',
1574
1575                 tc: tc,
1576                 bc: bc
1577             };
1578         } else {
1579             ml = '-' + (frameWidth * 0) + 'px 0';
1580             mr = 'right 0';
1581
1582             if (dock && dock == "bottom") {
1583                 ml = 'left bottom';
1584                 mr = 'right bottom';
1585             }
1586
1587             positions = {
1588                 tl: '0 -' + (frameWidth * 2) + 'px',
1589                 tr: 'right -' + (frameWidth * 3) + 'px',
1590                 bl: '0 -' + (frameWidth * 4) + 'px',
1591                 br: 'right -' + (frameWidth * 5) + 'px',
1592
1593                 ml: ml,
1594                 mr: mr,
1595
1596                 tc: '0 -' + (frameWidth * 0) + 'px',
1597                 bc: '0 -' + (frameWidth * 1) + 'px'
1598             };
1599         }
1600
1601         return positions;
1602     },
1603
1604     /**
1605      * @private
1606      */
1607     getFrameTpl : function(table) {
1608         return table ? this.getTpl('frameTableTpl') : this.getTpl('frameTpl');
1609     },
1610
1611     /**
1612      * Creates an array of class names from the configurations to add to this Component's `el` on render.
1613      *
1614      * Private, but (possibly) used by ComponentQuery for selection by class name if Component is not rendered.
1615      *
1616      * @return {String[]} An array of class names with which the Component's element will be rendered.
1617      * @private
1618      */
1619     initCls: function() {
1620         var me = this,
1621             cls = [];
1622
1623         cls.push(me.baseCls);
1624
1625         //<deprecated since=0.99>
1626         if (Ext.isDefined(me.cmpCls)) {
1627             if (Ext.isDefined(Ext.global.console)) {
1628                 Ext.global.console.warn('Ext.Component: cmpCls has been deprecated. Please use componentCls.');
1629             }
1630             me.componentCls = me.cmpCls;
1631             delete me.cmpCls;
1632         }
1633         //</deprecated>
1634
1635         if (me.componentCls) {
1636             cls.push(me.componentCls);
1637         } else {
1638             me.componentCls = me.baseCls;
1639         }
1640         if (me.cls) {
1641             cls.push(me.cls);
1642             delete me.cls;
1643         }
1644
1645         return cls.concat(me.additionalCls);
1646     },
1647
1648     /**
1649      * Sets the UI for the component. This will remove any existing UIs on the component. It will also loop through any
1650      * uiCls set on the component and rename them so they include the new UI
1651      * @param {String} ui The new UI for the component
1652      */
1653     setUI: function(ui) {
1654         var me = this,
1655             oldUICls = Ext.Array.clone(me.uiCls),
1656             newUICls = [],
1657             classes = [],
1658             cls,
1659             i;
1660
1661         //loop through all exisiting uiCls and update the ui in them
1662         for (i = 0; i < oldUICls.length; i++) {
1663             cls = oldUICls[i];
1664
1665             classes = classes.concat(me.removeClsWithUI(cls, true));
1666             newUICls.push(cls);
1667         }
1668
1669         if (classes.length) {
1670             me.removeCls(classes);
1671         }
1672
1673         //remove the UI from the element
1674         me.removeUIFromElement();
1675
1676         //set the UI
1677         me.ui = ui;
1678
1679         //add the new UI to the elemend
1680         me.addUIToElement();
1681
1682         //loop through all exisiting uiCls and update the ui in them
1683         classes = [];
1684         for (i = 0; i < newUICls.length; i++) {
1685             cls = newUICls[i];
1686             classes = classes.concat(me.addClsWithUI(cls, true));
1687         }
1688
1689         if (classes.length) {
1690             me.addCls(classes);
1691         }
1692     },
1693
1694     /**
1695      * Adds a cls to the uiCls array, which will also call {@link #addUIClsToElement} and adds to all elements of this
1696      * component.
1697      * @param {String/String[]} cls A string or an array of strings to add to the uiCls
1698      * @param {Object} skip (Boolean) skip True to skip adding it to the class and do it later (via the return)
1699      */
1700     addClsWithUI: function(cls, skip) {
1701         var me = this,
1702             classes = [],
1703             i;
1704
1705         if (!Ext.isArray(cls)) {
1706             cls = [cls];
1707         }
1708
1709         for (i = 0; i < cls.length; i++) {
1710             if (cls[i] && !me.hasUICls(cls[i])) {
1711                 me.uiCls = Ext.Array.clone(me.uiCls);
1712                 me.uiCls.push(cls[i]);
1713
1714                 classes = classes.concat(me.addUIClsToElement(cls[i]));
1715             }
1716         }
1717
1718         if (skip !== true) {
1719             me.addCls(classes);
1720         }
1721
1722         return classes;
1723     },
1724
1725     /**
1726      * Removes a cls to the uiCls array, which will also call {@link #removeUIClsFromElement} and removes it from all
1727      * elements of this component.
1728      * @param {String/String[]} cls A string or an array of strings to remove to the uiCls
1729      */
1730     removeClsWithUI: function(cls, skip) {
1731         var me = this,
1732             classes = [],
1733             i;
1734
1735         if (!Ext.isArray(cls)) {
1736             cls = [cls];
1737         }
1738
1739         for (i = 0; i < cls.length; i++) {
1740             if (cls[i] && me.hasUICls(cls[i])) {
1741                 me.uiCls = Ext.Array.remove(me.uiCls, cls[i]);
1742
1743                 classes = classes.concat(me.removeUIClsFromElement(cls[i]));
1744             }
1745         }
1746
1747         if (skip !== true) {
1748             me.removeCls(classes);
1749         }
1750
1751         return classes;
1752     },
1753
1754     /**
1755      * Checks if there is currently a specified uiCls
1756      * @param {String} cls The cls to check
1757      */
1758     hasUICls: function(cls) {
1759         var me = this,
1760             uiCls = me.uiCls || [];
1761
1762         return Ext.Array.contains(uiCls, cls);
1763     },
1764
1765     /**
1766      * Method which adds a specified UI + uiCls to the components element. Can be overridden to remove the UI from more
1767      * than just the components element.
1768      * @param {String} ui The UI to remove from the element
1769      */
1770     addUIClsToElement: function(cls, force) {
1771         var me = this,
1772             result = [],
1773             frameElementCls = me.frameElementCls;
1774
1775         result.push(Ext.baseCSSPrefix + cls);
1776         result.push(me.baseCls + '-' + cls);
1777         result.push(me.baseCls + '-' + me.ui + '-' + cls);
1778
1779         if (!force && me.frame && !Ext.supports.CSS3BorderRadius) {
1780             // define each element of the frame
1781             var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
1782                 classes, i, j, el;
1783
1784             // loop through each of them, and if they are defined add the ui
1785             for (i = 0; i < els.length; i++) {
1786                 el = me['frame' + els[i].toUpperCase()];
1787                 classes = [me.baseCls + '-' + me.ui + '-' + els[i], me.baseCls + '-' + me.ui + '-' + cls + '-' + els[i]];
1788                 if (el && el.dom) {
1789                     el.addCls(classes);
1790                 } else {
1791                     for (j = 0; j < classes.length; j++) {
1792                         if (Ext.Array.indexOf(frameElementCls[els[i]], classes[j]) == -1) {
1793                             frameElementCls[els[i]].push(classes[j]);
1794                         }
1795                     }
1796                 }
1797             }
1798         }
1799
1800         me.frameElementCls = frameElementCls;
1801
1802         return result;
1803     },
1804
1805     /**
1806      * Method which removes a specified UI + uiCls from the components element. The cls which is added to the element
1807      * will be: `this.baseCls + '-' + ui`
1808      * @param {String} ui The UI to add to the element
1809      */
1810     removeUIClsFromElement: function(cls, force) {
1811         var me = this,
1812             result = [],
1813             frameElementCls = me.frameElementCls;
1814
1815         result.push(Ext.baseCSSPrefix + cls);
1816         result.push(me.baseCls + '-' + cls);
1817         result.push(me.baseCls + '-' + me.ui + '-' + cls);
1818
1819         if (!force && me.frame && !Ext.supports.CSS3BorderRadius) {
1820             // define each element of the frame
1821             var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
1822                 i, el;
1823             cls = me.baseCls + '-' + me.ui + '-' + cls + '-' + els[i];
1824             // loop through each of them, and if they are defined add the ui
1825             for (i = 0; i < els.length; i++) {
1826                 el = me['frame' + els[i].toUpperCase()];
1827                 if (el && el.dom) {
1828                     el.removeCls(cls);
1829                 } else {
1830                     Ext.Array.remove(frameElementCls[els[i]], cls);
1831                 }
1832             }
1833         }
1834
1835         me.frameElementCls = frameElementCls;
1836
1837         return result;
1838     },
1839
1840     /**
1841      * Method which adds a specified UI to the components element.
1842      * @private
1843      */
1844     addUIToElement: function(force) {
1845         var me = this,
1846             frameElementCls = me.frameElementCls;
1847
1848         me.addCls(me.baseCls + '-' + me.ui);
1849
1850         if (me.frame && !Ext.supports.CSS3BorderRadius) {
1851             // define each element of the frame
1852             var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
1853                 i, el, cls;
1854
1855             // loop through each of them, and if they are defined add the ui
1856             for (i = 0; i < els.length; i++) {
1857                 el = me['frame' + els[i].toUpperCase()];
1858                 cls = me.baseCls + '-' + me.ui + '-' + els[i];
1859                 if (el) {
1860                     el.addCls(cls);
1861                 } else {
1862                     if (!Ext.Array.contains(frameElementCls[els[i]], cls)) {
1863                         frameElementCls[els[i]].push(cls);
1864                     }
1865                 }
1866             }
1867         }
1868     },
1869
1870     /**
1871      * Method which removes a specified UI from the components element.
1872      * @private
1873      */
1874     removeUIFromElement: function() {
1875         var me = this,
1876             frameElementCls = me.frameElementCls;
1877
1878         me.removeCls(me.baseCls + '-' + me.ui);
1879
1880         if (me.frame && !Ext.supports.CSS3BorderRadius) {
1881             // define each element of the frame
1882             var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
1883                 i, j, el, cls;
1884
1885             // loop through each of them, and if they are defined add the ui
1886             for (i = 0; i < els.length; i++) {
1887                 el = me['frame' + els[i].toUpperCase()];
1888                 cls = me.baseCls + '-' + me.ui + '-' + els[i];
1889
1890                 if (el) {
1891                     el.removeCls(cls);
1892                 } else {
1893                     Ext.Array.remove(frameElementCls[els[i]], cls);
1894                 }
1895             }
1896         }
1897     },
1898
1899     getElConfig : function() {
1900         if (Ext.isString(this.autoEl)) {
1901             this.autoEl = {
1902                 tag: this.autoEl
1903             };
1904         }
1905
1906         var result = this.autoEl || {tag: 'div'};
1907         result.id = this.id;
1908         return result;
1909     },
1910
1911     /**
1912      * This function takes the position argument passed to onRender and returns a DOM element that you can use in the
1913      * insertBefore.
1914      * @param {String/Number/Ext.Element/HTMLElement} position Index, element id or element you want to put this
1915      * component before.
1916      * @return {HTMLElement} DOM element that you can use in the insertBefore
1917      */
1918     getInsertPosition: function(position) {
1919         // Convert the position to an element to insert before
1920         if (position !== undefined) {
1921             if (Ext.isNumber(position)) {
1922                 position = this.container.dom.childNodes[position];
1923             }
1924             else {
1925                 position = Ext.getDom(position);
1926             }
1927         }
1928
1929         return position;
1930     },
1931
1932     /**
1933      * Adds ctCls to container.
1934      * @return {Ext.Element} The initialized container
1935      * @private
1936      */
1937     initContainer: function(container) {
1938         var me = this;
1939
1940         // If you render a component specifying the el, we get the container
1941         // of the el, and make sure we dont move the el around in the dom
1942         // during the render
1943         if (!container && me.el) {
1944             container = me.el.dom.parentNode;
1945             me.allowDomMove = false;
1946         }
1947
1948         me.container = Ext.get(container);
1949
1950         if (me.ctCls) {
1951             me.container.addCls(me.ctCls);
1952         }
1953
1954         return me.container;
1955     },
1956
1957     /**
1958      * Initialized the renderData to be used when rendering the renderTpl.
1959      * @return {Object} Object with keys and values that are going to be applied to the renderTpl
1960      * @private
1961      */
1962     initRenderData: function() {
1963         var me = this;
1964
1965         return Ext.applyIf(me.renderData, {
1966             id: me.id,
1967             ui: me.ui,
1968             uiCls: me.uiCls,
1969             baseCls: me.baseCls,
1970             componentCls: me.componentCls,
1971             frame: me.frame
1972         });
1973     },
1974
1975     /**
1976      * @private
1977      */
1978     getTpl: function(name) {
1979         var me = this,
1980             prototype = me.self.prototype,
1981             ownerPrototype,
1982             tpl;
1983
1984         if (me.hasOwnProperty(name)) {
1985             tpl = me[name];
1986             if (tpl && !(tpl instanceof Ext.XTemplate)) {
1987                 me[name] = Ext.ClassManager.dynInstantiate('Ext.XTemplate', tpl);
1988             }
1989
1990             return me[name];
1991         }
1992
1993         if (!(prototype[name] instanceof Ext.XTemplate)) {
1994             ownerPrototype = prototype;
1995
1996             do {
1997                 if (ownerPrototype.hasOwnProperty(name)) {
1998                     tpl = ownerPrototype[name];
1999                     if (tpl && !(tpl instanceof Ext.XTemplate)) {
2000                         ownerPrototype[name] = Ext.ClassManager.dynInstantiate('Ext.XTemplate', tpl);
2001                         break;
2002                     }
2003                 }
2004
2005                 ownerPrototype = ownerPrototype.superclass;
2006             } while (ownerPrototype);
2007         }
2008
2009         return prototype[name];
2010     },
2011
2012     /**
2013      * Initializes the renderTpl.
2014      * @return {Ext.XTemplate} The renderTpl XTemplate instance.
2015      * @private
2016      */
2017     initRenderTpl: function() {
2018         return this.getTpl('renderTpl');
2019     },
2020
2021     /**
2022      * Converts style definitions to String.
2023      * @return {String} A CSS style string with style, padding, margin and border.
2024      * @private
2025      */
2026     initStyles: function() {
2027         var style = {},
2028             me = this,
2029             Element = Ext.Element;
2030
2031         if (Ext.isString(me.style)) {
2032             style = Element.parseStyles(me.style);
2033         } else {
2034             style = Ext.apply({}, me.style);
2035         }
2036
2037         // Convert the padding, margin and border properties from a space seperated string
2038         // into a proper style string
2039         if (me.padding !== undefined) {
2040             style.padding = Element.unitizeBox((me.padding === true) ? 5 : me.padding);
2041         }
2042
2043         if (me.margin !== undefined) {
2044             style.margin = Element.unitizeBox((me.margin === true) ? 5 : me.margin);
2045         }
2046
2047         delete me.style;
2048         return style;
2049     },
2050
2051     /**
2052      * Initializes this components contents. It checks for the properties html, contentEl and tpl/data.
2053      * @private
2054      */
2055     initContent: function() {
2056         var me = this,
2057             target = me.getTargetEl(),
2058             contentEl,
2059             pre;
2060
2061         if (me.html) {
2062             target.update(Ext.DomHelper.markup(me.html));
2063             delete me.html;
2064         }
2065
2066         if (me.contentEl) {
2067             contentEl = Ext.get(me.contentEl);
2068             pre = Ext.baseCSSPrefix;
2069             contentEl.removeCls([pre + 'hidden', pre + 'hide-display', pre + 'hide-offsets', pre + 'hide-nosize']);
2070             target.appendChild(contentEl.dom);
2071         }
2072
2073         if (me.tpl) {
2074             // Make sure this.tpl is an instantiated XTemplate
2075             if (!me.tpl.isTemplate) {
2076                 me.tpl = Ext.create('Ext.XTemplate', me.tpl);
2077             }
2078
2079             if (me.data) {
2080                 me.tpl[me.tplWriteMode](target, me.data);
2081                 delete me.data;
2082             }
2083         }
2084     },
2085
2086     // @private
2087     initEvents : function() {
2088         var me = this,
2089             afterRenderEvents = me.afterRenderEvents,
2090             el,
2091             property,
2092             fn = function(listeners){
2093                 me.mon(el, listeners);
2094             };
2095         if (afterRenderEvents) {
2096             for (property in afterRenderEvents) {
2097                 if (afterRenderEvents.hasOwnProperty(property)) {
2098                     el = me[property];
2099                     if (el && el.on) {
2100                         Ext.each(afterRenderEvents[property], fn);
2101                     }
2102                 }
2103             }
2104         }
2105     },
2106
2107     /**
2108      * Adds each argument passed to this method to the {@link #childEls} array.
2109      */
2110     addChildEls: function () {
2111         var me = this,
2112             childEls = me.childEls || (me.childEls = []);
2113
2114         childEls.push.apply(childEls, arguments);
2115     },
2116
2117     /**
2118      * Removes items in the childEls array based on the return value of a supplied test function. The function is called
2119      * with a entry in childEls and if the test function return true, that entry is removed. If false, that entry is
2120      * kept.
2121      * @param {Function} testFn The test function.
2122      */
2123     removeChildEls: function (testFn) {
2124         var me = this,
2125             old = me.childEls,
2126             keepers = (me.childEls = []),
2127             n, i, cel;
2128
2129         for (i = 0, n = old.length; i < n; ++i) {
2130             cel = old[i];
2131             if (!testFn(cel)) {
2132                 keepers.push(cel);
2133             }
2134         }
2135     },
2136
2137     /**
2138      * Sets references to elements inside the component. This applies {@link #renderSelectors}
2139      * as well as {@link #childEls}.
2140      * @private
2141      */
2142     applyRenderSelectors: function() {
2143         var me = this,
2144             childEls = me.childEls,
2145             selectors = me.renderSelectors,
2146             el = me.el,
2147             dom = el.dom,
2148             baseId, childName, childId, i, selector;
2149
2150         if (childEls) {
2151             baseId = me.id + '-';
2152             for (i = childEls.length; i--; ) {
2153                 childName = childId = childEls[i];
2154                 if (typeof(childName) != 'string') {
2155                     childId = childName.id || (baseId + childName.itemId);
2156                     childName = childName.name;
2157                 } else {
2158                     childId = baseId + childId;
2159                 }
2160
2161                 // We don't use Ext.get because that is 3x (or more) slower on IE6-8. Since
2162                 // we know the el's are children of our el we use getById instead:
2163                 me[childName] = el.getById(childId);
2164             }
2165         }
2166
2167         // We still support renderSelectors. There are a few places in the framework that
2168         // need them and they are a documented part of the API. In fact, we support mixing
2169         // childEls and renderSelectors (no reason not to).
2170         if (selectors) {
2171             for (selector in selectors) {
2172                 if (selectors.hasOwnProperty(selector) && selectors[selector]) {
2173                     me[selector] = Ext.get(Ext.DomQuery.selectNode(selectors[selector], dom));
2174                 }
2175             }
2176         }
2177     },
2178
2179     /**
2180      * Tests whether this Component matches the selector string.
2181      * @param {String} selector The selector string to test against.
2182      * @return {Boolean} True if this Component matches the selector.
2183      */
2184     is: function(selector) {
2185         return Ext.ComponentQuery.is(this, selector);
2186     },
2187
2188     /**
2189      * Walks up the `ownerCt` axis looking for an ancestor Container which matches the passed simple selector.
2190      *
2191      * Example:
2192      *
2193      *     var owningTabPanel = grid.up('tabpanel');
2194      *
2195      * @param {String} [selector] The simple selector to test.
2196      * @return {Ext.container.Container} The matching ancestor Container (or `undefined` if no match was found).
2197      */
2198     up: function(selector) {
2199         var result = this.ownerCt;
2200         if (selector) {
2201             for (; result; result = result.ownerCt) {
2202                 if (Ext.ComponentQuery.is(result, selector)) {
2203                     return result;
2204                 }
2205             }
2206         }
2207         return result;
2208     },
2209
2210     /**
2211      * Returns the next sibling of this Component.
2212      *
2213      * Optionally selects the next sibling which matches the passed {@link Ext.ComponentQuery ComponentQuery} selector.
2214      *
2215      * May also be refered to as **`next()`**
2216      *
2217      * Note that this is limited to siblings, and if no siblings of the item match, `null` is returned. Contrast with
2218      * {@link #nextNode}
2219      * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the following items.
2220      * @return {Ext.Component} The next sibling (or the next sibling which matches the selector).
2221      * Returns null if there is no matching sibling.
2222      */
2223     nextSibling: function(selector) {
2224         var o = this.ownerCt, it, last, idx, c;
2225         if (o) {
2226             it = o.items;
2227             idx = it.indexOf(this) + 1;
2228             if (idx) {
2229                 if (selector) {
2230                     for (last = it.getCount(); idx < last; idx++) {
2231                         if ((c = it.getAt(idx)).is(selector)) {
2232                             return c;
2233                         }
2234                     }
2235                 } else {
2236                     if (idx < it.getCount()) {
2237                         return it.getAt(idx);
2238                     }
2239                 }
2240             }
2241         }
2242         return null;
2243     },
2244
2245     /**
2246      * Returns the previous sibling of this Component.
2247      *
2248      * Optionally selects the previous sibling which matches the passed {@link Ext.ComponentQuery ComponentQuery}
2249      * selector.
2250      *
2251      * May also be refered to as **`prev()`**
2252      *
2253      * Note that this is limited to siblings, and if no siblings of the item match, `null` is returned. Contrast with
2254      * {@link #previousNode}
2255      * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the preceding items.
2256      * @return {Ext.Component} The previous sibling (or the previous sibling which matches the selector).
2257      * Returns null if there is no matching sibling.
2258      */
2259     previousSibling: function(selector) {
2260         var o = this.ownerCt, it, idx, c;
2261         if (o) {
2262             it = o.items;
2263             idx = it.indexOf(this);
2264             if (idx != -1) {
2265                 if (selector) {
2266                     for (--idx; idx >= 0; idx--) {
2267                         if ((c = it.getAt(idx)).is(selector)) {
2268                             return c;
2269                         }
2270                     }
2271                 } else {
2272                     if (idx) {
2273                         return it.getAt(--idx);
2274                     }
2275                 }
2276             }
2277         }
2278         return null;
2279     },
2280
2281     /**
2282      * Returns the previous node in the Component tree in tree traversal order.
2283      *
2284      * Note that this is not limited to siblings, and if invoked upon a node with no matching siblings, will walk the
2285      * tree in reverse order to attempt to find a match. Contrast with {@link #previousSibling}.
2286      * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the preceding nodes.
2287      * @return {Ext.Component} The previous node (or the previous node which matches the selector).
2288      * Returns null if there is no matching node.
2289      */
2290     previousNode: function(selector, includeSelf) {
2291         var node = this,
2292             result,
2293             it, len, i;
2294
2295         // If asked to include self, test me
2296         if (includeSelf && node.is(selector)) {
2297             return node;
2298         }
2299
2300         result = this.prev(selector);
2301         if (result) {
2302             return result;
2303         }
2304
2305         if (node.ownerCt) {
2306             for (it = node.ownerCt.items.items, i = Ext.Array.indexOf(it, node) - 1; i > -1; i--) {
2307                 if (it[i].query) {
2308                     result = it[i].query(selector);
2309                     result = result[result.length - 1];
2310                     if (result) {
2311                         return result;
2312                     }
2313                 }
2314             }
2315             return node.ownerCt.previousNode(selector, true);
2316         }
2317     },
2318
2319     /**
2320      * Returns the next node in the Component tree in tree traversal order.
2321      *
2322      * Note that this is not limited to siblings, and if invoked upon a node with no matching siblings, will walk the
2323      * tree to attempt to find a match. Contrast with {@link #nextSibling}.
2324      * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the following nodes.
2325      * @return {Ext.Component} The next node (or the next node which matches the selector).
2326      * Returns null if there is no matching node.
2327      */
2328     nextNode: function(selector, includeSelf) {
2329         var node = this,
2330             result,
2331             it, len, i;
2332
2333         // If asked to include self, test me
2334         if (includeSelf && node.is(selector)) {
2335             return node;
2336         }
2337
2338         result = this.next(selector);
2339         if (result) {
2340             return result;
2341         }
2342
2343         if (node.ownerCt) {
2344             for (it = node.ownerCt.items, i = it.indexOf(node) + 1, it = it.items, len = it.length; i < len; i++) {
2345                 if (it[i].down) {
2346                     result = it[i].down(selector);
2347                     if (result) {
2348                         return result;
2349                     }
2350                 }
2351             }
2352             return node.ownerCt.nextNode(selector);
2353         }
2354     },
2355
2356     /**
2357      * Retrieves the id of this component. Will autogenerate an id if one has not already been set.
2358      * @return {String}
2359      */
2360     getId : function() {
2361         return this.id || (this.id = 'ext-comp-' + (this.getAutoId()));
2362     },
2363
2364     getItemId : function() {
2365         return this.itemId || this.id;
2366     },
2367
2368     /**
2369      * Retrieves the top level element representing this component.
2370      * @return {Ext.core.Element}
2371      */
2372     getEl : function() {
2373         return this.el;
2374     },
2375
2376     /**
2377      * This is used to determine where to insert the 'html', 'contentEl' and 'items' in this component.
2378      * @private
2379      */
2380     getTargetEl: function() {
2381         return this.frameBody || this.el;
2382     },
2383
2384     /**
2385      * Tests whether or not this Component is of a specific xtype. This can test whether this Component is descended
2386      * from the xtype (default) or whether it is directly of the xtype specified (shallow = true).
2387      *
2388      * **If using your own subclasses, be aware that a Component must register its own xtype to participate in
2389      * determination of inherited xtypes.**
2390      *
2391      * For a list of all available xtypes, see the {@link Ext.Component} header.
2392      *
2393      * Example usage:
2394      *
2395      *     var t = new Ext.form.field.Text();
2396      *     var isText = t.isXType('textfield');        // true
2397      *     var isBoxSubclass = t.isXType('field');       // true, descended from Ext.form.field.Base
2398      *     var isBoxInstance = t.isXType('field', true); // false, not a direct Ext.form.field.Base instance
2399      *
2400      * @param {String} xtype The xtype to check for this Component
2401      * @param {Boolean} [shallow=false] True to check whether this Component is directly of the specified xtype, false to
2402      * check whether this Component is descended from the xtype.
2403      * @return {Boolean} True if this component descends from the specified xtype, false otherwise.
2404      */
2405     isXType: function(xtype, shallow) {
2406         //assume a string by default
2407         if (Ext.isFunction(xtype)) {
2408             xtype = xtype.xtype;
2409             //handle being passed the class, e.g. Ext.Component
2410         } else if (Ext.isObject(xtype)) {
2411             xtype = xtype.statics().xtype;
2412             //handle being passed an instance
2413         }
2414
2415         return !shallow ? ('/' + this.getXTypes() + '/').indexOf('/' + xtype + '/') != -1: this.self.xtype == xtype;
2416     },
2417
2418     /**
2419      * Returns this Component's xtype hierarchy as a slash-delimited string. For a list of all available xtypes, see the
2420      * {@link Ext.Component} header.
2421      *
2422      * **If using your own subclasses, be aware that a Component must register its own xtype to participate in
2423      * determination of inherited xtypes.**
2424      *
2425      * Example usage:
2426      *
2427      *     var t = new Ext.form.field.Text();
2428      *     alert(t.getXTypes());  // alerts 'component/field/textfield'
2429      *
2430      * @return {String} The xtype hierarchy string
2431      */
2432     getXTypes: function() {
2433         var self = this.self,
2434             xtypes, parentPrototype, parentXtypes;
2435
2436         if (!self.xtypes) {
2437             xtypes = [];
2438             parentPrototype = this;
2439
2440             while (parentPrototype) {
2441                 parentXtypes = parentPrototype.xtypes;
2442
2443                 if (parentXtypes !== undefined) {
2444                     xtypes.unshift.apply(xtypes, parentXtypes);
2445                 }
2446
2447                 parentPrototype = parentPrototype.superclass;
2448             }
2449
2450             self.xtypeChain = xtypes;
2451             self.xtypes = xtypes.join('/');
2452         }
2453
2454         return self.xtypes;
2455     },
2456
2457     /**
2458      * Update the content area of a component.
2459      * @param {String/Object} htmlOrData If this component has been configured with a template via the tpl config then
2460      * it will use this argument as data to populate the template. If this component was not configured with a template,
2461      * the components content area will be updated via Ext.Element update
2462      * @param {Boolean} [loadScripts=false] Only legitimate when using the html configuration.
2463      * @param {Function} [callback] Only legitimate when using the html configuration. Callback to execute when
2464      * scripts have finished loading
2465      */
2466     update : function(htmlOrData, loadScripts, cb) {
2467         var me = this;
2468
2469         if (me.tpl && !Ext.isString(htmlOrData)) {
2470             me.data = htmlOrData;
2471             if (me.rendered) {
2472                 me.tpl[me.tplWriteMode](me.getTargetEl(), htmlOrData || {});
2473             }
2474         } else {
2475             me.html = Ext.isObject(htmlOrData) ? Ext.DomHelper.markup(htmlOrData) : htmlOrData;
2476             if (me.rendered) {
2477                 me.getTargetEl().update(me.html, loadScripts, cb);
2478             }
2479         }
2480
2481         if (me.rendered) {
2482             me.doComponentLayout();
2483         }
2484     },
2485
2486     /**
2487      * Convenience function to hide or show this component by boolean.
2488      * @param {Boolean} visible True to show, false to hide
2489      * @return {Ext.Component} this
2490      */
2491     setVisible : function(visible) {
2492         return this[visible ? 'show': 'hide']();
2493     },
2494
2495     /**
2496      * Returns true if this component is visible.
2497      *
2498      * @param {Boolean} [deep=false] Pass `true` to interrogate the visibility status of all parent Containers to
2499      * determine whether this Component is truly visible to the user.
2500      *
2501      * Generally, to determine whether a Component is hidden, the no argument form is needed. For example when creating
2502      * dynamically laid out UIs in a hidden Container before showing them.
2503      *
2504      * @return {Boolean} True if this component is visible, false otherwise.
2505      */
2506     isVisible: function(deep) {
2507         var me = this,
2508             child = me,
2509             visible = !me.hidden,
2510             ancestor = me.ownerCt;
2511
2512         // Clear hiddenOwnerCt property
2513         me.hiddenAncestor = false;
2514         if (me.destroyed) {
2515             return false;
2516         }
2517
2518         if (deep && visible && me.rendered && ancestor) {
2519             while (ancestor) {
2520                 // If any ancestor is hidden, then this is hidden.
2521                 // If an ancestor Panel (only Panels have a collapse method) is collapsed,
2522                 // then its layoutTarget (body) is hidden, so this is hidden unless its within a
2523                 // docked item; they are still visible when collapsed (Unless they themseves are hidden)
2524                 if (ancestor.hidden || (ancestor.collapsed &&
2525                         !(ancestor.getDockedItems && Ext.Array.contains(ancestor.getDockedItems(), child)))) {
2526                     // Store hiddenOwnerCt property if needed
2527                     me.hiddenAncestor = ancestor;
2528                     visible = false;
2529                     break;
2530                 }
2531                 child = ancestor;
2532                 ancestor = ancestor.ownerCt;
2533             }
2534         }
2535         return visible;
2536     },
2537
2538     /**
2539      * Enable the component
2540      * @param {Boolean} [silent=false] Passing true will supress the 'enable' event from being fired.
2541      */
2542     enable: function(silent) {
2543         var me = this;
2544
2545         if (me.rendered) {
2546             me.el.removeCls(me.disabledCls);
2547             me.el.dom.disabled = false;
2548             me.onEnable();
2549         }
2550
2551         me.disabled = false;
2552
2553         if (silent !== true) {
2554             me.fireEvent('enable', me);
2555         }
2556
2557         return me;
2558     },
2559
2560     /**
2561      * Disable the component.
2562      * @param {Boolean} [silent=false] Passing true will supress the 'disable' event from being fired.
2563      */
2564     disable: function(silent) {
2565         var me = this;
2566
2567         if (me.rendered) {
2568             me.el.addCls(me.disabledCls);
2569             me.el.dom.disabled = true;
2570             me.onDisable();
2571         }
2572
2573         me.disabled = true;
2574
2575         if (silent !== true) {
2576             me.fireEvent('disable', me);
2577         }
2578
2579         return me;
2580     },
2581
2582     // @private
2583     onEnable: function() {
2584         if (this.maskOnDisable) {
2585             this.el.unmask();
2586         }
2587     },
2588
2589     // @private
2590     onDisable : function() {
2591         if (this.maskOnDisable) {
2592             this.el.mask();
2593         }
2594     },
2595
2596     /**
2597      * Method to determine whether this Component is currently disabled.
2598      * @return {Boolean} the disabled state of this Component.
2599      */
2600     isDisabled : function() {
2601         return this.disabled;
2602     },
2603
2604     /**
2605      * Enable or disable the component.
2606      * @param {Boolean} disabled True to disable.
2607      */
2608     setDisabled : function(disabled) {
2609         return this[disabled ? 'disable': 'enable']();
2610     },
2611
2612     /**
2613      * Method to determine whether this Component is currently set to hidden.
2614      * @return {Boolean} the hidden state of this Component.
2615      */
2616     isHidden : function() {
2617         return this.hidden;
2618     },
2619
2620     /**
2621      * Adds a CSS class to the top level element representing this component.
2622      * @param {String} cls The CSS class name to add
2623      * @return {Ext.Component} Returns the Component to allow method chaining.
2624      */
2625     addCls : function(className) {
2626         var me = this;
2627         if (!className) {
2628             return me;
2629         }
2630         if (!Ext.isArray(className)){
2631             className = className.replace(me.trimRe, '').split(me.spacesRe);
2632         }
2633         if (me.rendered) {
2634             me.el.addCls(className);
2635         }
2636         else {
2637             me.additionalCls = Ext.Array.unique(me.additionalCls.concat(className));
2638         }
2639         return me;
2640     },
2641
2642     /**
2643      * Adds a CSS class to the top level element representing this component.
2644      * @param {String} cls The CSS class name to add
2645      * @return {Ext.Component} Returns the Component to allow method chaining.
2646      */
2647     addClass : function() {
2648         return this.addCls.apply(this, arguments);
2649     },
2650
2651     /**
2652      * Removes a CSS class from the top level element representing this component.
2653      * @param {Object} className
2654      * @return {Ext.Component} Returns the Component to allow method chaining.
2655      */
2656     removeCls : function(className) {
2657         var me = this;
2658
2659         if (!className) {
2660             return me;
2661         }
2662         if (!Ext.isArray(className)){
2663             className = className.replace(me.trimRe, '').split(me.spacesRe);
2664         }
2665         if (me.rendered) {
2666             me.el.removeCls(className);
2667         }
2668         else if (me.additionalCls.length) {
2669             Ext.each(className, function(cls) {
2670                 Ext.Array.remove(me.additionalCls, cls);
2671             });
2672         }
2673         return me;
2674     },
2675
2676     //<debug>
2677     removeClass : function() {
2678         if (Ext.isDefined(Ext.global.console)) {
2679             Ext.global.console.warn('Ext.Component: removeClass has been deprecated. Please use removeCls.');
2680         }
2681         return this.removeCls.apply(this, arguments);
2682     },
2683     //</debug>
2684
2685     addOverCls: function() {
2686         var me = this;
2687         if (!me.disabled) {
2688             me.el.addCls(me.overCls);
2689         }
2690     },
2691
2692     removeOverCls: function() {
2693         this.el.removeCls(this.overCls);
2694     },
2695
2696     addListener : function(element, listeners, scope, options) {
2697         var me = this,
2698             fn,
2699             option;
2700
2701         if (Ext.isString(element) && (Ext.isObject(listeners) || options && options.element)) {
2702             if (options.element) {
2703                 fn = listeners;
2704
2705                 listeners = {};
2706                 listeners[element] = fn;
2707                 element = options.element;
2708                 if (scope) {
2709                     listeners.scope = scope;
2710                 }
2711
2712                 for (option in options) {
2713                     if (options.hasOwnProperty(option)) {
2714                         if (me.eventOptionsRe.test(option)) {
2715                             listeners[option] = options[option];
2716                         }
2717                     }
2718                 }
2719             }
2720
2721             // At this point we have a variable called element,
2722             // and a listeners object that can be passed to on
2723             if (me[element] && me[element].on) {
2724                 me.mon(me[element], listeners);
2725             } else {
2726                 me.afterRenderEvents = me.afterRenderEvents || {};
2727                 if (!me.afterRenderEvents[element]) {
2728                     me.afterRenderEvents[element] = [];
2729                 }
2730                 me.afterRenderEvents[element].push(listeners);
2731             }
2732         }
2733
2734         return me.mixins.observable.addListener.apply(me, arguments);
2735     },
2736
2737     // inherit docs
2738     removeManagedListenerItem: function(isClear, managedListener, item, ename, fn, scope){
2739         var me = this,
2740             element = managedListener.options ? managedListener.options.element : null;
2741
2742         if (element) {
2743             element = me[element];
2744             if (element && element.un) {
2745                 if (isClear || (managedListener.item === item && managedListener.ename === ename && (!fn || managedListener.fn === fn) && (!scope || managedListener.scope === scope))) {
2746                     element.un(managedListener.ename, managedListener.fn, managedListener.scope);
2747                     if (!isClear) {
2748                         Ext.Array.remove(me.managedListeners, managedListener);
2749                     }
2750                 }
2751             }
2752         } else {
2753             return me.mixins.observable.removeManagedListenerItem.apply(me, arguments);
2754         }
2755     },
2756
2757     /**
2758      * Provides the link for Observable's fireEvent method to bubble up the ownership hierarchy.
2759      * @return {Ext.container.Container} the Container which owns this Component.
2760      */
2761     getBubbleTarget : function() {
2762         return this.ownerCt;
2763     },
2764
2765     /**
2766      * Method to determine whether this Component is floating.
2767      * @return {Boolean} the floating state of this component.
2768      */
2769     isFloating : function() {
2770         return this.floating;
2771     },
2772
2773     /**
2774      * Method to determine whether this Component is draggable.
2775      * @return {Boolean} the draggable state of this component.
2776      */
2777     isDraggable : function() {
2778         return !!this.draggable;
2779     },
2780
2781     /**
2782      * Method to determine whether this Component is droppable.
2783      * @return {Boolean} the droppable state of this component.
2784      */
2785     isDroppable : function() {
2786         return !!this.droppable;
2787     },
2788
2789     /**
2790      * @private
2791      * Method to manage awareness of when components are added to their
2792      * respective Container, firing an added event.
2793      * References are established at add time rather than at render time.
2794      * @param {Ext.container.Container} container Container which holds the component
2795      * @param {Number} pos Position at which the component was added
2796      */
2797     onAdded : function(container, pos) {
2798         this.ownerCt = container;
2799         this.fireEvent('added', this, container, pos);
2800     },
2801
2802     /**
2803      * @private
2804      * Method to manage awareness of when components are removed from their
2805      * respective Container, firing an removed event. References are properly
2806      * cleaned up after removing a component from its owning container.
2807      */
2808     onRemoved : function() {
2809         var me = this;
2810
2811         me.fireEvent('removed', me, me.ownerCt);
2812         delete me.ownerCt;
2813     },
2814
2815     // @private
2816     beforeDestroy : Ext.emptyFn,
2817     // @private
2818     // @private
2819     onResize : Ext.emptyFn,
2820
2821     /**
2822      * Sets the width and height of this Component. This method fires the {@link #resize} event. This method can accept
2823      * either width and height as separate arguments, or you can pass a size object like `{width:10, height:20}`.
2824      *
2825      * @param {Number/String/Object} width The new width to set. This may be one of:
2826      *
2827      *   - A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).
2828      *   - A String used to set the CSS width style.
2829      *   - A size object in the format `{width: widthValue, height: heightValue}`.
2830      *   - `undefined` to leave the width unchanged.
2831      *
2832      * @param {Number/String} height The new height to set (not required if a size object is passed as the first arg).
2833      * This may be one of:
2834      *
2835      *   - A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).
2836      *   - A String used to set the CSS height style. Animation may **not** be used.
2837      *   - `undefined` to leave the height unchanged.
2838      *
2839      * @return {Ext.Component} this
2840      */
2841     setSize : function(width, height) {
2842         var me = this,
2843             layoutCollection;
2844
2845         // support for standard size objects
2846         if (Ext.isObject(width)) {
2847             height = width.height;
2848             width  = width.width;
2849         }
2850
2851         // Constrain within configured maxima
2852         if (Ext.isNumber(width)) {
2853             width = Ext.Number.constrain(width, me.minWidth, me.maxWidth);
2854         }
2855         if (Ext.isNumber(height)) {
2856             height = Ext.Number.constrain(height, me.minHeight, me.maxHeight);
2857         }
2858
2859         if (!me.rendered || !me.isVisible()) {
2860             // If an ownerCt is hidden, add my reference onto the layoutOnShow stack.  Set the needsLayout flag.
2861             if (me.hiddenAncestor) {
2862                 layoutCollection = me.hiddenAncestor.layoutOnShow;
2863                 layoutCollection.remove(me);
2864                 layoutCollection.add(me);
2865             }
2866             me.needsLayout = {
2867                 width: width,
2868                 height: height,
2869                 isSetSize: true
2870             };
2871             if (!me.rendered) {
2872                 me.width  = (width !== undefined) ? width : me.width;
2873                 me.height = (height !== undefined) ? height : me.height;
2874             }
2875             return me;
2876         }
2877         me.doComponentLayout(width, height, true);
2878
2879         return me;
2880     },
2881
2882     isFixedWidth: function() {
2883         var me = this,
2884             layoutManagedWidth = me.layoutManagedWidth;
2885
2886         if (Ext.isDefined(me.width) || layoutManagedWidth == 1) {
2887             return true;
2888         }
2889         if (layoutManagedWidth == 2) {
2890             return false;
2891         }
2892         return (me.ownerCt && me.ownerCt.isFixedWidth());
2893     },
2894
2895     isFixedHeight: function() {
2896         var me = this,
2897             layoutManagedHeight = me.layoutManagedHeight;
2898
2899         if (Ext.isDefined(me.height) || layoutManagedHeight == 1) {
2900             return true;
2901         }
2902         if (layoutManagedHeight == 2) {
2903             return false;
2904         }
2905         return (me.ownerCt && me.ownerCt.isFixedHeight());
2906     },
2907
2908     setCalculatedSize : function(width, height, callingContainer) {
2909         var me = this,
2910             layoutCollection;
2911
2912         // support for standard size objects
2913         if (Ext.isObject(width)) {
2914             callingContainer = width.ownerCt;
2915             height = width.height;
2916             width  = width.width;
2917         }
2918
2919         // Constrain within configured maxima
2920         if (Ext.isNumber(width)) {
2921             width = Ext.Number.constrain(width, me.minWidth, me.maxWidth);
2922         }
2923         if (Ext.isNumber(height)) {
2924             height = Ext.Number.constrain(height, me.minHeight, me.maxHeight);
2925         }
2926
2927         if (!me.rendered || !me.isVisible()) {
2928             // If an ownerCt is hidden, add my reference onto the layoutOnShow stack.  Set the needsLayout flag.
2929             if (me.hiddenAncestor) {
2930                 layoutCollection = me.hiddenAncestor.layoutOnShow;
2931                 layoutCollection.remove(me);
2932                 layoutCollection.add(me);
2933             }
2934             me.needsLayout = {
2935                 width: width,
2936                 height: height,
2937                 isSetSize: false,
2938                 ownerCt: callingContainer
2939             };
2940             return me;
2941         }
2942         me.doComponentLayout(width, height, false, callingContainer);
2943
2944         return me;
2945     },
2946
2947     /**
2948      * This method needs to be called whenever you change something on this component that requires the Component's
2949      * layout to be recalculated.
2950      * @param {Object} width
2951      * @param {Object} height
2952      * @param {Object} isSetSize
2953      * @param {Object} callingContainer
2954      * @return {Ext.container.Container} this
2955      */
2956     doComponentLayout : function(width, height, isSetSize, callingContainer) {
2957         var me = this,
2958             componentLayout = me.getComponentLayout(),
2959             lastComponentSize = componentLayout.lastComponentSize || {
2960                 width: undefined,
2961                 height: undefined
2962             };
2963
2964         // collapsed state is not relevant here, so no testing done.
2965         // Only Panels have a collapse method, and that just sets the width/height such that only
2966         // a single docked Header parallel to the collapseTo side are visible, and the Panel body is hidden.
2967         if (me.rendered && componentLayout) {
2968             // If no width passed, then only insert a value if the Component is NOT ALLOWED to autowidth itself.
2969             if (!Ext.isDefined(width)) {
2970                 if (me.isFixedWidth()) {
2971                     width = Ext.isDefined(me.width) ? me.width : lastComponentSize.width;
2972                 }
2973             }
2974             // If no height passed, then only insert a value if the Component is NOT ALLOWED to autoheight itself.
2975             if (!Ext.isDefined(height)) {
2976                 if (me.isFixedHeight()) {
2977                     height = Ext.isDefined(me.height) ? me.height : lastComponentSize.height;
2978                 }
2979             }
2980
2981             if (isSetSize) {
2982                 me.width = width;
2983                 me.height = height;
2984             }
2985
2986             componentLayout.layout(width, height, isSetSize, callingContainer);
2987         }
2988
2989         return me;
2990     },
2991
2992     /**
2993      * Forces this component to redo its componentLayout.
2994      */
2995     forceComponentLayout: function () {
2996         this.doComponentLayout();
2997     },
2998
2999     // @private
3000     setComponentLayout : function(layout) {
3001         var currentLayout = this.componentLayout;
3002         if (currentLayout && currentLayout.isLayout && currentLayout != layout) {
3003             currentLayout.setOwner(null);
3004         }
3005         this.componentLayout = layout;
3006         layout.setOwner(this);
3007     },
3008
3009     getComponentLayout : function() {
3010         var me = this;
3011
3012         if (!me.componentLayout || !me.componentLayout.isLayout) {
3013             me.setComponentLayout(Ext.layout.Layout.create(me.componentLayout, 'autocomponent'));
3014         }
3015         return me.componentLayout;
3016     },
3017
3018     /**
3019      * Occurs after componentLayout is run.
3020      * @param {Number} adjWidth The box-adjusted width that was set
3021      * @param {Number} adjHeight The box-adjusted height that was set
3022      * @param {Boolean} isSetSize Whether or not the height/width are stored on the component permanently
3023      * @param {Ext.Component} callingContainer Container requesting the layout. Only used when isSetSize is false.
3024      */
3025     afterComponentLayout: function(width, height, isSetSize, callingContainer) {
3026         var me = this,
3027             layout = me.componentLayout,
3028             oldSize = me.preLayoutSize;
3029
3030         ++me.componentLayoutCounter;
3031         if (!oldSize || ((width !== oldSize.width) || (height !== oldSize.height))) {
3032             me.fireEvent('resize', me, width, height);
3033         }
3034     },
3035
3036     /**
3037      * Occurs before componentLayout is run. Returning false from this method will prevent the componentLayout from
3038      * being executed.
3039      * @param {Number} adjWidth The box-adjusted width that was set
3040      * @param {Number} adjHeight The box-adjusted height that was set
3041      * @param {Boolean} isSetSize Whether or not the height/width are stored on the component permanently
3042      * @param {Ext.Component} callingContainer Container requesting sent the layout. Only used when isSetSize is false.
3043      */
3044     beforeComponentLayout: function(width, height, isSetSize, callingContainer) {
3045         this.preLayoutSize = this.componentLayout.lastComponentSize;
3046         return true;
3047     },
3048
3049     /**
3050      * Sets the left and top of the component. To set the page XY position instead, use
3051      * {@link Ext.Component#setPagePosition setPagePosition}. This method fires the {@link #move} event.
3052      * @param {Number} left The new left
3053      * @param {Number} top The new top
3054      * @return {Ext.Component} this
3055      */
3056     setPosition : function(x, y) {
3057         var me = this;
3058
3059         if (Ext.isObject(x)) {
3060             y = x.y;
3061             x = x.x;
3062         }
3063
3064         if (!me.rendered) {
3065             return me;
3066         }
3067
3068         if (x !== undefined || y !== undefined) {
3069             me.el.setBox(x, y);
3070             me.onPosition(x, y);
3071             me.fireEvent('move', me, x, y);
3072         }
3073         return me;
3074     },
3075
3076     /**
3077      * @private
3078      * Called after the component is moved, this method is empty by default but can be implemented by any
3079      * subclass that needs to perform custom logic after a move occurs.
3080      * @param {Number} x The new x position
3081      * @param {Number} y The new y position
3082      */
3083     onPosition: Ext.emptyFn,
3084
3085     /**
3086      * Sets the width of the component. This method fires the {@link #resize} event.
3087      *
3088      * @param {Number} width The new width to setThis may be one of:
3089      *
3090      *   - A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).
3091      *   - A String used to set the CSS width style.
3092      *
3093      * @return {Ext.Component} this
3094      */
3095     setWidth : function(width) {
3096         return this.setSize(width);
3097     },
3098
3099     /**
3100      * Sets the height of the component. This method fires the {@link #resize} event.
3101      *
3102      * @param {Number} height The new height to set. This may be one of:
3103      *
3104      *   - A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).
3105      *   - A String used to set the CSS height style.
3106      *   - _undefined_ to leave the height unchanged.
3107      *
3108      * @return {Ext.Component} this
3109      */
3110     setHeight : function(height) {
3111         return this.setSize(undefined, height);
3112     },
3113
3114     /**
3115      * Gets the current size of the component's underlying element.
3116      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
3117      */
3118     getSize : function() {
3119         return this.el.getSize();
3120     },
3121
3122     /**
3123      * Gets the current width of the component's underlying element.
3124      * @return {Number}
3125      */
3126     getWidth : function() {
3127         return this.el.getWidth();
3128     },
3129
3130     /**
3131      * Gets the current height of the component's underlying element.
3132      * @return {Number}
3133      */
3134     getHeight : function() {
3135         return this.el.getHeight();
3136     },
3137
3138     /**
3139      * Gets the {@link Ext.ComponentLoader} for this Component.
3140      * @return {Ext.ComponentLoader} The loader instance, null if it doesn't exist.
3141      */
3142     getLoader: function(){
3143         var me = this,
3144             autoLoad = me.autoLoad ? (Ext.isObject(me.autoLoad) ? me.autoLoad : {url: me.autoLoad}) : null,
3145             loader = me.loader || autoLoad;
3146
3147         if (loader) {
3148             if (!loader.isLoader) {
3149                 me.loader = Ext.create('Ext.ComponentLoader', Ext.apply({
3150                     target: me,
3151                     autoLoad: autoLoad
3152                 }, loader));
3153             } else {
3154                 loader.setTarget(me);
3155             }
3156             return me.loader;
3157
3158         }
3159         return null;
3160     },
3161
3162     /**
3163      * This method allows you to show or hide a LoadMask on top of this component.
3164      *
3165      * @param {Boolean/Object/String} load True to show the default LoadMask, a config object that will be passed to the
3166      * LoadMask constructor, or a message String to show. False to hide the current LoadMask.
3167      * @param {Boolean} [targetEl=false] True to mask the targetEl of this Component instead of the `this.el`. For example,
3168      * setting this to true on a Panel will cause only the body to be masked.
3169      * @return {Ext.LoadMask} The LoadMask instance that has just been shown.
3170      */
3171     setLoading : function(load, targetEl) {
3172         var me = this,
3173             config;
3174
3175         if (me.rendered) {
3176             if (load !== false && !me.collapsed) {
3177                 if (Ext.isObject(load)) {
3178                     config = load;
3179                 }
3180                 else if (Ext.isString(load)) {
3181                     config = {msg: load};
3182                 }
3183                 else {
3184                     config = {};
3185                 }
3186                 me.loadMask = me.loadMask || Ext.create('Ext.LoadMask', targetEl ? me.getTargetEl() : me.el, config);
3187                 me.loadMask.show();
3188             } else if (me.loadMask) {
3189                 Ext.destroy(me.loadMask);
3190                 me.loadMask = null;
3191             }
3192         }
3193
3194         return me.loadMask;
3195     },
3196
3197     /**
3198      * Sets the dock position of this component in its parent panel. Note that this only has effect if this item is part
3199      * of the dockedItems collection of a parent that has a DockLayout (note that any Panel has a DockLayout by default)
3200      * @param {Object} dock The dock position.
3201      * @param {Boolean} [layoutParent=false] True to re-layout parent.
3202      * @return {Ext.Component} this
3203      */
3204     setDocked : function(dock, layoutParent) {
3205         var me = this;
3206
3207         me.dock = dock;
3208         if (layoutParent && me.ownerCt && me.rendered) {
3209             me.ownerCt.doComponentLayout();
3210         }
3211         return me;
3212     },
3213
3214     onDestroy : function() {
3215         var me = this;
3216
3217         if (me.monitorResize && Ext.EventManager.resizeEvent) {
3218             Ext.EventManager.resizeEvent.removeListener(me.setSize, me);
3219         }
3220         // Destroying the floatingItems ZIndexManager will also destroy descendant floating Components
3221         Ext.destroy(
3222             me.componentLayout,
3223             me.loadMask,
3224             me.floatingItems
3225         );
3226     },
3227
3228     /**
3229      * Remove any references to elements added via renderSelectors/childEls
3230      * @private
3231      */
3232     cleanElementRefs: function(){
3233         var me = this,
3234             i = 0,
3235             childEls = me.childEls,
3236             selectors = me.renderSelectors,
3237             selector,
3238             name,
3239             len;
3240
3241         if (me.rendered) {
3242             if (childEls) {
3243                 for (len = childEls.length; i < len; ++i) {
3244                     name = childEls[i];
3245                     if (typeof(name) != 'string') {
3246                         name = name.name;
3247                     }
3248                     delete me[name];
3249                 }
3250             }
3251
3252             if (selectors) {
3253                 for (selector in selectors) {
3254                     if (selectors.hasOwnProperty(selector)) {
3255                         delete me[selector];
3256                     }
3257                 }
3258             }
3259         }
3260         delete me.rendered;
3261         delete me.el;
3262         delete me.frameBody;
3263     },
3264
3265     /**
3266      * Destroys the Component.
3267      */
3268     destroy : function() {
3269         var me = this;
3270
3271         if (!me.isDestroyed) {
3272             if (me.fireEvent('beforedestroy', me) !== false) {
3273                 me.destroying = true;
3274                 me.beforeDestroy();
3275
3276                 if (me.floating) {
3277                     delete me.floatParent;
3278                     // A zIndexManager is stamped into a *floating* Component when it is added to a Container.
3279                     // If it has no zIndexManager at render time, it is assigned to the global Ext.WindowManager instance.
3280                     if (me.zIndexManager) {
3281                         me.zIndexManager.unregister(me);
3282                     }
3283                 } else if (me.ownerCt && me.ownerCt.remove) {
3284                     me.ownerCt.remove(me, false);
3285                 }
3286
3287                 me.onDestroy();
3288
3289                 // Attempt to destroy all plugins
3290                 Ext.destroy(me.plugins);
3291
3292                 if (me.rendered) {
3293                     me.el.remove();
3294                 }
3295
3296                 me.fireEvent('destroy', me);
3297                 Ext.ComponentManager.unregister(me);
3298
3299                 me.mixins.state.destroy.call(me);
3300
3301                 me.clearListeners();
3302                 // make sure we clean up the element references after removing all events
3303                 me.cleanElementRefs();
3304                 me.destroying = false;
3305                 me.isDestroyed = true;
3306             }
3307         }
3308     },
3309
3310     /**
3311      * Retrieves a plugin by its pluginId which has been bound to this component.
3312      * @param {Object} pluginId
3313      * @return {Ext.AbstractPlugin} plugin instance.
3314      */
3315     getPlugin: function(pluginId) {
3316         var i = 0,
3317             plugins = this.plugins,
3318             ln = plugins.length;
3319         for (; i < ln; i++) {
3320             if (plugins[i].pluginId === pluginId) {
3321                 return plugins[i];
3322             }
3323         }
3324     },
3325
3326     /**
3327      * Determines whether this component is the descendant of a particular container.
3328      * @param {Ext.Container} container
3329      * @return {Boolean} True if it is.
3330      */
3331     isDescendantOf: function(container) {
3332         return !!this.findParentBy(function(p){
3333             return p === container;
3334         });
3335     }
3336 }, function() {
3337     this.createAlias({
3338         on: 'addListener',
3339         prev: 'previousSibling',
3340         next: 'nextSibling'
3341     });
3342 });
3343