3
* Copyright(c) 2006-2008, Ext JS, LLC.
6
* http://extjs.com/license
10
* @class Ext.Component
11
* @extends Ext.util.Observable
12
* <p>Base class for all Ext components. All subclasses of Component can automatically participate in the standard
13
* Ext component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
14
* and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Ext.Container} and
15
* to be automatically registered with the {@link Ext.ComponentMgr} so that it can be referenced at any time via
16
* {@link Ext#getCmp}. All visual widgets that require rendering into a layout should subclass Component (or
17
* {@link Ext.BoxComponent} if managed box model handling is required).</p>
18
* <p>Every component has a specific xtype, which is its Ext-specific type name, along with methods for checking the
19
* xtype like {@link #getXType} and {@link #isXType}. This is the list of all valid xtypes:</p>
22
------------- ------------------
25
colorpalette Ext.ColorPalette
26
component Ext.Component
27
container Ext.Container
30
datepicker Ext.DatePicker
32
editorgrid Ext.grid.EditorGridPanel
33
grid Ext.grid.GridPanel
34
paging Ext.PagingToolbar
36
progress Ext.ProgressBar
37
propertygrid Ext.grid.PropertyGrid
39
splitbutton Ext.SplitButton
40
statusbar Ext.StatusBar
42
treepanel Ext.tree.TreePanel
47
---------------------------------------
49
tbbutton Ext.Toolbar.Button
50
tbfill Ext.Toolbar.Fill
51
tbitem Ext.Toolbar.Item
52
tbseparator Ext.Toolbar.Separator
53
tbspacer Ext.Toolbar.Spacer
54
tbsplit Ext.Toolbar.SplitButton
55
tbtext Ext.Toolbar.TextItem
58
---------------------------------------
60
checkbox Ext.form.Checkbox
61
combo Ext.form.ComboBox
62
datefield Ext.form.DateField
64
fieldset Ext.form.FieldSet
65
hidden Ext.form.Hidden
66
htmleditor Ext.form.HtmlEditor
68
numberfield Ext.form.NumberField
70
textarea Ext.form.TextArea
71
textfield Ext.form.TextField
72
timefield Ext.form.TimeField
73
trigger Ext.form.TriggerField
76
* @param {Ext.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
77
* element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
78
* and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
80
Ext.Component = function(config){
81
config = config || {};
82
if(config.initialConfig){
83
if(config.isAction){ // actions
84
this.baseAction = config;
86
config = config.initialConfig; // component cloning / action set up
87
}else if(config.tagName || config.dom || typeof config == "string"){ // element object
88
config = {applyTo: config, id: config.id || config};
92
* This Component's initial configuration specification. Read-only.
94
* @property initialConfig
96
this.initialConfig = config;
98
Ext.apply(this, config);
102
* Fires after the component is disabled.
103
* @param {Ext.Component} this
108
* Fires after the component is enabled.
109
* @param {Ext.Component} this
114
* Fires before the component is shown. Return false to stop the show.
115
* @param {Ext.Component} this
120
* Fires after the component is shown.
121
* @param {Ext.Component} this
126
* Fires before the component is hidden. Return false to stop the hide.
127
* @param {Ext.Component} this
132
* Fires after the component is hidden.
133
* @param {Ext.Component} this
137
* @event beforerender
138
* Fires before the component is rendered. Return false to stop the render.
139
* @param {Ext.Component} this
144
* Fires after the component is rendered.
145
* @param {Ext.Component} this
149
* @event beforedestroy
150
* Fires before the component is destroyed. Return false to stop the destroy.
151
* @param {Ext.Component} this
156
* Fires after the component is destroyed.
157
* @param {Ext.Component} this
161
* @event beforestaterestore
162
* Fires before the state of the component is restored. Return false to stop the restore.
163
* @param {Ext.Component} this
164
* @param {Object} state The hash of state values
166
'beforestaterestore',
168
* @event staterestore
169
* Fires after the state of the component is restored.
170
* @param {Ext.Component} this
171
* @param {Object} state The hash of state values
175
* @event beforestatesave
176
* Fires before the state of the component is saved to the configured state provider. Return false to stop the save.
177
* @param {Ext.Component} this
178
* @param {Object} state The hash of state values
183
* Fires after the state of the component is saved to the configured state provider.
184
* @param {Ext.Component} this
185
* @param {Object} state The hash of state values
190
Ext.ComponentMgr.register(this);
191
Ext.Component.superclass.constructor.call(this);
194
this.baseAction.addComponent(this);
197
this.initComponent();
200
if(Ext.isArray(this.plugins)){
201
for(var i = 0, len = this.plugins.length; i < len; i++){
202
this.plugins[i] = this.initPlugin(this.plugins[i]);
205
this.plugins = this.initPlugin(this.plugins);
209
if(this.stateful !== false){
210
this.initState(config);
214
this.applyToMarkup(this.applyTo);
216
}else if(this.renderTo){
217
this.render(this.renderTo);
218
delete this.renderTo;
223
Ext.Component.AUTO_ID = 1000;
225
Ext.extend(Ext.Component, Ext.util.Observable, {
228
* The unique id of this component (defaults to an auto-assigned id).
231
* @cfg {String/Object} autoEl
232
* A tag name or DomHelper spec to create an element with. This is intended to create shorthand
233
* utility components inline via JSON. It should not be used for higher level components which already create
234
* their own elements. Example usage:
236
{xtype:'box', autoEl: 'div', cls:'my-class'}
237
{xtype:'box', autoEl: {tag:'blockquote', html:'autoEl is cool!'}} // with DomHelper
241
* @cfg {String} xtype
242
* The registered xtype to create. This config option is not used when passing
243
* a config object into a constructor. This config option is used only when
244
* lazy instantiation is being used, and a child item of a Container is being
245
* specified not as a fully instantiated Component, but as a <i>Component config
246
* object</i>. The xtype will be looked up at render time up to determine what
247
* type of child Component to create.<br><br>
248
* The predefined xtypes are listed {@link Ext.Component here}.
250
* If you subclass Components to create your own Components, you may register
251
* them using {@link Ext.ComponentMgr#registerType} in order to be able to
252
* take advantage of lazy instantiation and rendering.
256
* An optional extra CSS class that will be added to this component's Element (defaults to ''). This can be
257
* useful for adding customized styles to the component or any of its children using standard CSS rules.
260
* @cfg {String} overCls
261
* An optional extra CSS class that will be added to this component's Element when the mouse moves
262
* over the Element, and removed when the mouse moves out. (defaults to ''). This can be
263
* useful for adding customized "active" or "hover" styles to the component or any of its children using standard CSS rules.
266
* @cfg {String} style
267
* A custom style specification to be applied to this component's Element. Should be a valid argument to
268
* {@link Ext.Element#applyStyles}.
271
* @cfg {String} ctCls
272
* An optional extra CSS class that will be added to this component's container (defaults to ''). This can be
273
* useful for adding customized styles to the container or any of its children using standard CSS rules.
276
* @cfg {Boolean} disabled
277
* Render this component disabled (default is false).
280
* @cfg {Boolean} hidden
281
* Render this component hidden (default is false).
284
* @cfg {Object/Array} plugins
285
* An object or array of objects that will provide custom functionality for this component. The only
286
* requirement for a valid plugin is that it contain an init method that accepts a reference of type Ext.Component.
287
* When a component is created, if any plugins are available, the component will call the init method on each
288
* plugin, passing a reference to itself. Each plugin can then call methods or respond to events on the
289
* component as needed to provide its functionality.
292
* @cfg {Mixed} applyTo
293
* The id of the node, a DOM node or an existing Element corresponding to a DIV that is already present in
294
* the document that specifies some structural markup for this component. When applyTo is used, constituent parts of
295
* the component can also be specified by id or CSS class name within the main element, and the component being created
296
* may attempt to create its subcomponents from that markup if applicable. Using this config, a call to render() is
297
* not required. If applyTo is specified, any value passed for {@link #renderTo} will be ignored and the target
298
* element's parent node will automatically be used as the component's container.
301
* @cfg {Mixed} renderTo
302
* The id of the node, a DOM node or an existing Element that will be the container to render this component into.
303
* Using this config, a call to render() is not required.
307
* @cfg {Boolean} stateful
308
* A flag which causes the Component to attempt to restore the state of internal properties
309
* from a saved state on startup.<p>
310
* For state saving to work, the state manager's provider must have been set to an implementation
311
* of {@link Ext.state.Provider} which overrides the {@link Ext.state.Provider#set set}
312
* and {@link Ext.state.Provider#get get} methods to save and recall name/value pairs.
313
* A built-in implementation, {@link Ext.state.CookieProvider} is available.</p>
314
* <p>To set the state provider for the current page:</p>
316
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
318
* <p>Components attempt to save state when one of the events listed in the {@link #stateEvents}
319
* configuration fires.</p>
320
* <p>You can perform extra processing on state save and restore by attaching handlers to the
321
* {@link #beforestaterestore}, {@link staterestore}, {@link beforestatesave} and {@link statesave} events</p>
324
* @cfg {String} stateId
325
* The unique id for this component to use for state management purposes (defaults to the component id).
326
* <p>See {@link #stateful} for an explanation of saving and restoring Component state.</p>
328
/* //internal - to be set by subclasses
329
* @cfg {Array} stateEvents
330
* An array of events that, when fired, should trigger this component to save its state (defaults to none).
331
* These can be any types of events supported by this component, including browser or custom events (e.g.,
332
* ['click', 'customerchange']).
333
* <p>See {@link #stateful} for an explanation of saving and restoring Component state.</p>
337
* @cfg {String} disabledClass
338
* CSS class added to the component when it is disabled (defaults to "x-item-disabled").
340
disabledClass : "x-item-disabled",
342
* @cfg {Boolean} allowDomMove
343
* Whether the component can move the Dom node when rendering (defaults to true).
347
* @cfg {Boolean} autoShow
348
* True if the component should check for hidden classes (e.g. 'x-hidden' or 'x-hide-display') and remove
349
* them on render (defaults to false).
353
* @cfg {String} hideMode
354
* How this component should hidden. Supported values are "visibility" (css visibility), "offsets" (negative
355
* offset position) and "display" (css display) - defaults to "display".
359
* @cfg {Boolean} hideParent
360
* True to hide and show the component's container when hide/show is called on the component, false to hide
361
* and show the component itself (defaults to false). For example, this can be used as a shortcut for a hide
362
* button on a window by setting hide:true on the button when adding it to its parent container.
367
* The component's owner {@link Ext.Container} (defaults to undefined, and is set automatically when
368
* the component is added to a container). Read-only.
369
* @type Ext.Container
373
* True if this component is hidden. Read-only.
379
* True if this component is disabled. Read-only.
385
* True if this component has been rendered. Read-only.
392
ctype : "Ext.Component",
398
getActionEl : function(){
399
return this[this.actionMode];
402
initPlugin : function(p){
408
* Function to be implemented by Component subclasses to be part of standard component initialization flow (it is empty by default).
410
// Traditional constructor:
411
Ext.Foo = function(config){
412
// call superclass constructor:
413
Ext.Foo.superclass.constructor.call(this, config);
419
Ext.extend(Ext.Foo, Ext.Bar, {
423
// initComponent replaces the constructor:
424
Ext.Foo = Ext.extend(Ext.Bar, {
425
initComponent : function(){
426
// call superclass initComponent
427
Ext.Container.superclass.initComponent.call(this);
436
initComponent : Ext.emptyFn,
439
* <p>Render this Components into the passed HTML element.</p>
440
* <p><b>If you are using a {@link Ext.Container Container} object to house this Component, then
441
* do not use the render method.</b></p>
442
* <p>A Container's child Components are rendered by that Container's
443
* {@link Ext.Container#layout layout} manager when the Container is first rendered.</p>
444
* <p>Certain layout managers allow dynamic addition of child components. Those that do
445
* include {@link Ext.layout.CardLayout}, {@link Ext.layout.AnchorLayout},
446
* {@link Ext.layout.FormLayout}, {@link Ext.layout.TableLayout}.</p>
447
* <p>If the Container is already rendered when a new child Component is added, you may need to call
448
* the Container's {@link Ext.Container#doLayout doLayout} to refresh the view which causes any
449
* unrendered child Components to be rendered. This is required so that you can add multiple
450
* child components if needed while only refreshing the layout once.</p>
451
* <p>When creating complex UIs, it is important to remember that sizing and positioning
452
* of child items is the responsibility of the Container's {@link Ext.Container#layout layout} manager.
453
* If you expect child items to be sized in response to user interactions, you must
454
* configure the Container with a layout manager which creates and manages the type of layout you
456
* <p><b>Omitting the Container's {@link Ext.Container#layout layout} config means that a basic
457
* layout manager is used which does nothnig but render child components sequentially into the
458
* Container. No sizing or positioning will be performed in this situation.</b></p>
459
* @param {Element/HTMLElement/String} container (optional) The element this Component should be
460
* rendered into. If it is being created from existing markup, this should be omitted.
461
* @param {String/Number} position (optional) The element ID or DOM node index within the container <b>before</b>
462
* which this component will be inserted (defaults to appending to the end of the container)
464
render : function(container, position){
465
if(!this.rendered && this.fireEvent("beforerender", this) !== false){
466
if(!container && this.el){
467
this.el = Ext.get(this.el);
468
container = this.el.dom.parentNode;
469
this.allowDomMove = false;
471
this.container = Ext.get(container);
473
this.container.addClass(this.ctCls);
475
this.rendered = true;
476
if(position !== undefined){
477
if(typeof position == 'number'){
478
position = this.container.dom.childNodes[position];
480
position = Ext.getDom(position);
483
this.onRender(this.container, position || null);
485
this.el.removeClass(['x-hidden','x-hide-' + this.hideMode]);
488
this.el.addClass(this.cls);
492
this.el.applyStyles(this.style);
495
this.fireEvent("render", this);
496
this.afterRender(this.container);
504
if(this.stateful !== false){
505
this.initStateEvents();
512
initState : function(config){
513
if(Ext.state.Manager){
514
var state = Ext.state.Manager.get(this.stateId || this.id);
516
if(this.fireEvent('beforestaterestore', this, state) !== false){
517
this.applyState(state);
518
this.fireEvent('staterestore', this, state);
525
initStateEvents : function(){
526
if(this.stateEvents){
527
for(var i = 0, e; e = this.stateEvents[i]; i++){
528
this.on(e, this.saveState, this, {delay:100});
534
applyState : function(state, config){
536
Ext.apply(this, state);
541
getState : function(){
546
saveState : function(){
547
if(Ext.state.Manager){
548
var state = this.getState();
549
if(this.fireEvent('beforestatesave', this, state) !== false){
550
Ext.state.Manager.set(this.stateId || this.id, state);
551
this.fireEvent('statesave', this, state);
557
* Apply this component to existing markup that is valid. With this function, no call to render() is required.
558
* @param {String/HTMLElement} el
560
applyToMarkup : function(el){
561
this.allowDomMove = false;
562
this.el = Ext.get(el);
563
this.render(this.el.dom.parentNode);
567
* Adds a CSS class to the component's underlying element.
568
* @param {string} cls The CSS class name to add
570
addClass : function(cls){
572
this.el.addClass(cls);
574
this.cls = this.cls ? this.cls + ' ' + cls : cls;
579
* Removes a CSS class from the component's underlying element.
580
* @param {string} cls The CSS class name to remove
582
removeClass : function(cls){
584
this.el.removeClass(cls);
586
this.cls = this.cls.split(' ').remove(cls).join(' ');
591
// default function is not really useful
592
onRender : function(ct, position){
594
if(typeof this.autoEl == 'string'){
595
this.el = document.createElement(this.autoEl);
597
var div = document.createElement('div');
598
Ext.DomHelper.overwrite(div, this.autoEl);
599
this.el = div.firstChild;
602
this.el.id = this.getId();
606
this.el = Ext.get(this.el);
607
if(this.allowDomMove !== false){
608
ct.dom.insertBefore(this.el.dom, position);
611
this.el.addClassOnOver(this.overCls);
617
getAutoCreate : function(){
618
var cfg = typeof this.autoCreate == "object" ?
619
this.autoCreate : Ext.apply({}, this.defaultAutoCreate);
620
if(this.id && !cfg.id){
627
afterRender : Ext.emptyFn,
630
* Destroys this component by purging any event listeners, removing the component's element from the DOM,
631
* removing the component from its {@link Ext.Container} (if applicable) and unregistering it from
632
* {@link Ext.ComponentMgr}. Destruction is generally handled automatically by the framework and this method
633
* should usually not need to be called directly.
635
destroy : function(){
636
if(this.fireEvent("beforedestroy", this) !== false){
637
this.beforeDestroy();
639
this.el.removeAllListeners();
641
if(this.actionMode == "container"){
642
this.container.remove();
646
Ext.ComponentMgr.unregister(this);
647
this.fireEvent("destroy", this);
648
this.purgeListeners();
653
beforeDestroy : Ext.emptyFn,
656
onDestroy : Ext.emptyFn,
659
* Returns the underlying {@link Ext.Element}.
660
* @return {Ext.Element} The element
667
* Returns the id of this component.
671
return this.id || (this.id = "ext-comp-" + (++Ext.Component.AUTO_ID));
675
* Returns the item id of this component.
678
getItemId : function(){
679
return this.itemId || this.getId();
683
* Try to focus this component.
684
* @param {Boolean} selectText (optional) If applicable, true to also select the text in this component
685
* @param {Boolean/Number} delay (optional) Delay the focus this number of milliseconds (true for 10 milliseconds)
686
* @return {Ext.Component} this
688
focus : function(selectText, delay){
690
this.focus.defer(typeof delay == 'number' ? delay : 10, this, [selectText, false]);
695
if(selectText === true){
696
this.el.dom.select();
711
* Disable this component.
712
* @return {Ext.Component} this
714
disable : function(){
718
this.disabled = true;
719
this.fireEvent("disable", this);
724
onDisable : function(){
725
this.getActionEl().addClass(this.disabledClass);
726
this.el.dom.disabled = true;
730
* Enable this component.
731
* @return {Ext.Component} this
737
this.disabled = false;
738
this.fireEvent("enable", this);
743
onEnable : function(){
744
this.getActionEl().removeClass(this.disabledClass);
745
this.el.dom.disabled = false;
749
* Convenience function for setting disabled/enabled by boolean.
750
* @param {Boolean} disabled
752
setDisabled : function(disabled){
753
this[disabled ? "disable" : "enable"]();
757
* Show this component.
758
* @return {Ext.Component} this
761
if(this.fireEvent("beforeshow", this) !== false){
764
this.render(typeof this.autoRender == 'boolean' ? Ext.getBody() : this.autoRender);
769
this.fireEvent("show", this);
777
this.container.removeClass('x-hide-' + this.hideMode);
779
this.getActionEl().removeClass('x-hide-' + this.hideMode);
785
* Hide this component.
786
* @return {Ext.Component} this
789
if(this.fireEvent("beforehide", this) !== false){
794
this.fireEvent("hide", this);
802
this.container.addClass('x-hide-' + this.hideMode);
804
this.getActionEl().addClass('x-hide-' + this.hideMode);
809
* Convenience function to hide or show this component by boolean.
810
* @param {Boolean} visible True to show, false to hide
811
* @return {Ext.Component} this
813
setVisible: function(visible){
823
* Returns true if this component is visible.
825
isVisible : function(){
826
return this.rendered && this.getActionEl().isVisible();
830
* Clone the current component using the original config values passed into this instance by default.
831
* @param {Object} overrides A new config containing any properties to override in the cloned version.
832
* An id property can be passed on this object, otherwise one will be generated to avoid duplicates.
833
* @return {Ext.Component} clone The cloned copy of this component
835
cloneConfig : function(overrides){
836
overrides = overrides || {};
837
var id = overrides.id || Ext.id();
838
var cfg = Ext.applyIf(overrides, this.initialConfig);
839
cfg.id = id; // prevent dup id
840
return new this.constructor(cfg);
844
* Gets the xtype for this component as registered with {@link Ext.ComponentMgr}. For a list of all
845
* available xtypes, see the {@link Ext.Component} header. Example usage:
847
var t = new Ext.form.TextField();
848
alert(t.getXType()); // alerts 'textfield'
850
* @return {String} The xtype
852
getXType : function(){
853
return this.constructor.xtype;
857
* <p>Tests whether or not this Component is of a specific xtype. This can test whether this Component is descended
858
* from the xtype (default) or whether it is directly of the xtype specified (shallow = true).</p>
859
* <p><b>If using your own subclasses, be aware that a Component must register its own xtype
860
* to participate in determination of inherited xtypes.</b></p>
861
* <p>For a list of all available xtypes, see the {@link Ext.Component} header.</p>
862
* <p>Example usage:</p>
864
var t = new Ext.form.TextField();
865
var isText = t.isXType('textfield'); // true
866
var isBoxSubclass = t.isXType('box'); // true, descended from BoxComponent
867
var isBoxInstance = t.isXType('box', true); // false, not a direct BoxComponent instance
869
* @param {String} xtype The xtype to check for this Component
870
* @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
871
* the default), or true to check whether this Component is directly of the specified xtype.
873
isXType : function(xtype, shallow){
875
('/' + this.getXTypes() + '/').indexOf('/' + xtype + '/') != -1 :
876
this.constructor.xtype == xtype;
880
* <p>Returns this Component's xtype hierarchy as a slash-delimited string. For a list of all
881
* available xtypes, see the {@link Ext.Component} header.</p>
882
* <p><b>If using your own subclasses, be aware that a Component must register its own xtype
883
* to participate in determination of inherited xtypes.</b></p>
884
* <p>Example usage:</p>
886
var t = new Ext.form.TextField();
887
alert(t.getXTypes()); // alerts 'component/box/field/textfield'
889
* @return {String} The xtype hierarchy string
891
getXTypes : function(){
892
var tc = this.constructor;
894
var c = [], sc = this;
895
while(sc && sc.constructor.xtype){
896
c.unshift(sc.constructor.xtype);
897
sc = sc.constructor.superclass;
900
tc.xtypes = c.join('/');
906
* Find a container above this component at any level by a custom function. If the passed function returns
907
* true, the container will be returned. The passed function is called with the arguments (container, this component).
908
* @param {Function} fcn
909
* @param {Object} scope (optional)
910
* @return {Array} Array of Ext.Components
912
findParentBy: function(fn) {
913
for (var p = this.ownerCt; (p != null) && !fn(p, this); p = p.ownerCt);
918
* Find a container above this component at any level by xtype or class
919
* @param {String/Class} xtype The xtype string for a component, or the class of the component directly
920
* @return {Container} The found container
922
findParentByType: function(xtype) {
923
return typeof xtype == 'function' ?
924
this.findParentBy(function(p){
925
return p.constructor === xtype;
927
this.findParentBy(function(p){
928
return p.constructor.xtype === xtype;
932
// internal function for auto removal of assigned event handlers on destruction
933
mon : function(item, ename, fn, scope, opt){
936
this.on('beforedestroy', function(){
937
for(var i= 0, len = this.mons.length; i < len; i++){
938
var m = this.mons[i];
939
m.item.un(m.ename, m.fn, m.scope);
944
item: item, ename: ename, fn: fn, scope: scope
946
item.on(ename, fn, scope, opt);
950
Ext.reg('component', Ext.Component);