Roo/Component.js
[roojs1] / Roo / Component.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12 /**
13  * @class Roo.Component
14  * @extends Roo.util.Observable
15  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
16  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
17  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
18  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
19  * All visual components (widgets) that require rendering into a layout should subclass Component.
20  * @constructor
21  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
22  * 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
23  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
24  */
25 Roo.Component = function(config){
26     config = config || {};
27     if(config.tagName || config.dom || typeof config == "string"){ // element object
28         config = {el: config, id: config.id || config};
29     }
30     this.initialConfig = config;
31
32     Roo.apply(this, config);
33     this.addEvents({
34         /**
35          * @event disable
36          * Fires after the component is disabled.
37              * @param {Roo.Component} this
38              */
39         disable : true,
40         /**
41          * @event enable
42          * Fires after the component is enabled.
43              * @param {Roo.Component} this
44              */
45         enable : true,
46         /**
47          * @event beforeshow
48          * Fires before the component is shown.  Return false to stop the show.
49              * @param {Roo.Component} this
50              */
51         beforeshow : true,
52         /**
53          * @event show
54          * Fires after the component is shown.
55              * @param {Roo.Component} this
56              */
57         show : true,
58         /**
59          * @event beforehide
60          * Fires before the component is hidden. Return false to stop the hide.
61              * @param {Roo.Component} this
62              */
63         beforehide : true,
64         /**
65          * @event hide
66          * Fires after the component is hidden.
67              * @param {Roo.Component} this
68              */
69         hide : true,
70         /**
71          * @event beforerender
72          * Fires before the component is rendered. Return false to stop the render.
73              * @param {Roo.Component} this
74              */
75         beforerender : true,
76         /**
77          * @event render
78          * Fires after the component is rendered.
79              * @param {Roo.Component} this
80              */
81         render : true,
82         /**
83          * @event beforedestroy
84          * Fires before the component is destroyed. Return false to stop the destroy.
85              * @param {Roo.Component} this
86              */
87         beforedestroy : true,
88         /**
89          * @event destroy
90          * Fires after the component is destroyed.
91              * @param {Roo.Component} this
92              */
93         destroy : true
94     });
95     if(!this.id){
96         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
97     }
98     Roo.ComponentMgr.register(this);
99     Roo.Component.superclass.constructor.call(this);
100     this.initComponent();
101     if(this.renderTo){ // not supported by all components yet. use at your own risk!
102         this.render(this.renderTo);
103         delete this.renderTo;
104     }
105 };
106
107 /** @private */
108 Roo.Component.AUTO_ID = 1000;
109
110 Roo.extend(Roo.Component, Roo.util.Observable, {
111     /**
112      * @scope Roo.Component.prototype
113      * @type {Boolean}
114      * true if this component is hidden. Read-only.
115      */
116     hidden : false,
117     /**
118      * @type {Boolean}
119      * true if this component is disabled. Read-only.
120      */
121     disabled : false,
122     /**
123      * @type {Boolean}
124      * true if this component has been rendered. Read-only.
125      */
126     rendered : false,
127     
128     /** @cfg {String} disableClass
129      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
130      */
131     disabledClass : "x-item-disabled",
132         /** @cfg {Boolean} allowDomMove
133          * Whether the component can move the Dom node when rendering (defaults to true).
134          */
135     allowDomMove : true,
136     /** @cfg {String} hideMode (display|visibility)
137      * How this component should hidden. Supported values are
138      * "visibility" (css visibility), "offsets" (negative offset position) and
139      * "display" (css display) - defaults to "display".
140      */
141     hideMode: 'display',
142
143     /** @private */
144     ctype : "Roo.Component",
145
146     /**
147      * @cfg {String} actionMode 
148      * which property holds the element that used for  hide() / show() / disable() / enable()
149      * default is 'el' for forms you probably want to set this to fieldEl 
150      */
151     actionMode : "el",
152
153          /**
154      * @cfg {String} style
155      * css styles to add to component
156      * eg. text-align:right;
157      */
158     style : false,
159         
160     /** @private */
161     getActionEl : function(){
162         return this[this.actionMode];
163     },
164
165     initComponent : Roo.emptyFn,
166     /**
167      * If this is a lazy rendering component, render it to its container element.
168      * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
169      */
170     render : function(container, position){
171         Roo.log('render');
172         Roo.log('render ' + this.xtype);
173         Roo.log(this.rendered);
174         if(this.rendered){
175             return this;
176         }
177         
178         if(this.fireEvent("beforerender", this) === false){
179             return false;
180         }
181         
182         if(!container && this.el){
183             this.el = Roo.get(this.el);
184             container = this.el.dom.parentNode;
185             this.allowDomMove = false;
186         }
187         this.container = Roo.get(container);
188         this.rendered = true;
189         if(position !== undefined){
190             if(typeof position == 'number'){
191                 position = this.container.dom.childNodes[position];
192             }else{
193                 position = Roo.getDom(position);
194             }
195         }
196         this.onRender(this.container, position || null);
197         if(this.cls){
198             this.el.addClass(this.cls);
199             delete this.cls;
200         }
201         if(this.style){
202             this.el.applyStyles(this.style);
203             delete this.style;
204         }
205         this.fireEvent("render", this);
206         this.afterRender(this.container);
207         if(this.hidden){
208             this.hide();
209         }
210         if(this.disabled){
211             this.disable();
212         }
213
214         return this;
215         
216     },
217
218     /** @private */
219     // default function is not really useful
220     onRender : function(ct, position){
221         if(this.el){
222             this.el = Roo.get(this.el);
223             if(this.allowDomMove !== false){
224                 ct.dom.insertBefore(this.el.dom, position);
225             }
226         }
227     },
228
229     /** @private */
230     getAutoCreate : function(){
231         var cfg = typeof this.autoCreate == "object" ?
232                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
233         if(this.id && !cfg.id){
234             cfg.id = this.id;
235         }
236         return cfg;
237     },
238
239     /** @private */
240     afterRender : Roo.emptyFn,
241
242     /**
243      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
244      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
245      */
246     destroy : function(){
247         if(this.fireEvent("beforedestroy", this) !== false){
248             this.purgeListeners();
249             this.beforeDestroy();
250             if(this.rendered){
251                 this.el.removeAllListeners();
252                 this.el.remove();
253                 if(this.actionMode == "container"){
254                     this.container.remove();
255                 }
256             }
257             this.onDestroy();
258             Roo.ComponentMgr.unregister(this);
259             this.fireEvent("destroy", this);
260         }
261     },
262
263         /** @private */
264     beforeDestroy : function(){
265
266     },
267
268         /** @private */
269         onDestroy : function(){
270
271     },
272
273     /**
274      * Returns the underlying {@link Roo.Element}.
275      * @return {Roo.Element} The element
276      */
277     getEl : function(){
278         return this.el;
279     },
280
281     /**
282      * Returns the id of this component.
283      * @return {String}
284      */
285     getId : function(){
286         return this.id;
287     },
288
289     /**
290      * Try to focus this component.
291      * @param {Boolean} selectText True to also select the text in this component (if applicable)
292      * @return {Roo.Component} this
293      */
294     focus : function(selectText){
295         if(this.rendered){
296             this.el.focus();
297             if(selectText === true){
298                 this.el.dom.select();
299             }
300         }
301         return this;
302     },
303
304     /** @private */
305     blur : function(){
306         if(this.rendered){
307             this.el.blur();
308         }
309         return this;
310     },
311
312     /**
313      * Disable this component.
314      * @return {Roo.Component} this
315      */
316     disable : function(){
317         if(this.rendered){
318             this.onDisable();
319         }
320         this.disabled = true;
321         this.fireEvent("disable", this);
322         return this;
323     },
324
325         // private
326     onDisable : function(){
327         this.getActionEl().addClass(this.disabledClass);
328         this.el.dom.disabled = true;
329     },
330
331     /**
332      * Enable this component.
333      * @return {Roo.Component} this
334      */
335     enable : function(){
336         if(this.rendered){
337             this.onEnable();
338         }
339         this.disabled = false;
340         this.fireEvent("enable", this);
341         return this;
342     },
343
344         // private
345     onEnable : function(){
346         this.getActionEl().removeClass(this.disabledClass);
347         this.el.dom.disabled = false;
348     },
349
350     /**
351      * Convenience function for setting disabled/enabled by boolean.
352      * @param {Boolean} disabled
353      */
354     setDisabled : function(disabled){
355         this[disabled ? "disable" : "enable"]();
356     },
357
358     /**
359      * Show this component.
360      * @return {Roo.Component} this
361      */
362     show: function(){
363         if(this.fireEvent("beforeshow", this) !== false){
364             this.hidden = false;
365             if(this.rendered){
366                 this.onShow();
367             }
368             this.fireEvent("show", this);
369         }
370         return this;
371     },
372
373     // private
374     onShow : function(){
375         var ae = this.getActionEl();
376         if(this.hideMode == 'visibility'){
377             ae.dom.style.visibility = "visible";
378         }else if(this.hideMode == 'offsets'){
379             ae.removeClass('x-hidden');
380         }else{
381             ae.dom.style.display = "";
382         }
383     },
384
385     /**
386      * Hide this component.
387      * @return {Roo.Component} this
388      */
389     hide: function(){
390         if(this.fireEvent("beforehide", this) !== false){
391             this.hidden = true;
392             if(this.rendered){
393                 this.onHide();
394             }
395             this.fireEvent("hide", this);
396         }
397         return this;
398     },
399
400     // private
401     onHide : function(){
402         var ae = this.getActionEl();
403         if(this.hideMode == 'visibility'){
404             ae.dom.style.visibility = "hidden";
405         }else if(this.hideMode == 'offsets'){
406             ae.addClass('x-hidden');
407         }else{
408             ae.dom.style.display = "none";
409         }
410     },
411
412     /**
413      * Convenience function to hide or show this component by boolean.
414      * @param {Boolean} visible True to show, false to hide
415      * @return {Roo.Component} this
416      */
417     setVisible: function(visible){
418         if(visible) {
419             this.show();
420         }else{
421             this.hide();
422         }
423         return this;
424     },
425
426     /**
427      * Returns true if this component is visible.
428      */
429     isVisible : function(){
430         return this.getActionEl().isVisible();
431     },
432
433     cloneConfig : function(overrides){
434         overrides = overrides || {};
435         var id = overrides.id || Roo.id();
436         var cfg = Roo.applyIf(overrides, this.initialConfig);
437         cfg.id = id; // prevent dup id
438         return new this.constructor(cfg);
439     }
440 });