# Component.js

    /**
     * @class Ext.ComponentMgr
     * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Ext.getCmp}).
     * @singleton
     */
    Ext.ComponentMgr = function(){
        var all = new Ext.util.MixedCollection();

        return {
            /**
             * Registers a component.
             * @param {Ext.Component} c The component
             */
            register : function(c){
                all.add(c);
            },

            /**
             * Unregisters a component.
             * @param {Ext.Component} c The component
             */
            unregister : function(c){
                all.remove(c);
            },

            /**
             * Returns a component by id
             * @param {String} id The component id
             */
            get : function(id){
                return all.get(id);
            },

            /**
             * Registers a function that will be called when a specified component is added to ComponentMgr
             * @param {String} id The component id
             * @param {Funtction} fn The callback function
             * @param {Object} scope The scope of the callback
             */
            onAvailable : function(id, fn, scope){
                all.on("add", function(index, o){
                    if(o.id == id){
                        fn.call(scope || o, o);
                        all.un("add", fn, scope);
                    }
                });
            }
        };
    }();

    /**
     * @class Ext.Component
     * @extends Ext.util.Observable
     * Base class for all major Ext components.  All subclasses of Component can automatically participate in the standard
     * Ext component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
     * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Ext.Container} and
     * to be automatically registered with the {@link Ext.ComponentMgr} so that it can be referenced at any time via {@link Ext.getCmp}.
     * All visual components (widgets) that require rendering into a layout should subclass Component.
     * @constructor
     * @param {Ext.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
     * 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
     * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
     */
    Ext.Component = function(config){
        config = config || {};
        if(config.tagName || config.dom || typeof config == "string"){ // element object
            config = {el: config, id: config.id || config};
        }
        this.initialConfig = config;

        Ext.apply(this, config);
        this.addEvents({
            /**
             * @event disable
             * Fires after the component is disabled.
    	     * @param {Ext.Component} this
    	     */
            disable : true,
            /**
             * @event enable
             * Fires after the component is enabled.
    	     * @param {Ext.Component} this
    	     */
            enable : true,
            /**
             * @event beforeshow
             * Fires before the component is shown.  Return false to stop the show.
    	     * @param {Ext.Component} this
    	     */
            beforeshow : true,
            /**
             * @event show
             * Fires after the component is shown.
    	     * @param {Ext.Component} this
    	     */
            show : true,
            /**
             * @event beforehide
             * Fires before the component is hidden. Return false to stop the hide.
    	     * @param {Ext.Component} this
    	     */
            beforehide : true,
            /**
             * @event hide
             * Fires after the component is hidden.
    	     * @param {Ext.Component} this
    	     */
            hide : true,
            /**
             * @event beforerender
             * Fires before the component is rendered. Return false to stop the render.
    	     * @param {Ext.Component} this
    	     */
            beforerender : true,
            /**
             * @event render
             * Fires after the component is rendered.
    	     * @param {Ext.Component} this
    	     */
            render : true,
            /**
             * @event beforedestroy
             * Fires before the component is destroyed. Return false to stop the destroy.
    	     * @param {Ext.Component} this
    	     */
            beforedestroy : true,
            /**
             * @event destroy
             * Fires after the component is destroyed.
    	     * @param {Ext.Component} this
    	     */
            destroy : true
        });
        if(!this.id){
            this.id = "ext-comp-" + (++Ext.Component.AUTO_ID);
        }
        Ext.ComponentMgr.register(this);
        Ext.Component.superclass.constructor.call(this);
        this.initComponent();
        if(this.renderTo){ // not supported by all components yet. use at your own risk!
            this.render(this.renderTo);
            delete this.renderTo;
        }
    };

    // private
    Ext.Component.AUTO_ID = 1000;

    Ext.extend(Ext.Component, Ext.util.Observable, {
        /**
         * true if this component is hidden. Read-only.
         */
        hidden : false,
        /**
         * true if this component is disabled. Read-only.
         */
        disabled : false,
        /**
         * true if this component has been rendered. Read-only.
         */
        rendered : false,

        /** @cfg {String} disableClass
         * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
         */
        disabledClass : "x-item-disabled",
    	/** @cfg {Boolean} allowDomMove
    	 * Whether the component can move the Dom node when rendering (defaults to true).
    	 */
        allowDomMove : true,
        /** @cfg {String} hideMode
         * How this component should hidden. Supported values are
         * "visibility" (css visibility), "offsets" (negative offset position) and
         * "display" (css display) - defaults to "display".
         */
        hideMode: 'display',

        // private
        ctype : "Ext.Component",

        // private
        actionMode : "el",

        // private
        getActionEl : function(){
            return this[this.actionMode];
        },

        initComponent : Ext.emptyFn,
        /**
         * If this is a lazy rendering component, render it to its container element.
         * @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.
         */
        render : function(container, position){
            if(!this.rendered && this.fireEvent("beforerender", this) !== false){
                if(!container && this.el){
                    this.el = Ext.get(this.el);
                    container = this.el.dom.parentNode;
                    this.allowDomMove = false;
                }
                this.container = Ext.get(container);
                this.rendered = true;
                if(position !== undefined){
                    if(typeof position == 'number'){
                        position = this.container.dom.childNodes[position];
                    }else{
                        position = Ext.getDom(position);
                    }
                }
                this.onRender(this.container, position || null);
                if(this.cls){
                    this.el.addClass(this.cls);
                    delete this.cls;
                }
                if(this.style){
                    this.el.applyStyles(this.style);
                    delete this.style;
                }
                this.fireEvent("render", this);
                this.afterRender(this.container);
                if(this.hidden){
                    this.hide();
                }
                if(this.disabled){
                    this.disable();
                }
            }
            return this;
        },

        // private
        // default function is not really useful
        onRender : function(ct, position){
            if(this.el){
                this.el = Ext.get(this.el);
                if(this.allowDomMove !== false){
                    ct.dom.insertBefore(this.el.dom, position);
                }
            }
        },

        // private
        getAutoCreate : function(){
            var cfg = typeof this.autoCreate == "object" ?
                          this.autoCreate : Ext.apply({}, this.defaultAutoCreate);
            if(this.id && !cfg.id){
                cfg.id = this.id;
            }
            return cfg;
        },

        // private
        afterRender : Ext.emptyFn,

        /**
         * Destroys this component by purging any event listeners, removing the component's element from the DOM,
         * removing the component from its {@link Ext.Container} (if applicable) and unregistering it from {@link Ext.ComponentMgr}.
         */
        destroy : function(){
            if(this.fireEvent("beforedestroy", this) !== false){
                this.purgeListeners();
                this.beforeDestroy();
                if(this.rendered){
                    this.el.removeAllListeners();
                    this.el.remove();
                    if(this.actionMode == "container"){
                        this.container.remove();
                    }
                }
                this.onDestroy();
                Ext.ComponentMgr.unregister(this);
                this.fireEvent("destroy", this);
            }
        },

    	// private
        beforeDestroy : function(){

        },

    	// private
    	onDestroy : function(){

        },

        /**
         * Returns the underlying {@link Ext.Element}.
         * @return {Ext.Element} The element
         */
        getEl : function(){
            return this.el;
        },

        /**
         * Returns the id of this component.
         * @return {String}
         */
        getId : function(){
            return this.id;
        },

        /**
         * Try to focus this component.
         * @param {Boolean} selectText True to also select the text in this component (if applicable)
         * @return {Ext.Component} this
         */
        focus : function(selectText){
            if(this.rendered){
                this.el.focus();
                if(selectText === true){
                    this.el.dom.select();
                }
            }
            return this;
        },

        // private
        blur : function(){
            if(this.rendered){
                this.el.blur();
            }
            return this;
        },

        /**
         * Disable this component.
         * @return {Ext.Component} this
         */
        disable : function(){
            if(this.rendered){
                this.onDisable();
            }
            this.disabled = true;
            this.fireEvent("disable", this);
            return this;
        },

    	// private
        onDisable : function(){
            this.getActionEl().addClass(this.disabledClass);
            this.el.dom.disabled = true;
        },

        /**
         * Enable this component.
         * @return {Ext.Component} this
         */
        enable : function(){
            if(this.rendered){
                this.onEnable();
            }
            this.disabled = false;
            this.fireEvent("enable", this);
            return this;
        },

    	// private
        onEnable : function(){
            this.getActionEl().removeClass(this.disabledClass);
            this.el.dom.disabled = false;
        },

        /**
         * Convenience function for setting disabled/enabled by boolean.
         * @param {Boolean} disabled
         */
        setDisabled : function(disabled){
            this[disabled ? "disable" : "enable"]();
        },

        /**
         * Show this component.
         * @return {Ext.Component} this
         */
        show: function(){
            if(this.fireEvent("beforeshow", this) !== false){
                this.hidden = false;
                if(this.rendered){
                    this.onShow();
                }
                this.fireEvent("show", this);
            }
            return this;
        },

        // private
        onShow : function(){
            var ae = this.getActionEl();
            if(this.hideMode == 'visibility'){
                ae.dom.style.visibility = "visible";
            }else if(this.hideMode == 'offsets'){
                ae.removeClass('x-hidden');
            }else{
                ae.dom.style.display = "";
            }
        },

        /**
         * Hide this component.
         * @return {Ext.Component} this
         */
        hide: function(){
            if(this.fireEvent("beforehide", this) !== false){
                this.hidden = true;
                if(this.rendered){
                    this.onHide();
                }
                this.fireEvent("hide", this);
            }
            return this;
        },

        // private
        onHide : function(){
            var ae = this.getActionEl();
            if(this.hideMode == 'visibility'){
                ae.dom.style.visibility = "hidden";
            }else if(this.hideMode == 'offsets'){
                ae.addClass('x-hidden');
            }else{
                ae.dom.style.display = "none";
            }
        },

        /**
         * Convenience function to hide or show this component by boolean.
         * @param {Boolean} visible True to show, false to hide
         * @return {Ext.Component} this
         */
        setVisible: function(visible){
            if(visible) {
                this.show();
            }else{
                this.hide();
            }
            return this;
        },

        /**
         * Returns true if this component is visible.
         */
        isVisible : function(){
            return this.getActionEl().isVisible();
        },

        cloneConfig : function(overrides){
            overrides = overrides || {};
            var id = overrides.id || Ext.id();
            var cfg = Ext.applyIf(overrides, this.initialConfig);
            cfg.id = id; // prevent dup id
            return new this.constructor(cfg);
        }
    });

Ext - Copyright © 2006-2007 Ext JS, LLC
All rights reserved.