/**
 * @class Ext.AbstractComponent
 * <p>An abstract base class which provides shared methods for Components across the Sencha product line.</p>
 * <p>Please refer to sub class's documentation</p>
 * @constructor
 */

Ext.define('Ext.AbstractComponent', {

    /* Begin Definitions */

    mixins: {
        observable: 'Ext.util.Observable',
        animate: 'Ext.util.Animate'
    },

    requires: [
        'Ext.PluginMgr',
        'Ext.ComponentMgr',
        'Ext.core.Element',
        'Ext.core.DomHelper',
        'Ext.XTemplate',
        'Ext.ComponentQuery',
        'Ext.LoadMask',
        'Ext.ComponentLoader',
        'Ext.EventManager',
        'Ext.layout.Manager',
        'Ext.layout.component.Auto'
    ],

    // Please remember to add dependencies whenever you use it
    // I had to fix these many times already
    uses: [
        'Ext.ZIndexManager'
    ],

    statics: {
        AUTO_ID: 1000
    },

    /* End Definitions */

    isComponent: true,

    getAutoId: function() {
        return ++Ext.AbstractComponent.AUTO_ID;
    },

    /**
     * @cfg {String} id
     * <p>The <b><u>unique id of this component instance</u></b> (defaults to an {@link #getId auto-assigned id}).</p>
     * <p>It should not be necessary to use this configuration except for singleton objects in your application.
     * Components created with an id may be accessed globally using {@link Ext#getCmp Ext.getCmp}.</p>
     * <p>Instead of using assigned ids, use the {@link #itemId} config, and {@link Ext.ComponentQuery ComponentQuery} which
     * provides selector-based searching for Sencha Components analogous to DOM querying. The {@link Ext.container.Container Container}
     * class contains {@link Ext.container.Container#down shortcut methods} to query its descendant Components by selector.</p>
     * <p>Note that this id will also be used as the element id for the containing HTML element
     * that is rendered to the page for this component. This allows you to write id-based CSS
     * rules to style the specific instance of this component uniquely, and also to select
     * sub-elements using this component's id as the parent.</p>
     * <p><b>Note</b>: to avoid complications imposed by a unique <tt>id</tt> also see <code>{@link #itemId}</code>.</p>
     * <p><b>Note</b>: to access the container of a Component see <code>{@link #ownerCt}</code>.</p>
     */

    /**
     * @cfg {String} itemId
     * <p>An <tt>itemId</tt> can be used as an alternative way to get a reference to a component
     * when no object reference is available.  Instead of using an <code>{@link #id}</code> with
     * {@link Ext}.{@link Ext#getCmp getCmp}, use <code>itemId</code> with
     * {@link Ext.container.Container}.{@link Ext.container.Container#getComponent getComponent} which will retrieve
     * <code>itemId</code>'s or <tt>{@link #id}</tt>'s. Since <code>itemId</code>'s are an index to the
     * container's internal MixedCollection, the <code>itemId</code> is scoped locally to the container --
     * avoiding potential conflicts with {@link Ext.ComponentMgr} which requires a <b>unique</b>
     * <code>{@link #id}</code>.</p>
     * 
**/var c = new Ext.panel.Panel({ // {@link Ext.Component#height height}: 300, {@link #renderTo}: document.body, {@link Ext.container.Container#layout layout}: 'auto', {@link Ext.container.Container#items items}: [ { itemId: 'p1', {@link Ext.panel.Panel#title title}: 'Panel 1', {@link Ext.Component#height height}: 150 }, { itemId: 'p2', {@link Ext.panel.Panel#title title}: 'Panel 2', {@link Ext.Component#height height}: 150 } ] }) p1 = c.{@link Ext.container.Container#getComponent getComponent}('p1'); // not the same as {@link Ext#getCmp Ext.getCmp()} p2 = p1.{@link #ownerCt}.{@link Ext.container.Container#getComponent getComponent}('p2'); // reference via a sibling *
/** * <p>Also see <tt>{@link #id}</tt>, <code>{@link #query}</code>, <code>{@link #down}</code> and <code>{@link #child}</code>.</p> * <p><b>Note</b>: to access the container of an item see <tt>{@link #ownerCt}</tt>.</p> */ /** * This Component's owner {@link Ext.container.Container Container} (defaults to undefined, and is set automatically when * this Component is added to a Container). Read-only. * <p><b>Note</b>: to access items within the Container see <tt>{@link #itemId}</tt>.</p> * @type Ext.Container * @property ownerCt */ /** * @cfg {Mixed} autoEl * <p>A tag name or {@link Ext.core.DomHelper DomHelper} spec used to create the {@link #getEl Element} which will * encapsulate this Component.</p> * <p>You do not normally need to specify this. For the base classes {@link Ext.Component} and {@link Ext.container.Container}, * this defaults to <b><tt>'div'</tt></b>. The more complex Sencha classes use a more complex * DOM structure specified by their own {@link #renderTpl}s.</p> * <p>This is intended to allow the developer to create application-specific utility Components encapsulated by * different DOM elements. Example usage:</p>
**/{ xtype: 'component', autoEl: { tag: 'img', src: 'http://www.example.com/example.jpg' } }, { xtype: 'component', autoEl: { tag: 'blockquote', html: 'autoEl is cool!' } }, { xtype: 'container', autoEl: 'ul', cls: 'ux-unordered-list', items: { xtype: 'component', autoEl: 'li', html: 'First list item' } }
/** */ /** * @cfg {Mixed} renderTpl * <p>An {@link Ext.XTemplate XTemplate} used to create the internal structure inside this Component's * encapsulating {@link #getEl Element}.</p> * <p>You do not normally need to specify this. For the base classes {@link Ext.Component} * and {@link Ext.container.Container}, this defaults to <b><code>null</code></b> which means that they will be initially rendered * with no internal structure; they render their {@link #getEl Element} empty. The more specialized ExtJS and Touch classes * which use a more complex DOM structure, provide their own template definitions.</p> * <p>This is intended to allow the developer to create application-specific utility Components with customized * internal structure.</p> * <p>Upon rendering, any created child elements may be automatically imported into object properties using the * {@link #renderSelectors} option.</p> */ renderTpl: null, /** * @cfg {Object} renderSelectors An object containing properties specifying {@link Ext.DomQuery DomQuery} selectors which identify child elements created by the render process. After the Component's internal structure is rendered according to the {@link #renderTpl}, this object is iterated through, and the found Elements are added as properties to the Component using the `renderSelector` property name. For example, a Component which rendered an image, and description into its element might use the following properties coded into its prototype: renderTpl: '&lt;img src="{imageUrl}" class="x-image-component-img">&lt;div class="x-image-component-desc">{description}&gt;/div&lt;', renderSelectors: { image: 'img.x-image-component-img', descEl: 'div.x-image-component-desc' } After rendering, the Component would have a property <code>image</code> referencing its child `img` Element, and a property `descEl` referencing the `div` Element which contains the description. * @markdown */ /** * @cfg {Mixed} renderTo * <p>Specify the id of the element, a DOM element or an existing Element that this component * will be rendered into.</p><div><ul> * <li><b>Notes</b> : <ul> * <div class="sub-desc">Do <u>not</u> use this option if the Component is to be a child item of * a {@link Ext.container.Container Container}. It is the responsibility of the * {@link Ext.container.Container Container}'s {@link Ext.container.Container#layout layout manager} * to render and manage its child items.</div> * <div class="sub-desc">When using this config, a call to render() is not required.</div> * </ul></li> * </ul></div> * <p>See <code>{@link #render}</code> also.</p> */ /** * @cfg {Boolean} frame * <p>Specify as <code>true</code> to have the Component inject framing elements within the Component at render time to * provide a graphical rounded frame around the Component content.</p> * <p>This is only necessary when running on outdated, or non standard-compliant browsers such as Microsoft's Internet Explorer * prior to version 9 which do not support rounded corners natively.</p> * <p>The extra space taken up by this framing is available from the read only property {@link #frameSize}.</p> */ /** * <p>Read-only property indicating the width of any framing elements which were added within the encapsulating element * to provide graphical, rounded borders. See the {@link #frame} config.</p> * <p> This is an object containing the frame width in pixels for all four sides of the Component containing * the following properties:</p><div class="mdetail-params"><ul> * <li><code>top</code> The width of the top framing element in pixels.</li> * <li><code>right</code> The width of the right framing element in pixels.</li> * <li><code>bottom</code> The width of the bottom framing element in pixels.</li> * <li><code>left</code> The width of the left framing element in pixels.</li> * </ul></div> * @property frameSize * @type {Object} */ /** * @cfg {String/Object} componentLayout * <p>The sizing and positioning of a Component's internal Elements is the responsibility of * the Component's layout manager which sizes a Component's internal structure in response to the Component being sized.</p> * <p>Generally, developers will not use this configuration as all provided Components which need their internal * elements sizing (Such as {@link Ext.form.Field input fields}) come with their own componentLayout managers.</p> * <p>The {@link Ext.layout.container.Auto default layout manager} will be used on instances of the base Ext.Component class * which simply sizes the Component's encapsulating element to the height and width specified in the {@link #setSize} method.</p> */ /** * @cfg {Mixed} tpl * An <bold>{@link Ext.Template}</bold>, <bold>{@link Ext.XTemplate}</bold> * or an array of strings to form an Ext.XTemplate. * Used in conjunction with the <code>{@link #data}</code> and * <code>{@link #tplWriteMode}</code> configurations. */ /** * @cfg {Mixed} data * The initial set of data to apply to the <code>{@link #tpl}</code> to * update the content area of the Component. */ /** * @cfg {String} tplWriteMode The Ext.(X)Template method to use when * updating the content area of the Component. Defaults to <code>'overwrite'</code> * (see <code>{@link Ext.XTemplate#overwrite}</code>). */ tplWriteMode: 'overwrite', /** * @cfg {String} baseCls * The base CSS class to apply to this components's element. This will also be prepended to * elements within this component like Panel's body will get a class x-panel-body. This means * that if you create a subclass of Panel, and you want it to get all the Panels styling for the * element and the body, you leave the baseCls x-panel and use componentCls to add specific styling for this * component. */ baseCls: Ext.baseCSSPrefix + 'component', /** * @cfg {String} componentCls * CSS Class to be added to a components root level element to give distinction to it * via styling. */ /** * @cfg {String} cls * An optional extra CSS class that will be added to this component's Element (defaults to ''). This can be * useful for adding customized styles to the component or any of its children using standard CSS rules. */ /** * @cfg {String} overCls * An optional extra CSS class that will be added to this component's Element when the mouse moves * over the Element, and removed when the mouse moves out. (defaults to ''). This can be * useful for adding customized 'active' or 'hover' styles to the component or any of its children using standard CSS rules. */ /** * @cfg {String} disabledCls * CSS class to add when the Component is disabled. Defaults to 'x-item-disabled'. */ disabledCls: Ext.baseCSSPrefix + 'item-disabled', /** * @cfg {String} ui * A set of predefined ui styles for individual components. * * Most components support 'light' and 'dark'. * * Extra string added to the baseCls with an extra '-'. *
**/ new Ext.panel.Panel({ title: 'Some Title', baseCls: 'x-component' ui: 'green' });
/** * <p>The ui configuration in this example would add 'x-component-green' as an additional class.</p> */ /** * @cfg {String} style * A custom style specification to be applied to this component's Element. Should be a valid argument to * {@link Ext.core.Element#applyStyles}. *
**/ new Ext.panel.Panel({ title: 'Some Title', renderTo: Ext.getBody(), width: 400, height: 300, layout: 'form', items: [{ xtype: 'textarea', style: { width: '95%', marginBottom: '10px' } }, new Ext.button.Button({ text: 'Send', minWidth: '100', style: { marginBottom: '10px' } }) ] });
/** */ /** * @cfg {Number} width * The width of this component in pixels. */ /** * @cfg {Number} height * The height of this component in pixels. */ /** * @cfg {Number/String} border * Specifies the border for this component. The border can be a single numeric value to apply to all sides or * it can be a CSS style specification for each style, for example: '10 5 3 10'. */ /** * @cfg {Number/String} padding * Specifies the padding for this component. The padding can be a single numeric value to apply to all sides or * it can be a CSS style specification for each style, for example: '10 5 3 10'. */ /** * @cfg {Number/String} margin * Specifies the margin for this component. The margin can be a single numeric value to apply to all sides or * it can be a CSS style specification for each style, for example: '10 5 3 10'. */ /** * @cfg {Boolean} hidden * Defaults to false. */ hidden: false, /** * @cfg {Boolean} disabled * Defaults to false. */ disabled: false, /** * @cfg {Boolean} draggable * Allows the component to be dragged via the touch event. */ /** * Read-only property indicating whether or not the component can be dragged * @property draggable * @type {Boolean} */ draggable: false, /** * @cfg {Boolean} floating * Create the Component as a floating and use absolute positioning. * Defaults to false. */ floating: false, /** * @cfg {String} hideMode * A String which specifies how this Component's encapsulating DOM element will be hidden. * Values may be<div class="mdetail-params"><ul> * <li><code>'display'</code> : The Component will be hidden using the <code>display: none</code> style.</li> * <li><code>'visibility'</code> : The Component will be hidden using the <code>visibility: hidden</code> style.</li> * <li><code>'offsets'</code> : The Component will be hidden by absolutely positioning it out of the visible area of the document. This * is useful when a hidden Component must maintain measurable dimensions. Hiding using <code>display</code> results * in a Component having zero dimensions.</li></ul></div> * Defaults to <code>'display'</code>. */ hideMode: 'display', /** * @cfg {String} contentEl * <p>Optional. Specify an existing HTML element, or the <code>id</code> of an existing HTML element to use as the content * for this component.</p> * <ul> * <li><b>Description</b> : * <div class="sub-desc">This config option is used to take an existing HTML element and place it in the layout element * of a new component (it simply moves the specified DOM element <i>after the Component is rendered</i> to use as the content.</div></li> * <li><b>Notes</b> : * <div class="sub-desc">The specified HTML element is appended to the layout element of the component <i>after any configured * {@link #html HTML} has been inserted</i>, and so the document will not contain this element at the time the {@link #render} event is fired.</div> * <div class="sub-desc">The specified HTML element used will not participate in any <code><b>{@link Ext.container.Container#layout layout}</b></code> * scheme that the Component may use. It is just HTML. Layouts operate on child <code><b>{@link Ext.container.Container#items items}</b></code>.</div> * <div class="sub-desc">Add either the <code>x-hidden</code> or the <code>x-hide-display</code> CSS class to * prevent a brief flicker of the content before it is rendered to the panel.</div></li> * </ul> */ /** * @cfg {String/Object} html * An HTML fragment, or a {@link Ext.core.DomHelper DomHelper} specification to use as the layout element * content (defaults to ''). The HTML content is added after the component is rendered, * so the document will not contain this HTML at the time the {@link #render} event is fired. * This content is inserted into the body <i>before</i> any configured {@link #contentEl} is appended. */ /** * @cfg {String} styleHtmlContent * True to automatically style the html inside the content target of this component (body for panels). * Defaults to false. */ styleHtmlContent: false, /** * @cfg {String} styleHtmlCls * The class that is added to the content target when you set styleHtmlContent to true. * Defaults to 'x-html' */ styleHtmlCls: Ext.baseCSSPrefix + 'html', /** * @cfg {Number} minHeight * <p>The minimum value in pixels which this Component will set its height to.</p> * <p><b>Warning:</b> This will override any size management applied by layout managers.</p> */ /** * @cfg {Number} minWidth * <p>The minimum value in pixels which this Component will set its width to.</p> * <p><b>Warning:</b> This will override any size management applied by layout managers.</p> */ /** * @cfg {Number} maxHeight * <p>The maximum value in pixels which this Component will set its height to.</p> * <p><b>Warning:</b> This will override any size management applied by layout managers.</p> */ /** * @cfg {Number} maxWidth * <p>The maximum value in pixels which this Component will set its width to.</p> * <p><b>Warning:</b> This will override any size management applied by layout managers.</p> */ /** * @cfg {Ext.ComponentLoader/Object} loader * A configuration object or an instance of a {@link Ext.ComponentLoader} to load remote * content for this Component. */ // @private allowDomMove: true, autoShow: false, /** * @cfg {Mixed} autoRender * <p>This config is intended mainly for {@link #floating} Components which may or may not be shown. Instead * of using {@link #renderTo} in the configuration, and rendering upon construction, this allows a Component * to render itself upon first <i>{@link #show}</i>.</p> * <p>Specify as <code>true</code> to have this Component render to the document body upon first show.</p> * <p>Specify as an element, or the ID of an element to have this Component render to a specific element upon first show.</p> * <p><b>This defaults to <code>true</code> for the {@link Ext.window.Window Window} class.</b></p> */ autoRender: false, needsLayout: false, /** * @cfg {Object/Array} plugins * An object or array of objects that will provide custom functionality for this component. The only * requirement for a valid plugin is that it contain an init method that accepts a reference of type Ext.Component. * When a component is created, if any plugins are available, the component will call the init method on each * plugin, passing a reference to itself. Each plugin can then call methods or respond to events on the * component as needed to provide its functionality. */ /** * Read-only property indicating whether or not the component has been rendered. * @property rendered * @type {Boolean} */ rendered: false, constructor : function(config) { var me = this, i, len; config = config || {}; me.initialConfig = config; Ext.apply(me, config); me.addEvents( /** * @event beforeactivate * Fires before a Component has been visually activated. * Returning false from an event listener can prevent the activate * from occurring. * @param {Ext.Component} this */ 'beforeactivate', /** * @event activate * Fires after a Component has been visually activated. * @param {Ext.Component} this */ 'activate', /** * @event beforedeactivate * Fires before a Component has been visually deactivated. * Returning false from an event listener can prevent the deactivate * from occurring. * @param {Ext.Component} this */ 'beforedeactivate', /** * @event deactivate * Fires after a Component has been visually deactivated. * @param {Ext.Component} this */ 'deactivate', /** * @event added * Fires after a Component had been added to a Container. * @param {Ext.Component} this * @param {Ext.container.Container} container Parent Container * @param {Number} pos position of Component */ 'added', /** * @event disable * Fires after the component is disabled. * @param {Ext.Component} this */ 'disable', /** * @event enable * Fires after the component is enabled. * @param {Ext.Component} this */ 'enable', /** * @event beforeshow * Fires before the component is shown when calling the {@link #show} method. * Return false from an event handler to stop the show. * @param {Ext.Component} this */ 'beforeshow', /** * @event show * Fires after the component is shown when calling the {@link #show} method. * @param {Ext.Component} this */ 'show', /** * @event beforehide * Fires before the component is hidden when calling the {@link #hide} method. * Return false from an event handler to stop the hide. * @param {Ext.Component} this */ 'beforehide', /** * @event hide * Fires after the component is hidden. * Fires after the component is hidden when calling the {@link #hide} method. * @param {Ext.Component} this */ 'hide', /** * @event removed * Fires when a component is removed from an Ext.container.Container * @param {Ext.Component} this * @param {Ext.container.Container} ownerCt Container which holds the component */ 'removed', /** * @event beforerender * Fires before the component is {@link #rendered}. Return false from an * event handler to stop the {@link #render}. * @param {Ext.Component} this */ 'beforerender', /** * @event render * Fires after the component markup is {@link #rendered}. * @param {Ext.Component} this */ 'render', /** * @event afterrender * <p>Fires after the component rendering is finished.</p> * <p>The afterrender event is fired after this Component has been {@link #rendered}, been postprocesed * by any afterRender method defined for the Component, and, if {@link #stateful}, after state * has been restored.</p> * @param {Ext.Component} this */ 'afterrender', /** * @event beforedestroy * Fires before the component is {@link #destroy}ed. Return false from an event handler to stop the {@link #destroy}. * @param {Ext.Component} this */ 'beforedestroy', /** * @event destroy * Fires after the component is {@link #destroy}ed. * @param {Ext.Component} this */ 'destroy', /** * @event resize * Fires after the component is resized. * @param {Ext.Component} this * @param {Number} adjWidth The box-adjusted width that was set * @param {Number} adjHeight The box-adjusted height that was set */ 'resize', /** * @event move * Fires after the component is moved. * @param {Ext.Component} this * @param {Number} x The new x position * @param {Number} y The new y position */ 'move', 'beforestaterestore', 'staterestore', 'beforestatesave', 'statesave' ); me.getId(); me.mons = []; me.additionalCls = []; me.renderData = me.renderData || {}; me.renderSelectors = me.renderSelectors || {}; if (me.plugins) { me.plugins = [].concat(me.plugins); for (i = 0, len = me.plugins.length; i < len; i++) { me.plugins[i] = me.constructPlugin(me.plugins[i]); } } me.initComponent(); // ititComponent gets a chance to change the id property before registering Ext.ComponentMgr.register(me); // Dont pass the config so that it is not applied to 'this' again me.mixins.observable.constructor.call(me); // Move this into Observable? if (me.plugins) { me.plugins = [].concat(me.plugins); for (i = 0, len = me.plugins.length; i < len; i++) { me.plugins[i] = me.initPlugin(me.plugins[i]); } } me.loader = me.getLoader(); // This won't work in Touch if (me.applyTo) { me.applyToMarkup(me.applyTo); delete me.applyTo; } else if (me.renderTo) { me.render(me.renderTo); } //<debug> if (Ext.isDefined(me.disabledClass)) { throw "Component: disabledClass has been deprecated. Please use disabledCls."; } //</debug> }, initComponent: Ext.emptyFn, applyToMarkup: Ext.emptyFn, show: Ext.emptyFn, animate: function(animObj) { var me = this, to; animObj = animObj || {}; to = animObj.to || {}; if (Ext.fx.Manager.hasFxBlock(me.id)) { return me; } // Special processing for animating Component dimensions. if (!animObj.dynamic && (to.height || to.width)) { var curWidth = me.getWidth(), w = curWidth, curHeight = me.getHeight(), h = curHeight, needsResize = false; if (to.height && to.height > curHeight) { h = to.height; needsResize = true; } if (to.width && to.width > curWidth) { w = to.width; needsResize = true; } // If any dimensions are being increased, we must resize the internal structure // of the Component, but then clip it by sizing its encapsulating element back to original dimensions. // The animation will then progressively reveal the larger content. if (needsResize) { var clearWidth = !Ext.isNumber(me.width), clearHeight = !Ext.isNumber(me.height); me.componentLayout.childrenChanged = true; me.setSize(w, h, me.ownerCt); me.el.setSize(curWidth, curHeight); if (clearWidth) { delete me.width; } if (clearHeight) { delete me.height; } } } return me.mixins.animate.animate.apply(me, arguments); }, /** * <p>This method finds the topmost active layout who's processing will eventually determine the size and position of this * Component.<p> * <p>This method is useful when dynamically adding Components into Containers, and some processing must take place after the * final sizing and positioning of the Component has been performed.</p> * @returns */ findLayoutController: function() { return this.findParentBy(function(c) { // Return true if we are at the root of the Container tree // or this Container's layout is busy but the next one up is not. return !c.ownerCt || (c.layout.layoutBusy && !c.ownerCt.layout.layoutBusy); }); }, onShow : function() { // Layout if needed var needsLayout = this.needsLayout; if (Ext.isObject(needsLayout)) { this.doComponentLayout(needsLayout.width, needsLayout.height, needsLayout.isSetSize, needsLayout.ownerCt); } }, constructPlugin: function(plugin) { if (plugin.ptype && typeof plugin.init != 'function') { plugin.cmp = this; plugin = Ext.PluginMgr.create(plugin); } else if (typeof plugin == 'string') { plugin = Ext.PluginMgr.create({ ptype: plugin, cmp: this }); } return plugin; }, // @private initPlugin : function(plugin) { plugin.init(this); return plugin; }, /** * Handles autoRender. * Floating Components may have an ownerCt. If they are asking to be constrained, constrain them within that * ownerCt, and have their z-index managed locally. Floating Components are always rendered to document.body */ doAutoRender: function() { var me = this; if (me.floating) { me.render(document.body); } else { me.render(Ext.isBoolean(me.autoRender) ? Ext.getBody() : me.autoRender); } }, /** * @private * <p>Finds the ancestor Container responsible for allocating zIndexes for the passed Component.</p> * <p>That will be the outermost floating Container (a Container which has no ownerCt and has floating:true).</p> * <p>If we have no ancestors, or we walk all the way up to the document body, there's no zIndexParent, * and the global Ext.WindowMgr will be used.</p> */ getZIndexParent: function() { var p = this.ownerCt, c; if (p) { while (p) { c = p; p = p.ownerCt; } if (c.floating) { return c; } } }, // @private render : function(container, position) { var me = this; if (!me.rendered && me.fireEvent('beforerender', me) !== false) { // If this.el is defined, we want to make sure we are dealing with // an Ext Element. if (me.el) { me.el = Ext.get(me.el); } // Floaters must register with a ZIndexManager at render time when the ownerCt chain is complete if (me.floating) { me.zIndexParent = me.getZIndexParent(); me.floatParent = me.ownerCt; delete me.ownerCt; // If a floating Component is configured to be constrained, but has no configured // constrainTo setting, set its constrainTo to be it's ownerCt before rendering. if ((me.constrain || me.constrainHeader) && !me.constrainTo) { me.constrainTo = me.floatParent ? me.floatParent.getTargetEl() : Ext.getBody(); } if (me.zIndexParent) { me.zIndexParent.registerFloatingItem(me); } else { Ext.WindowMgr.register(me); } } container = me.initContainer(container); me.onRender(container, position); // Tell the encapsulating element to hide itself in the way the Component is configured to hide // This means DISPLAY, VISIBILITY or OFFSETS. me.el.setVisibilityMode(Ext.core.Element[me.hideMode.toUpperCase()]); if(me.overCls){ me.el.addClsOnOver(me.overCls); } me.fireEvent('render', me); me.initContent(); me.afterRender(container); me.fireEvent('afterrender', me); me.initEvents(); if (me.autoShow) { me.show(); } if (me.hidden) { // call this so we don't fire initial hide events. me.onHide(false); // no animation after render } if (me.disabled) { // pass silent so the event doesn't fire the first time. me.disable(true); } } return me; }, // @private onRender : function(container, position) { var me = this, el = me.el, cls = me.initCls(), styles = me.initStyles(), renderTpl, renderData; position = me.getInsertPosition(position); if (!el) { if (position) { el = Ext.core.DomHelper.insertBefore(position, me.getElConfig(), true); } else { el = Ext.core.DomHelper.append(container, me.getElConfig(), true); } } else if (me.allowDomMove !== false) { if (position) { container.dom.insertBefore(el.dom, position); } else { container.dom.appendChild(el.dom); } } if (Ext.scopeResetCSS && !me.ownerCt) { // If this component's el is the body element, we add the reset class to the html tag if (el.dom == Ext.getBody().dom) { el.parent().addCls(Ext.baseCSSPrefix + 'reset'); } else { // Else we wrap this element in an element that adds the reset class. me.resetEl = el.wrap({ cls: Ext.baseCSSPrefix + 'reset' }); } } el.addCls(cls); el.setStyle(styles); // Here we check if the component has a height set through style or css. // If it does then we set the this.height to that value and it won't be // considered an auto height component // if (this.height === undefined) { // var height = el.getHeight(); // // This hopefully means that the panel has an explicit height set in style or css // if (height - el.getPadding('tb') - el.getBorderWidth('tb') > 0) { // this.height = height; // } // } me.el = el; if (!Ext.supports.CSS3BorderRadius) { me.initFrame(cls, styles); } renderTpl = me.initRenderTpl(); if (renderTpl) { renderData = me.initRenderData(); renderTpl.append(me.getTargetEl(), renderData); } me.applyRenderSelectors(); me.rendered = true; }, // @private afterRender : function() { var me = this, pos, xy; me.getComponentLayout(); // Set the size if a size is configured, or if this is the outermost Container if (!me.ownerCt || (me.height || me.width)) { me.setSize(me.width, me.height); } // For floaters, calculate x and y if they aren't defined by aligning // the sized element to the center of either the the container or the ownerCt if (me.floating && (me.x === undefined || me.y === undefined)) { if (me.floatParent) { xy = me.el.getAlignToXY(me.floatParent.getTargetEl(), 'c-c'); pos = me.floatParent.getTargetEl().translatePoints(xy[0], xy[1]); } else { xy = me.el.getAlignToXY(me.container, 'c-c'); pos = me.el.translatePoints(xy[0], xy[1]); } me.x = me.x === undefined ? pos.left: me.x; me.y = me.y === undefined ? pos.top: me.y; } if (Ext.isDefined(me.x) || Ext.isDefined(me.y)) { me.setPosition(me.x, me.y); } if (me.styleHtmlContent) { me.getTargetEl().addCls(me.styleHtmlCls); } }, frameCls: Ext.baseCSSPrefix + 'frame', frameTpl: [ '<tpl if="top">', '<tpl if="left"><div class="{frameCls}-tl {baseCls}-tl" style="background-position: 0 -{tl}px; padding-left: {frameWidth}px" role="presentation"></tpl>', '<tpl if="right"><div class="{frameCls}-tr {baseCls}-tr" style="background-position: right -{tr}px; padding-right: {frameWidth}px" role="presentation"></tpl>', '<div class="{frameCls}-tc {baseCls}-tc" style="background-position: 0 0; height: {frameWidth}px" role="presentation"></div>', '<tpl if="right"></div></tpl>', '<tpl if="left"></div></tpl>', '</tpl>', '<tpl if="left"><div class="{frameCls}-ml {baseCls}-ml" style="background-position: 0 0; padding-left: {frameWidth}px" role="presentation"></tpl>', '<tpl if="right"><div class="{frameCls}-mr {baseCls}-mr" style="background-position: right 0; padding-right: {frameWidth}px" role="presentation"></tpl>', '<div class="{frameCls}-mc {baseCls}-mc" role="presentation"></div>', '<tpl if="right"></div></tpl>', '<tpl if="left"></div></tpl>', '<tpl if="bottom">', '<tpl if="left"><div class="{frameCls}-bl {baseCls}-bl" style="background-position: 0 -{bl}px; padding-left: {frameWidth}px" role="presentation"></tpl>', '<tpl if="right"><div class="{frameCls}-br {baseCls}-br" style="background-position: right -{br}px; padding-right: {frameWidth}px" role="presentation"></tpl>', '<div class="{frameCls}-bc {baseCls}-bc" style="background-position: 0 -{frameWidth}px; height: {frameWidth}px" role="presentation"></div>', '<tpl if="right"></div></tpl>', '<tpl if="left"></div></tpl>', '</tpl>' ], frameTableTpl: [ '<table><tbody>', '<tpl if="top">', '<tr>', '<tpl if="left"><td class="{frameCls}-tl {baseCls}-tl" style="background-position: 0 -{tl}px; width: {frameWidth}px" role="presentation"></td></tpl>', '<td class="{frameCls}-tc {baseCls}-tc" style="background-position: 0 0; height: {frameWidth}px" role="presentation"></td>', '<tpl if="right"><td class="{frameCls}-tr {baseCls}-tr" style="background-position: right -{tr}px; width: {frameWidth}px" role="presentation"></td></tpl>', '</tr>', '</tpl>', '<tr>', '<tpl if="left"><td class="{frameCls}-ml {baseCls}-ml" style="background-position: 0 -{ml}px; width: {frameWidth}px" role="presentation"></td></tpl>', '<td class="{frameCls}-mc {baseCls}-mc" style="background-position: 0 0;" role="presentation"></td>', '<tpl if="right"><td class="{frameCls}-mr {baseCls}-mr" style="background-position: right 0; width: {frameWidth}px" role="presentation"></td></tpl>', '</tr>', '<tpl if="bottom">', '<tr>', '<tpl if="left"><td class="{frameCls}-bl {baseCls}-bl" style="background-position: 0 -{bl}px; width: {frameWidth}px" role="presentation"></td></tpl>', '<td class="{frameCls}-bc {baseCls}-bc" style="background-position: 0 -{frameWidth}px; height: {frameWidth}px" role="presentation"></td>', '<tpl if="right"><td class="{frameCls}-br {baseCls}-br" style="background-position: right -{br}px; width: {frameWidth}px" role="presentation"></td></tpl>', '</tr>', '</tpl>', '</tbody></table>' ], initFrame : function(cls, styles) { var me = this, frameBaseCls = me.baseCls + (me.ui ? '-' + me.ui : ''), left = me.el.getStyle('background-position-x'), top = me.el.getStyle('background-position-y'), frameWidth = 0, frameSize, frameTpl, info, max; // Some browsers dont support background-position-x and y, so for those // browsers let's split background-position into two parts. if (!left && !top) { info = me.el.getStyle('background-position').split(' '); left = info[0]; top = info[1]; } // We actually pass a string in the form of '[type][tl][tr]px [type][br][bl]px' as // the background position of this.el from the css to indicate to IE that this component needs // framing. We parse it here and change the markup accordingly. if (parseInt(left, 10) >= 1000000 && parseInt(top, 10) >= 1000000) { // Table markup starts with 110, div markup with 100. frameTpl = me.getFrameTpl(left.substr(0, 3) == '110'); // Get and parse the different border radius sizes max = Math.max; frameSize = { top: max(left.substr(3, 2), left.substr(5, 2)), right: max(left.substr(5, 2), top.substr(3, 2)), bottom: max(top.substr(3, 2), top.substr(5, 2)), left: max(top.substr(5, 2), left.substr(3, 2)) }; frameWidth = max(frameSize.top, frameSize.right, frameSize.bottom, frameSize.left); // Just to be sure we set the background image of the el to none. me.el.setStyle('background-image', 'none'); } // This happens when you set frame: true explicitly without using the x-frame mixin in sass. // This way IE can't figure out what sizes to use and thus framing can't work. if (me.frame === true && !frameSize) { //<debug error> throw new Error("[" + Ext.getClassName(me) + "#initFrame] You have set frame: true explicity on this component " + "while it doesnt have any framing in sass. This way IE can't figure out what sizes to use and thus framing " + "on this component will be disabled"); //</debug> } me.frame = me.frame || !!frameWidth; me.frameSize = frameSize || false; if (me.frame) { //<debug error> if (!frameSize) { throw new Error("[" + Ext.getClassName(me) + "#initFrame] Unable to read background-image style " + "(got '" + info + "') of element: " + me.el.dom.outerHTML + " to handle framing."); } //</debug> // Here we render the frameTpl to this component. This inserts the 9point div or the table framing. frameTpl.append(me.el, { frameCls: me.frameCls, baseCls: frameBaseCls, frameWidth: frameWidth, top: !!frameSize.top, left: !!frameSize.left, right: !!frameSize.right, bottom: !!frameSize.bottom, tl: (frameWidth * 2), tr: (frameWidth * 3), bl: (frameWidth * 4), br: (frameWidth * 5) }); // The frameBody is returned in getTargetEl, so that layouts render items to the correct target. me.frameBody = me.el.down('.' + frameBaseCls + '-mc'); } }, getFrameTpl : function(table) { var frameTpl = table ? this.frameTableTpl : this.frameTpl; if (Ext.isArray(frameTpl) || typeof frameTpl === "string") { frameTpl = new Ext.XTemplate(frameTpl); } return frameTpl; }, /** * <p>Creates an array of class names from the configurations to add to this Component's <code>el</code> on render.</p> * <p>Private, but (possibly) used by ComponentQuery for selection by class name if Component is not rendered.</p> * @return {Array} An array of class names with which the Component's element will be rendered. * @private */ initCls: function() { var me = this, cls = []; cls.push(me.baseCls); //<deprecated since=0.99> if (Ext.isDefined(me.cmpCls)) { throw "Ext.Component: cmpCls renamed to componentCls"; } //</deprecated> if (me.componentCls) { cls.push(me.componentCls); } else { me.componentCls = me.baseCls; } if (me.cls) { cls.push(me.cls); delete me.cls; } if (me.ui) { cls.push(me.componentCls + '-' + me.ui); } if (me.frame) { cls.push('x-framed ' + me.baseCls + '-' + (me.ui ? me.ui + '-' : '') + 'framed'); } return cls.concat(me.additionalCls); }, getElConfig : function() { var result = this.autoEl || {tag: 'div'}; result.id = this.id; return result; }, /** * This function takes the position argument passed to onRender and returns a * DOM element that you can use in the insertBefore. * @param {String/Number/Element/HTMLElement} position Index, element id or element you want * to put this component before. * @return {HTMLElement} DOM element that you can use in the insertBefore */ getInsertPosition: function(position) { // Convert the position to an element to insert before if (position !== undefined) { if (Ext.isNumber(position)) { position = this.container.dom.childNodes[position]; } else { position = Ext.getDom(position); } } return position; }, /** * Adds ctCls to container. * @return {Ext.core.Element} The initialized container * @private */ initContainer: function(container) { var me = this; // If you render a component specifying the el, we get the container // of the el, and make sure we dont move the el around in the dom // during the render if (!container && me.el) { container = me.el.dom.parentNode; me.allowDomMove = false; } me.container = Ext.get(container); if (me.ctCls) { me.container.addCls(me.ctCls); } return me.container; }, /** * Initialized the renderData to be used when rendering the renderTpl. * @return {Object} Object with keys and values that are going to be applied to the renderTpl * @private */ initRenderData: function() { var me = this; return Ext.applyIf(me.renderData, { ui: me.ui, baseCls: me.baseCls, componentCls: me.componentCls, frame: me.frame }); }, /** * Initializes the renderTpl. * @return {Ext.XTemplate} The renderTpl XTemplate instance. * @private */ initRenderTpl: function() { var renderTpl = this.renderTpl, prototype = Ext.AbstractComponent.prototype; if (renderTpl) { if (prototype.renderTpl !== renderTpl) { if (Ext.isArray(renderTpl) || typeof renderTpl === "string") { renderTpl = new Ext.XTemplate(renderTpl); } } else if (Ext.isArray(prototype.renderTpl)){ renderTpl = prototype.renderTpl = new Ext.XTemplate(renderTpl); } } return renderTpl; }, /** * Function description * @return {String} A CSS style string with style, padding, margin and border. * @private */ initStyles: function() { var style = {}, me = this, Element = Ext.core.Element, i, ln, split, prop; if (Ext.isString(me.style)) { style = Element.parseStyles(me.style); } else { style = Ext.apply({}, me.style); } // Convert the padding, margin and border properties from a space seperated string // into a proper style string if (me.padding != undefined) { style.padding = Element.unitizeBox((me.padding === true) ? 5 : me.padding); } if (me.margin != undefined) { style.margin = Element.unitizeBox((me.margin === true) ? 5 : me.margin); } if (me.border != undefined) { style.borderWidth = Element.unitizeBox((me.border === true) ? 1 : me.border); } delete me.style; return style; }, /** * Initializes this components contents. It checks for the properties * html, contentEl and tpl/data. * @private */ initContent: function() { var me = this, target = me.getTargetEl(), contentEl, pre; if (me.html) { target.update(Ext.core.DomHelper.markup(me.html)); delete me.html; } if (me.contentEl) { contentEl = Ext.get(me.contentEl); pre = Ext.baseCSSPrefix; contentEl.removeCls([pre + 'hidden', pre + 'hide-display', pre + 'hide-offsets', pre + 'hide-nosize']); target.appendChild(contentEl.dom); } if (me.tpl) { // Make sure this.tpl is an instantiated XTemplate if (!me.tpl.isTemplate) { me.tpl = new Ext.XTemplate(me.tpl); } if (me.data) { me.tpl[me.tplWriteMode](target, me.data); delete me.data; } } }, // @private initEvents : function() { var me = this, afterRenderEvents = me.afterRenderEvents, property, listeners; if (afterRenderEvents) { for (property in afterRenderEvents) { if (!afterRenderEvents.hasOwnProperty(property)) { continue; } listeners = afterRenderEvents[property]; if (me[property] && me[property].on) { me.mon(me[property], listeners); } } } }, /** * Sets references to elements inside the component. E.g body -> x-panel-body * @private */ applyRenderSelectors: function() { var selectors = this.renderSelectors || {}, el = this.el.dom, selector; for (selector in selectors) { if (!selectors.hasOwnProperty(selector) || !selectors[selector]) { continue; } this[selector] = Ext.get(Ext.DomQuery.selectNode(selectors[selector], el)); } }, is: function(selector) { return Ext.ComponentQuery.is(this, selector); }, /** * <p>Walks up the <code>ownerCt</code> axis looking for an ancestor Container which matches * the passed simple selector.</p> * <p>Example:
**/var owningTabContainer = grid.up('tabcontainer');
/** * @param {String} selector Optional. The simple selector to test. * @return {Ext.container.Container} The matching ancestor Container (or <code>undefined</code> if no match was found). */ up: function(selector) { var result = this.ownerCt; if (selector) { for (; result; result = result.ownerCt) { if (Ext.ComponentQuery.is(result, selector)) { return result; } } } return result; }, /** * <p>Returns the next sibling of this Component.</p> * <p>Optionally selects the next sibling which matches the passed {@link Ext.ComponentQuery ComponentQuery} selector.</p> * <p>May also be refered to as <code><b>prev()</b></code></p> * @param selector Optional. A {@link Ext.ComponentQuery ComponentQuery} selector to filter the following items. * @returns The next sibling (or the next sibling which matches the selector). Returns null if there is no matching sibling. */ nextSibling: function(selector) { var o = this.ownerCt, it, last, idx, c; if (o) { it = o.items; idx = it.indexOf(this) + 1; if (idx) { if (selector) { for (last = it.getCount(); idx < last; idx++) { if ((c = it.getAt(idx)).is(selector)) { return c; } } } else { if (idx < it.getCount()) { return it.getAt(idx); } } } } return null; }, /** * <p>Returns the previous sibling of this Component.</p> * <p>Optionally selects the previous sibling which matches the passed {@link Ext.ComponentQuery ComponentQuery} selector.</p> * <p>May also be refered to as <code><b>prev()</b></code></p> * @param selector Optional. A {@link Ext.ComponentQuery ComponentQuery} selector to filter the preceding items. * @returns The previous sibling (or the previous sibling which matches the selector). Returns null if there is no matching sibling. */ previousSibling: function(selector) { var o = this.ownerCt, it, idx, c; if (o) { it = o.items; idx = it.indexOf(this); if (idx != -1) { if (selector) { for (--idx; idx >= 0; idx--) { if ((c = it.getAt(idx)).is(selector)) { return c; } } } else { if (idx) { return it.getAt(--idx); } } } } return null; }, /** * Retrieves the id of this component. * Will autogenerate an id if one has not already been set. */ getId : function() { return this.id || (this.id = 'ext-comp-' + (this.getAutoId())); }, getItemId : function() { return this.itemId || this.id; }, /** * Retrieves the top level element representing this component. */ getEl : function() { return this.el; }, /** * This is used to determine where to insert the 'html', 'contentEl' and 'items' in this component. * @private */ getTargetEl: function() { return this.frameBody || this.el; }, /** * <p>Tests whether or not this Component is of a specific xtype. This can test whether this Component is descended * from the xtype (default) or whether it is directly of the xtype specified (shallow = true).</p> * <p><b>If using your own subclasses, be aware that a Component must register its own xtype * to participate in determination of inherited xtypes.</b></p> * <p>For a list of all available xtypes, see the {@link Ext.Component} header.</p> * <p>Example usage:</p> *
**/var t = new Ext.form.Text(); var isText = t.isXType('textfield'); // true var isBoxSubclass = t.isXType('field'); // true, descended from Ext.form.Field var isBoxInstance = t.isXType('field', true); // false, not a direct Ext.form.Field instance
/** * @param {String} xtype The xtype to check for this Component * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is * the default), or true to check whether this Component is directly of the specified xtype. * @return {Boolean} True if this component descends from the specified xtype, false otherwise. */ isXType: function(xtype, shallow) { //assume a string by default if (Ext.isFunction(xtype)) { xtype = xtype.xtype; //handle being passed the class, e.g. Ext.Component } else if (Ext.isObject(xtype)) { xtype = xtype.statics().xtype; //handle being passed an instance } return !shallow ? ('/' + this.getXTypes() + '/').indexOf('/' + xtype + '/') != -1: this.self.xtype == xtype; }, /** * <p>Returns this Component's xtype hierarchy as a slash-delimited string. For a list of all * available xtypes, see the {@link Ext.Component} header.</p> * <p><b>If using your own subclasses, be aware that a Component must register its own xtype * to participate in determination of inherited xtypes.</b></p> * <p>Example usage:</p> *
**/var t = new Ext.form.Text(); alert(t.getXTypes()); // alerts 'component/field/textfield'
/** * @return {String} The xtype hierarchy string */ getXTypes: function() { var self = this.self, xtypes = [], parentPrototype = this, xtype; if (!self.xtypes) { while (parentPrototype && Ext.getClass(parentPrototype)) { xtype = Ext.getClass(parentPrototype).xtype; if (xtype !== undefined) { xtypes.unshift(xtype); } parentPrototype = parentPrototype.superclass; } self.xtypeChain = xtypes; self.xtypes = xtypes.join('/'); } return self.xtypes; }, /** * Update the content area of a component. * @param {Mixed} htmlOrData * If this component has been configured with a template via the tpl config * then it will use this argument as data to populate the template. * If this component was not configured with a template, the components * content area will be updated via Ext.core.Element update * @param {Boolean} loadScripts * (optional) Only legitimate when using the html configuration. Defaults to false * @param {Function} callback * (optional) Only legitimate when using the html configuration. Callback to execute when scripts have finished loading */ update : function(htmlOrData, loadScripts, cb) { var me = this; if (me.tpl && !Ext.isString(htmlOrData)) { me.data = htmlOrData; if (me.rendered) { me.tpl[me.tplWriteMode](me.getTargetEl(), htmlOrData || {}); } } else { me.html = Ext.isObject(htmlOrData) ? Ext.core.DomHelper.markup(htmlOrData) : htmlOrData; if (me.rendered) { me.getTargetEl().update(me.html, loadScripts, cb); } } if (me.rendered) { me.doComponentLayout(); } }, /** * 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) { return this[visible ? 'show': 'hide'](); }, /** * Returns true if this component is visible. * @param {Boolean} deep. <p>Optional. Pass <code>true</code> to interrogate the visibility status of all * parent Containers to determine whether this Component is truly visible to the user.</p> * <p>Generally, to determine whether a Component is hidden, the no argument form is needed. For example * when creating dynamically laid out UIs in a hidden Container before showing them.</p> * @return {Boolean} True if this component is visible, false otherwise. */ isVisible: function(deep) { var me = this, child = me, visible = !me.hidden, ancestor = me.ownerCt; // Clear hiddenOwnerCt property me.hiddenAncestor = false; if (me.destroyed) { return false; } if (deep && visible && me.rendered && ancestor) { while (ancestor) { // If any ancestor is hidden, then this is hidden. // If an ancestor Panel (only Panels have a collapse method) is collapsed, // then its layoutTarget (body) is hidden, so this is hidden unless its within a // docked item; they are still visible when collapsed (Unless they themseves are hidden) if (ancestor.hidden || (ancestor.collapsed && !(ancestor.getDockedItems && Ext.Array.contains(ancestor.getDockedItems(), child)))) { // Store hiddenOwnerCt property if needed me.hiddenAncestor = ancestor; visible = false; break; } child = ancestor; ancestor = ancestor.ownerCt; } } return visible; }, /** * Enable the component * @param {Boolean} silent * Passing false will supress the 'enable' event from being fired. */ enable : function(silent) { var me = this; if (me.rendered) { me.el.removeCls(me.disabledCls); me.el.dom.disabled = false; me.onEnable(); } me.disabled = false; if (silent !== true) { me.fireEvent('enable', me); } return me; }, /** * Disable the component. * @param {Boolean} silent * Passing true, will supress the 'disable' event from being fired. */ disable : function(silent) { var me = this; if (me.rendered) { me.el.addCls(me.disabledCls); me.el.dom.disabled = true; me.onDisable(); } me.disabled = true; if (silent !== true) { me.fireEvent('disable', me); } return me; }, /** * Method to determine whether this Component is currently disabled. * @return {Boolean} the disabled state of this Component. */ isDisabled : function() { return this.disabled; }, /** * Enable or disable the component. * @param {Boolean} disabled */ setDisabled : function(disabled) { return this[disabled ? 'disable': 'enable'](); }, /** * Method to determine whether this Component is currently set to hidden. * @return {Boolean} the hidden state of this Component. */ isHidden : function() { return this.hidden; }, /** * Adds a CSS class to the top level element representing this component. * @returns {Ext.Component} Returns the Component to allow method chaining. */ addCls : function() { var me = this, args = Ext.Array.toArray(arguments); if (me.rendered) { me.el.addCls(args); } else { me.additionalCls = Ext.Array.unique(me.additionalCls.concat(args)); } return me; }, //<debug> addClass : function() { throw "Component: addClass has been deprecated. Please use addCls."; }, //</debug> /** * Removes a CSS class from the top level element representing this component. * @returns {Ext.Component} Returns the Component to allow method chaining. */ removeCls : function() { var me = this, args = Ext.Array.toArray(arguments); if (me.rendered) { me.el.removeCls(args); } else if (me.additionalCls.length) { Ext.each(args, function(cls) { Ext.Array.remove(me.additionalCls, cls); }); } return me; }, //<debug> removeClass : function() { throw "Component: removeClass has been deprecated. Please use removeCls."; }, //</debug> addListener : function(element, listeners, scope, options) { var me = this, fn, option; if (Ext.isString(element) && (Ext.isObject(listeners) || options && options.element)) { if (options.element) { fn = listeners; listeners = {}; listeners[element] = fn; element = options.element; if (scope) { listeners.scope = scope; } for (option in options) { if (!options.hasOwnProperty(option)) { continue; } if (me.eventOptionsRe.test(option)) { listeners[option] = options[option]; } } } // At this point we have a variable called element, // and a listeners object that can be passed to on if (me[element] && me[element].on) { me.mon(me[element], listeners); } else { me.afterRenderEvents = me.afterRenderEvents || {}; me.afterRenderEvents[element] = listeners; } } return me.mixins.observable.addListener.apply(me, arguments); }, // @TODO: implement removelistener to support the dom event stuff /** * Provides the link for Observable's fireEvent method to bubble up the ownership hierarchy. * @return {Ext.container.Container} the Container which owns this Component. */ getBubbleTarget : function() { return this.ownerCt; }, /** * Method to determine whether this Component is floating. * @return {Boolean} the floating state of this component. */ isFloating : function() { return this.floating; }, /** * Method to determine whether this Component is draggable. * @return {Boolean} the draggable state of this component. */ isDraggable : function() { return !!this.draggable; }, /** * Method to determine whether this Component is droppable. * @return {Boolean} the droppable state of this component. */ isDroppable : function() { return !!this.droppable; }, /** * @private * Method to manage awareness of when components are added to their * respective Container, firing an added event. * References are established at add time rather than at render time. * @param {Ext.container.Container} container Container which holds the component * @param {number} pos Position at which the component was added */ onAdded : function(container, pos) { this.ownerCt = container; this.fireEvent('added', this, container, pos); }, /** * @private * Method to manage awareness of when components are removed from their * respective Container, firing an removed event. References are properly * cleaned up after removing a component from its owning container. */ onRemoved : function() { var me = this; me.fireEvent('removed', me, me.ownerCt); delete me.ownerCt; }, // @private onEnable : Ext.emptyFn, // @private onDisable : Ext.emptyFn, // @private beforeDestroy : Ext.emptyFn, // @private // @private onResize : Ext.emptyFn, /** * Sets the width and height of this Component. This method fires the {@link #resize} event. This method can accept * either width and height as separate arguments, or you can pass a size object like <code>{width:10, height:20}</code>. * @param {Mixed} width The new width to set. This may be one of:<div class="mdetail-params"><ul> * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.core.Element#defaultUnit}s (by default, pixels).</li> * <li>A String used to set the CSS width style.</li> * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li> * <li><code>undefined</code> to leave the width unchanged.</li> * </ul></div> * @param {Mixed} height The new height to set (not required if a size object is passed as the first arg). * This may be one of:<div class="mdetail-params"><ul> * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.core.Element#defaultUnit}s (by default, pixels).</li> * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li> * <li><code>undefined</code> to leave the height unchanged.</li> * </ul></div> * @return {Ext.Component} this */ setSize : function(width, height) { var me = this, layoutCollection; // support for standard size objects if (Ext.isObject(width)) { height = width.height; width = width.width; } // Constrain within configured maxima if (Ext.isNumber(width)) { width = Ext.Number.constrain(width, me.minWidth, me.maxWidth); } if (Ext.isNumber(height)) { height = Ext.Number.constrain(height, me.minHeight, me.maxHeight); } if (!me.rendered || !me.isVisible()) { // If an ownerCt is hidden, add my reference onto the layoutOnShow stack. Set the needsLayout flag. if (me.hiddenAncestor) { layoutCollection = me.hiddenAncestor.layoutOnShow; layoutCollection.remove(me); layoutCollection.add(me); } me.needsLayout = { width: width, height: height, isSetSize: true }; if (!me.rendered) { me.width = (width !== undefined) ? width : me.width; me.height = (height !== undefined) ? height : me.height; } return me; } me.doComponentLayout(width, height, true); return me; }, setCalculatedSize : function(width, height, ownerCt) { var me = this, layoutCollection; // support for standard size objects if (Ext.isObject(width)) { ownerCt = width.ownerCt; height = width.height; width = width.width; } // Constrain within configured maxima if (Ext.isNumber(width)) { width = Ext.Number.constrain(width, me.minWidth, me.maxWidth); } if (Ext.isNumber(height)) { height = Ext.Number.constrain(height, me.minHeight, me.maxHeight); } if (!me.rendered || !me.isVisible()) { // If an ownerCt is hidden, add my reference onto the layoutOnShow stack. Set the needsLayout flag. if (me.hiddenAncestor) { layoutCollection = me.hiddenAncestor.layoutOnShow; layoutCollection.remove(me); layoutCollection.add(me); } me.needsLayout = { width: width, height: height, isSetSize: false, ownerCt: ownerCt }; return me; } me.doComponentLayout(width, height, false, ownerCt); return me; }, /** * This method needs to be called whenever you change something on this component that requires the Component's * layout to be recalculated. * @return {Ext.container.Container} this */ doComponentLayout : function(width, height, isSetSize, ownerCt) { var me = this, componentLayout = me.getComponentLayout(); // collapsed state is not relevant here, so no testing done. // Only Panels have a collapse method, and that just sets the width/height such that only // a single docked Header parallel to the collapseTo side are visible, and the Panel body is hidden. if (me.rendered && componentLayout) { width = (width !== undefined) ? width : me.width; height = (height !== undefined) ? height : me.height; if (isSetSize) { me.width = width; me.height = height; } componentLayout.layout(width, height, isSetSize, ownerCt); } return me; }, // @private setComponentLayout : function(layout) { var currentLayout = this.componentLayout; if (currentLayout && currentLayout.isLayout && currentLayout != layout) { currentLayout.setOwner(null); } this.componentLayout = layout; layout.setOwner(this); }, getComponentLayout : function() { var me = this; if (!me.componentLayout || !me.componentLayout.isLayout) { me.setComponentLayout(Ext.layout.Manager.create(me.componentLayout, 'autocomponent')); } return me.componentLayout; }, /** * @param {Ext.Component} this * @param {Number} adjWidth The box-adjusted width that was set * @param {Number} adjHeight The box-adjusted height that was set */ afterComponentLayout: function(width, height) { this.fireEvent('resize', this, width, height); }, /** * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}. * This method fires the {@link #move} event. * @param {Number} left The new left * @param {Number} top The new top * @return {Ext.Component} this */ setPosition : function(x, y) { var me = this; if (Ext.isObject(x)) { y = x.y; x = x.x; } if (!me.rendered) { return me; } if (x !== undefined || y !== undefined) { me.el.setBox(x, y); me.onPosition(x, y); me.fireEvent('move', me, x, y); } return me; }, /* @private * Called after the component is moved, this method is empty by default but can be implemented by any * subclass that needs to perform custom logic after a move occurs. * @param {Number} x The new x position * @param {Number} y The new y position */ onPosition: Ext.emptyFn, /** * Sets the width of the component. This method fires the {@link #resize} event. * @param {Number} width The new width to setThis may be one of:<div class="mdetail-params"><ul> * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.core.Element#defaultUnit}s (by default, pixels).</li> * <li>A String used to set the CSS width style.</li> * </ul></div> * @return {Ext.Component} this */ setWidth : function(width) { return this.setSize(width); }, /** * Sets the height of the component. This method fires the {@link #resize} event. * @param {Number} height The new height to set. This may be one of:<div class="mdetail-params"><ul> * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.core.Element#defaultUnit}s (by default, pixels).</li> * <li>A String used to set the CSS height style.</li> * <li><i>undefined</i> to leave the height unchanged.</li> * </ul></div> * @return {Ext.Component} this */ setHeight : function(height) { return this.setSize(undefined, height); }, /** * Gets the current size of the component's underlying element. * @return {Object} An object containing the element's size {width: (element width), height: (element height)} */ getSize : function() { return this.el.getSize(); }, /** * Gets the current width of the component's underlying element. * @return {Number} */ getWidth : function() { return this.el.getWidth(); }, /** * Gets the current height of the component's underlying element. * @return {Number} */ getHeight : function() { return this.el.getHeight(); }, /** * Gets the {@link Ext.ComponentLoader} for this Component. * @return {Ext.ComponentLoader} The loader instance, null if it doesn't exist. */ getLoader: function(){ var me = this, autoLoad = me.autoLoad ? (Ext.isObject(me.autoLoad) ? me.autoLoad : {url: me.autoLoad}) : null, loader = me.loader || autoLoad; if (loader) { if (!loader.isLoader) { me.loader = Ext.create('Ext.ComponentLoader', Ext.apply({ target: me, autoLoad: autoLoad }, loader)); } else { loader.setTarget(me); } return me.loader; } return null; }, /** * This method allows you to show or hide a LoadMask on top of this component. * @param {Boolean/Object} load True to show the default LoadMask or a config object * that will be passed to the LoadMask constructor. False to hide the current LoadMask. * @param {Boolean} targetEl True to mask the targetEl of this Component instead of the this.el. * For example, setting this to true on a Panel will cause only the body to be masked. (defaults to false) * @return {Ext.LoadMask} The LoadMask instance that has just been shown. */ setLoading : function(load, targetEl) { var me = this; if (me.rendered) { if (load !== false) { me.loadMask = me.loadMask || new Ext.LoadMask(targetEl ? me.getTargetEl() : me.el, Ext.applyIf(Ext.isObject(load) ? load : {})); me.loadMask.show(); } else { Ext.destroy(me.loadMask); me.loadMask = null; } } return me.loadMask; }, /** * Sets the dock position of this component in its parent panel. Note that * this only has effect if this item is part of the dockedItems collection * of a parent that has a DockLayout (note that any Panel has a DockLayout * by default) * @return {Component} this */ setDocked : function(dock, layoutParent) { var me = this; me.dock = dock; if (layoutParent && me.ownerCt && me.rendered) { me.ownerCt.doComponentLayout(); } return me; }, onDestroy : function() { var me = this; if (me.monitorResize && Ext.EventManager.resizeEvent) { Ext.EventManager.resizeEvent.removeListener(me.setSize, me); } Ext.destroy(me.componentLayout, me.loadMask); }, /** * Destroys the Component. */ destroy : function() { var me = this; if (!me.isDestroyed) { if (me.fireEvent('beforedestroy', me) !== false) { me.destroying = true; me.beforeDestroy(); if (me.ownerCt && me.ownerCt.remove) { me.ownerCt.remove(me, false); } if (me.rendered) { me.el.remove(); } me.onDestroy(); Ext.ComponentMgr.unregister(me); me.fireEvent('destroy', me); me.clearListeners(); me.destroying = false; me.isDestroyed = true; } } }, /** * Retrieves a plugin by its pluginId which has been bound to this * component. * @returns {Ext.AbstractPlugin} pluginInstance */ getPlugin: function(pluginId) { var i = 0, plugins = this.plugins, ln = plugins.length; for (; i < ln; i++) { if (plugins[i].pluginId === pluginId) { return plugins[i]; } } } }, function() { this.createAlias({ on: 'addListener', prev: 'previousSibling', next: 'nextSibling' }); }); ￿