initial import
[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 Ext components.  All subclasses of Component can automatically participate in the standard
16  * Ext 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 = "ext-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      * @property {Boolean} hidden
113      * true if this component is hidden. Read-only.
114      */
115     hidden : false,
116     /**
117      * true if this component is disabled. Read-only.
118      */
119     disabled : false,
120     /**
121      * true if this component has been rendered. Read-only.
122      */
123     rendered : false,
124     
125     /** @cfg {String} disableClass
126      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
127      */
128     disabledClass : "x-item-disabled",
129         /** @cfg {Boolean} allowDomMove
130          * Whether the component can move the Dom node when rendering (defaults to true).
131          */
132     allowDomMove : true,
133     /** @cfg {String} hideMode
134      * How this component should hidden. Supported values are
135      * "visibility" (css visibility), "offsets" (negative offset position) and
136      * "display" (css display) - defaults to "display".
137      */
138     hideMode: 'display',
139
140     // private
141     ctype : "Roo.Component",
142
143     /** @cfg {String} actionMode 
144      * which property holds the element that used for  hide() / show() / disable() / enable()
145      * default is 'el' 
146      */
147     actionMode : "el",
148
149     // private
150     getActionEl : function(){
151         return this[this.actionMode];
152     },
153
154     initComponent : Roo.emptyFn,
155     /**
156      * If this is a lazy rendering component, render it to its container element.
157      * @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.
158      */
159     render : function(container, position){
160         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
161             if(!container && this.el){
162                 this.el = Roo.get(this.el);
163                 container = this.el.dom.parentNode;
164                 this.allowDomMove = false;
165             }
166             this.container = Roo.get(container);
167             this.rendered = true;
168             if(position !== undefined){
169                 if(typeof position == 'number'){
170                     position = this.container.dom.childNodes[position];
171                 }else{
172                     position = Roo.getDom(position);
173                 }
174             }
175             this.onRender(this.container, position || null);
176             if(this.cls){
177                 this.el.addClass(this.cls);
178                 delete this.cls;
179             }
180             if(this.style){
181                 this.el.applyStyles(this.style);
182                 delete this.style;
183             }
184             this.fireEvent("render", this);
185             this.afterRender(this.container);
186             if(this.hidden){
187                 this.hide();
188             }
189             if(this.disabled){
190                 this.disable();
191             }
192         }
193         return this;
194     },
195
196     // private
197     // default function is not really useful
198     onRender : function(ct, position){
199         if(this.el){
200             this.el = Roo.get(this.el);
201             if(this.allowDomMove !== false){
202                 ct.dom.insertBefore(this.el.dom, position);
203             }
204         }
205     },
206
207     // private
208     getAutoCreate : function(){
209         var cfg = typeof this.autoCreate == "object" ?
210                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
211         if(this.id && !cfg.id){
212             cfg.id = this.id;
213         }
214         return cfg;
215     },
216
217     // private
218     afterRender : Roo.emptyFn,
219
220     /**
221      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
222      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
223      */
224     destroy : function(){
225         if(this.fireEvent("beforedestroy", this) !== false){
226             this.purgeListeners();
227             this.beforeDestroy();
228             if(this.rendered){
229                 this.el.removeAllListeners();
230                 this.el.remove();
231                 if(this.actionMode == "container"){
232                     this.container.remove();
233                 }
234             }
235             this.onDestroy();
236             Roo.ComponentMgr.unregister(this);
237             this.fireEvent("destroy", this);
238         }
239     },
240
241         // private
242     beforeDestroy : function(){
243
244     },
245
246         // private
247         onDestroy : function(){
248
249     },
250
251     /**
252      * Returns the underlying {@link Roo.Element}.
253      * @return {Roo.Element} The element
254      */
255     getEl : function(){
256         return this.el;
257     },
258
259     /**
260      * Returns the id of this component.
261      * @return {String}
262      */
263     getId : function(){
264         return this.id;
265     },
266
267     /**
268      * Try to focus this component.
269      * @param {Boolean} selectText True to also select the text in this component (if applicable)
270      * @return {Roo.Component} this
271      */
272     focus : function(selectText){
273         if(this.rendered){
274             this.el.focus();
275             if(selectText === true){
276                 this.el.dom.select();
277             }
278         }
279         return this;
280     },
281
282     // private
283     blur : function(){
284         if(this.rendered){
285             this.el.blur();
286         }
287         return this;
288     },
289
290     /**
291      * Disable this component.
292      * @return {Roo.Component} this
293      */
294     disable : function(){
295         if(this.rendered){
296             this.onDisable();
297         }
298         this.disabled = true;
299         this.fireEvent("disable", this);
300         return this;
301     },
302
303         // private
304     onDisable : function(){
305         this.getActionEl().addClass(this.disabledClass);
306         this.el.dom.disabled = true;
307     },
308
309     /**
310      * Enable this component.
311      * @return {Roo.Component} this
312      */
313     enable : function(){
314         if(this.rendered){
315             this.onEnable();
316         }
317         this.disabled = false;
318         this.fireEvent("enable", this);
319         return this;
320     },
321
322         // private
323     onEnable : function(){
324         this.getActionEl().removeClass(this.disabledClass);
325         this.el.dom.disabled = false;
326     },
327
328     /**
329      * Convenience function for setting disabled/enabled by boolean.
330      * @param {Boolean} disabled
331      */
332     setDisabled : function(disabled){
333         this[disabled ? "disable" : "enable"]();
334     },
335
336     /**
337      * Show this component.
338      * @return {Roo.Component} this
339      */
340     show: function(){
341         if(this.fireEvent("beforeshow", this) !== false){
342             this.hidden = false;
343             if(this.rendered){
344                 this.onShow();
345             }
346             this.fireEvent("show", this);
347         }
348         return this;
349     },
350
351     // private
352     onShow : function(){
353         var ae = this.getActionEl();
354         if(this.hideMode == 'visibility'){
355             ae.dom.style.visibility = "visible";
356         }else if(this.hideMode == 'offsets'){
357             ae.removeClass('x-hidden');
358         }else{
359             ae.dom.style.display = "";
360         }
361     },
362
363     /**
364      * Hide this component.
365      * @return {Roo.Component} this
366      */
367     hide: function(){
368         if(this.fireEvent("beforehide", this) !== false){
369             this.hidden = true;
370             if(this.rendered){
371                 this.onHide();
372             }
373             this.fireEvent("hide", this);
374         }
375         return this;
376     },
377
378     // private
379     onHide : function(){
380         var ae = this.getActionEl();
381         if(this.hideMode == 'visibility'){
382             ae.dom.style.visibility = "hidden";
383         }else if(this.hideMode == 'offsets'){
384             ae.addClass('x-hidden');
385         }else{
386             ae.dom.style.display = "none";
387         }
388     },
389
390     /**
391      * Convenience function to hide or show this component by boolean.
392      * @param {Boolean} visible True to show, false to hide
393      * @return {Roo.Component} this
394      */
395     setVisible: function(visible){
396         if(visible) {
397             this.show();
398         }else{
399             this.hide();
400         }
401         return this;
402     },
403
404     /**
405      * Returns true if this component is visible.
406      */
407     isVisible : function(){
408         return this.getActionEl().isVisible();
409     },
410
411     cloneConfig : function(overrides){
412         overrides = overrides || {};
413         var id = overrides.id || Roo.id();
414         var cfg = Roo.applyIf(overrides, this.initialConfig);
415         cfg.id = id; // prevent dup id
416         return new this.constructor(cfg);
417     }
418 });