/** * An abstract base class which provides shared methods for Components across the Sencha product line. * * Please refer to sub class's documentation * @private */ Ext.define('Ext.AbstractComponent', { /* Begin Definitions */ requires: [ 'Ext.ComponentQuery', 'Ext.ComponentManager', 'Ext.util.ProtoElement' ], mixins: { observable: 'Ext.util.Observable', animate: 'Ext.util.Animate', elementCt: 'Ext.util.ElementContainer', renderable: 'Ext.util.Renderable', state: 'Ext.state.Stateful' }, // The "uses" property specifies class which are used in an instantiated AbstractComponent. // They do *not* have to be loaded before this class may be defined - that is what "requires" is for. uses: [ 'Ext.PluginManager', 'Ext.Element', 'Ext.DomHelper', 'Ext.XTemplate', 'Ext.ComponentQuery', 'Ext.ComponentLoader', 'Ext.EventManager', 'Ext.layout.Context', 'Ext.layout.Layout', 'Ext.layout.component.Auto', 'Ext.LoadMask', 'Ext.ZIndexManager' ], statics: { AUTO_ID: 1000, pendingLayouts: null, layoutSuspendCount: 0, cancelLayout: function(comp) { var context = this.runningLayoutContext || this.pendingLayouts; if (context) { context.cancelComponent(comp); } }, flushLayouts: function () { var me = this, context = me.pendingLayouts; if (context && context.invalidQueue.length) { me.pendingLayouts = null; me.runningLayoutContext = context; Ext.override(context, { runComplete: function () { // we need to release the layout queue before running any of the // finishedLayout calls because they call afterComponentLayout // which can re-enter by calling doLayout/doComponentLayout. me.runningLayoutContext = null; return this.callParent(); // not "me" here! } }); context.run(); } }, resumeLayouts: function (flush) { if (this.layoutSuspendCount && ! --this.layoutSuspendCount) { if (flush) { this.flushLayouts(); } } }, suspendLayouts: function () { ++this.layoutSuspendCount; }, updateLayout: function (comp, defer) { var me = this, running = me.runningLayoutContext, pending; if (running) { running.queueInvalidate(comp); } else { pending = me.pendingLayouts || (me.pendingLayouts = new Ext.layout.Context()); pending.queueInvalidate(comp); if (!defer && !me.layoutSuspendCount && !comp.isLayoutSuspended()) { me.flushLayouts(); } } } }, /* End Definitions */ /** * @property {Boolean} isComponent * `true` in this class to identify an object as an instantiated Component, or subclass thereof. */ isComponent: true, /** * @private */ getAutoId: function() { this.autoGenId = true; return ++Ext.AbstractComponent.AUTO_ID; }, deferLayouts: false, /** * @cfg {String} id * The **unique id of this component instance.** * * 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}. * * 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. * * 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. * * **Note**: to avoid complications imposed by a unique id also see `{@link #itemId}`. * * **Note**: to access the container of a Component see `{@link #ownerCt}`. * * Defaults to an {@link #getId auto-assigned id}. */ /** * @property {Boolean} autoGenId * `true` indicates an id was auto-generated rather than provided by configuration. * @private */ autoGenId: false, /** * @cfg {String} itemId * An itemId can be used as an alternative way to get a reference to a component when no object reference is * available. Instead of using an `{@link #id}` with {@link Ext}.{@link Ext#getCmp getCmp}, use `itemId` with * {@link Ext.container.Container}.{@link Ext.container.Container#getComponent getComponent} which will retrieve * `itemId`'s or {@link #id}'s. Since `itemId`'s are an index to the container's internal MixedCollection, the * `itemId` is scoped locally to the container -- avoiding potential conflicts with {@link Ext.ComponentManager} * which requires a **unique** `{@link #id}`. * * 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#cfg-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 * * Also see {@link #id}, `{@link Ext.container.Container#query}`, `{@link Ext.container.Container#down}` and * `{@link Ext.container.Container#child}`. * * **Note**: to access the container of an item see {@link #ownerCt}. */ /** * @property {Ext.Container} ownerCt * This Component's owner {@link Ext.container.Container Container} (is set automatically * when this Component is added to a Container). * * **Note**: to access items within the Container see {@link #itemId}. * @readonly */ /** * @cfg {String/Object} autoEl * A tag name or {@link Ext.DomHelper DomHelper} spec used to create the {@link #getEl Element} which will * encapsulate this Component. * * You do not normally need to specify this. For the base classes {@link Ext.Component} and * {@link Ext.container.Container}, this defaults to **'div'**. The more complex Sencha classes use a more * complex DOM structure specified by their own {@link #renderTpl}s. * * This is intended to allow the developer to create application-specific utility Components encapsulated by * different DOM elements. Example usage: * * { * 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 {Ext.XTemplate/String/String[]} renderTpl * An {@link Ext.XTemplate XTemplate} used to create the internal structure inside this Component's encapsulating * {@link #getEl Element}. * * You do not normally need to specify this. For the base classes {@link Ext.Component} and * {@link Ext.container.Container}, this defaults to **`null`** 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. * * This is intended to allow the developer to create application-specific utility Components with customized * internal structure. * * Upon rendering, any created child elements may be automatically imported into object properties using the * {@link #renderSelectors} and {@link #childEls} options. * @protected */ renderTpl: '{%this.renderContent(out,values)%}', /** * @cfg {Object} renderData * * The data used by {@link #renderTpl} in addition to the following property values of the component: * * - id * - ui * - uiCls * - baseCls * - componentCls * - frame * * See {@link #renderSelectors} and {@link #childEls} for usage examples. */ /** * @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 renderes a title and description into its element: * * Ext.create('Ext.Component', { * renderTo: Ext.getBody(), * renderTpl: [ * '

{title}

', * '

{desc}

' * ], * renderData: { * title: "Error", * desc: "Something went wrong" * }, * renderSelectors: { * titleEl: 'h1.title', * descEl: 'p' * }, * listeners: { * afterrender: function(cmp){ * // After rendering the component will have a titleEl and descEl properties * cmp.titleEl.setStyle({color: "red"}); * } * } * }); * * For a faster, but less flexible, alternative that achieves the same end result (properties for child elements on the * Component after render), see {@link #childEls} and {@link #addChildEls}. */ /** * @cfg {Object[]} childEls * An array describing the child elements of the Component. Each member of the array * is an object with these properties: * * - `name` - The property name on the Component for the child element. * - `itemId` - The id to combine with the Component's id that is the id of the child element. * - `id` - The id of the child element. * * If the array member is a string, it is equivalent to `{ name: m, itemId: m }`. * * For example, a Component which renders a title and body text: * * Ext.create('Ext.Component', { * renderTo: Ext.getBody(), * renderTpl: [ * '

{title}

', * '

{msg}

', * ], * renderData: { * title: "Error", * msg: "Something went wrong" * }, * childEls: ["title"], * listeners: { * afterrender: function(cmp){ * // After rendering the component will have a title property * cmp.title.setStyle({color: "red"}); * } * } * }); * * A more flexible, but somewhat slower, approach is {@link #renderSelectors}. */ /** * @cfg {String/HTMLElement/Ext.Element} renderTo * Specify the id of the element, a DOM element or an existing Element that this component will be rendered into. * * **Notes:** * * Do *not* 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. * * When using this config, a call to render() is not required. * * See `{@link #render}` also. */ /** * @cfg {Boolean} frame * Specify as `true` to have the Component inject framing elements within the Component at render time to provide a * graphical rounded frame around the Component content. * * 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. * * The extra space taken up by this framing is available from the read only property {@link #frameSize}. */ /** * @property {Object} frameSize * @readonly * Indicates the width of any framing elements which were added within the encapsulating element * to provide graphical, rounded borders. See the {@link #frame} config. * * This is an object containing the frame width in pixels for all four sides of the Component containing the * following properties: * * @property {Number} [frameSize.top=0] The width of the top framing element in pixels. * @property {Number} [frameSize.right=0] The width of the right framing element in pixels. * @property {Number} [frameSize.bottom=0] The width of the bottom framing element in pixels. * @property {Number} [frameSize.left=0] The width of the left framing element in pixels. * @property {Number} [frameSize.width=0] The total width of the left and right framing elements in pixels. * @property {Number} [frameSize.height=0] The total height of the top and right bottom elements in pixels. */ frameSize: { left: 0, top: 0, right: 0, bottom: 0, width: 0, height: 0 }, /** * @cfg {String/Object} componentLayout * 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. * * Generally, developers will not use this configuration as all provided Components which need their internal * elements sizing (Such as {@link Ext.form.field.Base input fields}) come with their own componentLayout managers. * * 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. */ /** * @cfg {Ext.XTemplate/Ext.Template/String/String[]} tpl * An {@link Ext.Template}, {@link Ext.XTemplate} or an array of strings to form an Ext.XTemplate. Used in * conjunction with the `{@link #data}` and `{@link #tplWriteMode}` configurations. */ /** * @cfg {Object} data * The initial set of data to apply to the `{@link #tpl}` to update the content area of the Component. */ /** * @cfg {String} xtype * This property provides a shorter alternative to creating objects than using a full * class name. Using `xtype` is the most common way to define component instances, * especially in a container. For example, the items in a form containing text fields * could be created explicitly like so: * * items: [ * Ext.create('Ext.form.field.Text', { * fieldLabel: 'Foo' * }), * Ext.create('Ext.form.field.Text', { * fieldLabel: 'Bar' * }), * Ext.create('Ext.form.field.Number', { * fieldLabel: 'Num' * }) * ] * * But by using `xtype`, the above becomes: * * items: [ * { * xtype: 'textfield', * fieldLabel: 'Foo' * }, * { * xtype: 'textfield', * fieldLabel: 'Bar' * }, * { * xtype: 'numberfield', * fieldLabel: 'Num' * } * ] * * When the `xtype` is common to many items, {@link Ext.container.AbstractContainer#defaultType} * is another way to specify the `xtype` for all items that don't have an explicit `xtype`: * * defaultType: 'textfield', * items: [ * { fieldLabel: 'Foo' }, * { fieldLabel: 'Bar' }, * { fieldLabel: 'Num', xtype: 'numberfield' } * ] * * Each member of the `items` array is now just a "configuration object". These objects * are used to create and configure component instances. A configuration object can be * manually used to instantiate a component using {@link Ext#widget}: * * var text1 = Ext.create('Ext.form.field.Text', { * fieldLabel: 'Foo' * }); * * // or alternatively: * * var text1 = Ext.widget({ * xtype: 'textfield', * fieldLabel: 'Foo' * }); * * This conversion of configuration objects into instantiated components is done when * a container is created as part of its {Ext.container.AbstractContainer#initComponent} * process. As part of the same process, the `items` array is converted from its raw * array form into a {@link Ext.util.MixedCollection} instance. * * You can define your own `xtype` on a custom {@link Ext.Component component} by specifying * the `xtype` property in {@link Ext#define}. For example: * * Ext.define('MyApp.PressMeButton', { * extend: 'Ext.button.Button', * xtype: 'pressmebutton', * text: 'Press Me' * }); * * Care should be taken when naming an `xtype` in a custom component because there is * a single, shared scope for all xtypes. Third part components should consider using * a prefix to avoid collisions. * * Ext.define('Foo.form.CoolButton', { * extend: 'Ext.button.Button', * xtype: 'ux-coolbutton', * text: 'Cool!' * }); */ /** * @cfg {String} tplWriteMode * The Ext.(X)Template method to use when updating the content area of the Component. * See `{@link Ext.XTemplate#overwrite}` for information on default mode. */ tplWriteMode: 'overwrite', /** * @cfg {String} [baseCls='x-component'] * 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. 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. 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='x-item-disabled'] * CSS class to add when the Component is disabled. Defaults to 'x-item-disabled'. */ disabledCls: Ext.baseCSSPrefix + 'item-disabled', /** * @cfg {String/String[]} ui * A set style for a component. Can be a string or an Array of multiple strings (UIs) */ ui: 'default', /** * @cfg {String[]} uiCls * An array of of classNames which are currently applied to this component * @private */ uiCls: [], /** * @cfg {String/Object} style * A custom style specification to be applied to this component's Element. Should be a valid argument to * {@link Ext.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 * True to hide the component. */ hidden: false, /** * @cfg {Boolean} disabled * True to disable the component. */ disabled: false, /** * @cfg {Boolean} [draggable=false] * Allows the component to be dragged. */ /** * @property {Boolean} draggable * Indicates whether or not the component can be dragged. * @readonly */ draggable: false, /** * @cfg {Boolean} floating * Create the Component as a floating and use absolute positioning. * * The z-index of floating Components is handled by a ZIndexManager. If you simply render a floating Component into the DOM, it will be managed * by the global {@link Ext.WindowManager WindowManager}. * * If you include a floating Component as a child item of a Container, then upon render, ExtJS will seek an ancestor floating Component to house a new * ZIndexManager instance to manage its descendant floaters. If no floating ancestor can be found, the global WindowManager will be used. * * When a floating Component which has a ZindexManager managing descendant floaters is destroyed, those descendant floaters will also be destroyed. */ floating: false, /** * @cfg {String} hideMode * A String which specifies how this Component's encapsulating DOM element will be hidden. Values may be: * * - `'display'` : The Component will be hidden using the `display: none` style. * - `'visibility'` : The Component will be hidden using the `visibility: hidden` style. * - `'offsets'` : 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 `display` results in a * Component having zero dimensions. */ hideMode: 'display', /** * @cfg {String} contentEl * Specify an existing HTML element, or the `id` of an existing HTML element to use as the content for this component. * * 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 _after the Component is rendered_ to use as the content. * * **Notes:** * * The specified HTML element is appended to the layout element of the component _after any configured * {@link #html HTML} has been inserted_, and so the document will not contain this element at the time * the {@link #render} event is fired. * * The specified HTML element used will not participate in any **`{@link Ext.container.Container#layout layout}`** * scheme that the Component may use. It is just HTML. Layouts operate on child * **`{@link Ext.container.Container#cfg-items items}`**. * * Add either the `x-hidden` or the `x-hide-display` CSS class to prevent a brief flicker of the content before it * is rendered to the panel. */ /** * @cfg {String/Object} [html=''] * An HTML fragment, or a {@link Ext.DomHelper DomHelper} specification to use as the layout element content. * 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 _before_ any configured {@link #contentEl} * is appended. */ /** * @cfg {Boolean} styleHtmlContent * True to automatically style the html inside the content target of this component (body for panels). */ styleHtmlContent: false, /** * @cfg {String} [styleHtmlCls='x-html'] * The class that is added to the content target when you set styleHtmlContent to true. */ styleHtmlCls: Ext.baseCSSPrefix + 'html', /** * @cfg {Number} minHeight * The minimum value in pixels which this Component will set its height to. * * **Warning:** This will override any size management applied by layout managers. */ /** * @cfg {Number} minWidth * The minimum value in pixels which this Component will set its width to. * * **Warning:** This will override any size management applied by layout managers. */ /** * @cfg {Number} maxHeight * The maximum value in pixels which this Component will set its height to. * * **Warning:** This will override any size management applied by layout managers. */ /** * @cfg {Number} maxWidth * The maximum value in pixels which this Component will set its width to. * * **Warning:** This will override any size management applied by layout managers. */ /** * @cfg {Ext.ComponentLoader/Object} loader * A configuration object or an instance of a {@link Ext.ComponentLoader} to load remote content for this Component. */ /** * @cfg {Boolean} autoShow * True to automatically show the component upon creation. This config option may only be used for * {@link #floating} components or components that use {@link #autoRender}. Defaults to false. */ autoShow: false, /** * @cfg {Boolean/String/HTMLElement/Ext.Element} autoRender * This config is intended mainly for non-{@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 _{@link #method-show}_. If {@link #floating} is true, the value of this config is omited as if it is `true`. * * Specify as `true` to have this Component render to the document body upon first show. * * Specify as an element, or the ID of an element to have this Component render to a specific element upon first * show. */ autoRender: false, // @private allowDomMove: true, /** * @cfg {Object/Object[]} 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. */ /** * @property {Boolean} rendered * Indicates whether or not the component has been rendered. * @readonly */ rendered: false, /** * @property {Number} componentLayoutCounter * @private * The number of component layout calls made on this object. */ componentLayoutCounter: 0, /** * @cfg {Boolean/Number} [shrinkWrap=2] * * If this property is a number, it is interpreted as follows: * * - 0: Neither width nor height depend on content. This is equivalent to `false`. * - 1: Width depends on content (shrink wraps), but height does not. * - 2: Height depends on content (shrink wraps), but width does not. The default. * - 3: Both width and height depend on content (shrink wrap). This is equivalent to `true`. * * In CSS terms, shrink-wrap width is analogous to an inline-block element as opposed * to a block-level element. Some container layouts always shrink-wrap their children, * effectively ignoring this property (e.g., {@link Ext.layout.container.HBox}, * {@link Ext.layout.container.VBox}, {@link Ext.layout.component.Dock}). */ shrinkWrap: 2, weight: 0, /** * @property {Boolean} maskOnDisable * This is an internal flag that you use when creating custom components. By default this is set to true which means * that every component gets a mask when its disabled. Components like FieldContainer, FieldSet, Field, Button, Tab * override this property to false since they want to implement custom disable logic. */ maskOnDisable: true, /** * @property {Boolean} [_isLayoutRoot=false] * Setting this property to `true` causes the {@link #isLayoutRoot} method to return * `true` and stop the search for the top-most component for a layout. * @protected */ _isLayoutRoot: false, /** * Creates new Component. * @param {Object} config (optional) Config object. */ constructor : function(config) { var me = this, i, len, xhooks; if (config) { Ext.apply(me, config); xhooks = me.xhooks; if (xhooks) { delete me.xhooks; Ext.override(me, xhooks); } } else { config = {}; } me.initialConfig = config; me.mixins.elementCt.constructor.call(me); 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 * Fires after the component rendering is finished. * * The afterrender event is fired after this Component has been {@link #rendered}, been postprocesed by any * afterRender method defined for the Component. * @param {Ext.Component} this */ 'afterrender', /** * @event boxready * Fires *one time* - after the component has been layed out for the first time at its initial size. * @param {Ext.Component} this * @param {Number} width The initial width * @param {Number} height The initial height */ 'boxready', /** * @event beforedestroy * Fires before the component is {@link #method-destroy}ed. Return false from an event handler to stop the * {@link #method-destroy}. * @param {Ext.Component} this */ 'beforedestroy', /** * @event destroy * Fires after the component is {@link #method-destroy}ed. * @param {Ext.Component} this */ 'destroy', /** * @event resize * Fires after the component is resized. Note that this does *not* fire when the component is first layed out at its initial * size. To hook that point in the lifecycle, use the {@link #boxready} event. * @param {Ext.Component} this * @param {Number} width The new width that was set * @param {Number} height The new height that was set * @param {Number} oldWidth The previous width * @param {Number} oldHeight The previous height */ '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', /** * @event focus * Fires when this Component receives focus. * @param {Ext.Component} this * @param {Ext.EventObject} The focus event. */ 'focus', /** * @event blur * Fires when this Component loses focus. * @param {Ext.Component} this * @param {Ext.EventObject} The blur event. */ 'blur' ); me.getId(); me.setupProtoEl(); // initComponent, beforeRender, or event handlers may have set the style or cls property since the protoEl was set up // so we must apply styles and classes here too. if (me.cls) { me.initialCls = me.cls; me.protoEl.addCls(me.cls); } if (me.style) { me.initialStyle = me.style; me.protoEl.setStyle(me.style); } me.mons = []; me.renderData = me.renderData || {}; me.renderSelectors = me.renderSelectors || {}; if (me.plugins) { me.plugins = [].concat(me.plugins); me.constructPlugins(); } // we need this before we call initComponent if (!me.hasListeners) { me.hasListeners = new me.HasListeners(); } me.initComponent(); // ititComponent gets a chance to change the id property before registering Ext.ComponentManager.register(me); // Dont pass the config so that it is not applied to 'this' again me.mixins.observable.constructor.call(me); me.mixins.state.constructor.call(me, config); // Save state on resize. this.addStateEvents('resize'); // 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(); if (me.renderTo) { me.render(me.renderTo); // EXTJSIV-1935 - should be a way to do afterShow or something, but that // won't work. Likewise, rendering hidden and then showing (w/autoShow) has // implications to afterRender so we cannot do that. } if (me.autoShow) { me.show(); } // if (Ext.isDefined(me.disabledClass)) { if (Ext.isDefined(Ext.global.console)) { Ext.global.console.warn('Ext.Component: disabledClass has been deprecated. Please use disabledCls.'); } me.disabledCls = me.disabledClass; delete me.disabledClass; } // }, initComponent: function () { // This is called again here to allow derived classes to add plugin configs to the // plugins array before calling down to this, the base initComponent. this.constructPlugins(); // this will properly (ignore or) constrain the configured width/height to their // min/max values for consistency. this.setSize(this.width, this.height); }, /** * The supplied default state gathering method for the AbstractComponent class. * * This method returns dimension settings such as `flex`, `anchor`, `width` and `height` along with `collapsed` * state. * * Subclasses which implement more complex state should call the superclass's implementation, and apply their state * to the result if this basic state is to be saved. * * Note that Component state will only be saved if the Component has a {@link #stateId} and there as a StateProvider * configured for the document. * * @return {Object} */ getState: function() { var me = this, state = null, sizeModel = me.getSizeModel(); if (sizeModel.width.configured) { state = me.addPropertyToState(state, 'width'); } if (sizeModel.height.configured) { state = me.addPropertyToState(state, 'height'); } return state; }, /** * Save a property to the given state object if it is not its default or configured * value. * * @param {Object} state The state object * @param {String} propName The name of the property on this object to save. * @param {String} [value] The value of the state property (defaults to `this[propName]`). * @return {Boolean} The state object or a new object if state was null and the property * was saved. * @protected */ addPropertyToState: function (state, propName, value) { var me = this, len = arguments.length; // If the property is inherited, it is a default and we don't want to save it to // the state, however if we explicitly specify a value, always save it if (len == 3 || me.hasOwnProperty(propName)) { if (len < 3) { value = me[propName]; } // If the property has the same value as was initially configured, again, we // don't want to save it. if (value !== me.initialConfig[propName]) { (state || (state = {}))[propName] = value; } } return state; }, show: Ext.emptyFn, animate: function(animObj) { var me = this, hasToWidth, hasToHeight, toHeight, toWidth, to, clearWidth, clearHeight, curWidth, w, curHeight, h, needsResize; animObj = animObj || {}; to = animObj.to || {}; if (Ext.fx.Manager.hasFxBlock(me.id)) { return me; } hasToWidth = Ext.isDefined(to.width); if (hasToWidth) { toWidth = Ext.Number.constrain(to.width, me.minWidth, me.maxWidth); } hasToHeight = Ext.isDefined(to.height); if (hasToHeight) { toHeight = Ext.Number.constrain(to.height, me.minHeight, me.maxHeight); } // Special processing for animating Component dimensions. if (!animObj.dynamic && (hasToWidth || hasToHeight)) { curWidth = (animObj.from ? animObj.from.width : undefined) || me.getWidth(); w = curWidth; curHeight = (animObj.from ? animObj.from.height : undefined) || me.getHeight(); h = curHeight; needsResize = false; if (hasToHeight && toHeight > curHeight) { h = toHeight; needsResize = true; } if (hasToWidth && toWidth > curWidth) { w = toWidth; 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) { clearWidth = !Ext.isNumber(me.width); clearHeight = !Ext.isNumber(me.height); me.setSize(w, h); me.el.setSize(curWidth, curHeight); if (clearWidth) { delete me.width; } if (clearHeight) { delete me.height; } } if (hasToWidth) { to.width = toWidth; } if (hasToHeight) { to.height = toHeight; } } return me.mixins.animate.animate.apply(me, arguments); }, onHide: function() { this.updateLayout({ isRoot: false }); }, onShow : function() { this.updateLayout({ isRoot: false }); }, constructPlugin: function(plugin) { if (plugin.ptype && typeof plugin.init != 'function') { plugin.cmp = this; plugin = Ext.PluginManager.create(plugin); } else if (typeof plugin == 'string') { plugin = Ext.PluginManager.create({ ptype: plugin, cmp: this }); } return plugin; }, /** * Ensures that the plugins array contains fully constructed plugin instances. This converts any configs into their * appropriate instances. */ constructPlugins: function() { var me = this, plugins = me.plugins, i, len; if (plugins) { for (i = 0, len = plugins.length; i < len; i++) { // this just returns already-constructed plugin instances... plugins[i] = me.constructPlugin(plugins[i]); } } }, // @private initPlugin : function(plugin) { plugin.init(this); return plugin; }, /** * @private * Injected as an override by Ext.Aria.initialize */ updateAria: Ext.emptyFn, /** * Called by Component#doAutoRender * * Register a Container configured `floating: true` with this Component's {@link Ext.ZIndexManager ZIndexManager}. * * Components added in ths way will not participate in any layout, but will be rendered * upon first show in the way that {@link Ext.window.Window Window}s are. */ registerFloatingItem: function(cmp) { var me = this; if (!me.floatingItems) { me.floatingItems = new Ext.ZIndexManager(me); } me.floatingItems.register(cmp); }, unregisterFloatingItem: function(cmp) { var me = this; if (me.floatingItems) { me.floatingItems.unregister(cmp); } }, layoutSuspendCount: 0, suspendLayouts: function () { var me = this; if (!me.rendered) { return; } if (++me.layoutSuspendCount == 1) { me.suspendLayout = true; } }, resumeLayouts: function (flushOptions) { var me = this; if (!me.rendered) { return; } if (! --me.layoutSuspendCount) { me.suspendLayout = false; if (flushOptions && !me.isLayoutSuspended()) { me.updateLayout(flushOptions); } } }, setupProtoEl: function() { var me = this, cls = [ me.baseCls, me.getComponentLayout().targetCls ]; // if (Ext.isDefined(me.cmpCls)) { if (Ext.isDefined(Ext.global.console)) { Ext.global.console.warn('Ext.Component: cmpCls has been deprecated. Please use componentCls.'); } me.componentCls = me.cmpCls; delete me.cmpCls; } // if (me.componentCls) { cls.push(me.componentCls); } else { me.componentCls = me.baseCls; } me.protoEl = new Ext.util.ProtoElement({ cls: cls.join(' ') // in case any of the parts have multiple classes }); }, /** * Sets the UI for the component. This will remove any existing UIs on the component. It will also loop through any * uiCls set on the component and rename them so they include the new UI * @param {String} ui The new UI for the component */ setUI: function(ui) { var me = this, oldUICls = Ext.Array.clone(me.uiCls), newUICls = [], classes = [], cls, i; //loop through all existing uiCls and update the ui in them for (i = 0; i < oldUICls.length; i++) { cls = oldUICls[i]; classes = classes.concat(me.removeClsWithUI(cls, true)); newUICls.push(cls); } if (classes.length) { me.removeCls(classes); } //remove the UI from the element me.removeUIFromElement(); //set the UI me.ui = ui; //add the new UI to the element me.addUIToElement(); //loop through all existing uiCls and update the ui in them classes = []; for (i = 0; i < newUICls.length; i++) { cls = newUICls[i]; classes = classes.concat(me.addClsWithUI(cls, true)); } if (classes.length) { me.addCls(classes); } // Changing the ui can lead to significant changes to a component's appearance, so the layout needs to be // updated. Internally most calls to setUI are pre-render. Buttons are a notable exception as setScale changes // the ui and often requires the layout to be updated. if (me.rendered) { me.updateLayout(); } }, /** * Adds a cls to the uiCls array, which will also call {@link #addUIClsToElement} and adds to all elements of this * component. * @param {String/String[]} classes A string or an array of strings to add to the uiCls * @param {Object} skip (Boolean) skip True to skip adding it to the class and do it later (via the return) */ addClsWithUI: function(classes, skip) { var me = this, clsArray = [], length, i = 0, cls; if (typeof classes === "string") { classes = (classes.indexOf(' ') < 0) ? [classes] : Ext.String.splitWords(classes); } length = classes.length; me.uiCls = Ext.Array.clone(me.uiCls); for (; i < length; i++) { cls = classes[i]; if (cls && !me.hasUICls(cls)) { me.uiCls.push(cls); clsArray = clsArray.concat(me.addUIClsToElement(cls)); } } if (skip !== true) { me.addCls(clsArray); } return clsArray; }, /** * Removes a cls to the uiCls array, which will also call {@link #removeUIClsFromElement} and removes it from all * elements of this component. * @param {String/String[]} cls A string or an array of strings to remove to the uiCls */ removeClsWithUI: function(classes, skip) { var me = this, clsArray = [], i = 0, length, cls; if (typeof classes === "string") { classes = (classes.indexOf(' ') < 0) ? [classes] : Ext.String.splitWords(classes); } length = classes.length; for (i = 0; i < length; i++) { cls = classes[i]; if (cls && me.hasUICls(cls)) { me.uiCls = Ext.Array.remove(me.uiCls, cls); clsArray = clsArray.concat(me.removeUIClsFromElement(cls)); } } if (skip !== true) { me.removeCls(clsArray); } return clsArray; }, /** * Checks if there is currently a specified uiCls * @param {String} cls The cls to check */ hasUICls: function(cls) { var me = this, uiCls = me.uiCls || []; return Ext.Array.contains(uiCls, cls); }, frameElementsArray: ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'], /** * Method which adds a specified UI + uiCls to the components element. Can be overridden to remove the UI from more * than just the components element. * @param {String} ui The UI to remove from the element */ addUIClsToElement: function(cls) { var me = this, baseClsUi = me.baseCls + '-' + me.ui + '-' + cls, result = [Ext.baseCSSPrefix + cls, me.baseCls + '-' + cls, baseClsUi], frameElementCls = me.frameElementCls, frameElementsArray, frameElementsLength, i, el, frameElement, c; if (me.frame && !Ext.supports.CSS3BorderRadius) { // define each element of the frame frameElementsArray = me.frameElementsArray; frameElementsLength = frameElementsArray.length; i = 0; // loop through each of them, and if they are defined add the ui for (; i < frameElementsLength; i++) { frameElement = frameElementsArray[i]; el = me['frame' + frameElement.toUpperCase()]; c = baseClsUi + '-' + frameElement; if (el && el.dom) { el.addCls(c); } else if (Ext.Array.indexOf(frameElementCls[frameElement], c) == -1) { frameElementCls[frameElement].push(c); } } } me.frameElementCls = frameElementCls; return result; }, /** * Method which removes a specified UI + uiCls from the components element. The cls which is added to the element * will be: `this.baseCls + '-' + ui` * @param {String} ui The UI to add to the element */ removeUIClsFromElement: function(cls) { var me = this, baseClsUi = me.baseCls + '-' + me.ui + '-' + cls, result = [Ext.baseCSSPrefix + cls, me.baseCls + '-' + cls, baseClsUi], frameElementCls = me.frameElementCls, frameElementsArray, frameElementsLength, i, el, frameElement, c; if (me.frame && !Ext.supports.CSS3BorderRadius) { // define each element of the frame frameElementsArray = me.frameElementsArray; frameElementsLength = frameElementsArray.length; i = 0; // loop through each of them, and if they are defined add the ui for (; i < frameElementsLength; i++) { frameElement = frameElementsArray[i]; el = me['frame' + frameElement.toUpperCase()]; c = baseClsUi + '-' + frameElement; if (el && el.dom) { el.addCls(c); } else { Ext.Array.remove(frameElementCls[frameElement], c); } } } me.frameElementCls = frameElementCls; return result; }, /** * Method which adds a specified UI to the components element. * @private */ addUIToElement: function() { var me = this, baseClsUI = me.baseCls + '-' + me.ui, frameElementCls = me.frameElementCls, frameElementsArray, frameElementsLength, i, el, frameElement, c; me.addCls(baseClsUI); if (me.frame && !Ext.supports.CSS3BorderRadius) { // define each element of the frame frameElementsArray = me.frameElementsArray; frameElementsLength = frameElementsArray.length; i = 0; // loop through each of them, and if they are defined add the ui for (; i < frameElementsLength; i++) { frameElement = frameElementsArray[i]; el = me['frame' + frameElement.toUpperCase()]; c = baseClsUI + '-' + frameElement; if (el) { el.addCls(c); } else { if (!Ext.Array.contains(frameElementCls[frameElement], c)) { frameElementCls[frameElement].push(c); } } } } }, /** * Method which removes a specified UI from the components element. * @private */ removeUIFromElement: function() { var me = this, baseClsUI = me.baseCls + '-' + me.ui, frameElementCls = me.frameElementCls, frameElementsArray, frameElementsLength, i, el, frameElement, c; me.removeCls(baseClsUI); if (me.frame && !Ext.supports.CSS3BorderRadius) { // define each element of the frame frameElementsArray = me.frameElementsArray; frameElementsLength = frameElementsArray.length; i = 0; for (; i < frameElementsLength; i++) { frameElement = frameElementsArray[i]; el = me['frame' + frameElement.toUpperCase()]; c = baseClsUI + '-' + frameElement; if (el) { el.removeCls(c); } else { Ext.Array.remove(frameElementCls[frameElement], c); } } } }, /** * @private */ getTpl: function(name) { return Ext.XTemplate.getTpl(this, name); }, /** * Converts style definitions to String. * @return {String} A CSS style string with style, padding, margin and border. * @private */ initStyles: function(targetEl) { var me = this, Element = Ext.Element, padding = me.padding, margin = me.margin, x = me.x, y = me.y, width, height; // Convert the padding, margin and border properties from a space seperated string // into a proper style string if (padding !== undefined) { targetEl.setStyle('padding', Element.unitizeBox((padding === true) ? 5 : padding)); } if (margin !== undefined) { targetEl.setStyle('margin', Element.unitizeBox((margin === true) ? 5 : margin)); } if (me.border !== undefined) { me.setBorder(me.border, targetEl); } // initComponent, beforeRender, or event handlers may have set the style or cls property since the protoEl was set up // so we must apply styles and classes here too. if (me.cls && me.cls != me.initialCls) { targetEl.addCls(me.cls); delete me.cls; delete me.initialCls; } if (me.style && me.style != me.initialStyle) { targetEl.setStyle(me.style); delete me.style; delete me.initialStyle; } if (x !== undefined) { targetEl.setStyle('left', x + 'px'); } if (y !== undefined) { targetEl.setStyle('top', y + 'px'); } // Framed components need their width/height to apply to the frame, which is // best handled in layout at present. // If we're using the content box model, we also cannot assign initial sizes since we do not know the border widths to subtract if (!me.getFrameInfo() && Ext.isBorderBox) { width = me.width; height = me.height; // framed components need their width/height to apply to the frame, which is // best handled in layout at present if (width !== undefined) { targetEl.setStyle('width', (typeof width === 'number') ? width + 'px' : width); } if (height !== undefined) { targetEl.setStyle('height', (typeof height === 'number') ? height + 'px' : height); } } }, // @private initEvents : function() { var me = this, afterRenderEvents = me.afterRenderEvents, el, property, fn = function(listeners){ me.mon(el, listeners); }; if (afterRenderEvents) { for (property in afterRenderEvents) { if (afterRenderEvents.hasOwnProperty(property)) { el = me[property]; if (el && el.on) { Ext.each(afterRenderEvents[property], fn); } } } } // This will add focus/blur listeners to the getFocusEl() element if that is naturally focusable. // If *not* naturally focusable, then the FocusManager must be enabled to get it to listen for focus so that // the FocusManager can track and highlight focus. me.addFocusListener(); }, /** * @private *

Sets up the focus listener on this Component's {@link #getFocusEl focusEl} if it has one.

*

Form Components which must implicitly participate in tabbing order usually have a naturally focusable * element as their {@link #getFocusEl focusEl}, and it is the DOM event of that recieving focus which drives * the Component's onFocus handling, and the DOM event of it being blurred which drives the onBlur handling.

*

If the {@link #getFocusEl focusEl} is not naturally focusable, then the listeners are only added * if the {@link Ext.FocusManager FocusManager} is enabled.

*/ addFocusListener: function() { var me = this, focusEl = me.getFocusEl(), needsTabIndex; // All Containers may be focusable, not only "form" type elements, but also // Panels, Toolbars, Windows etc. // Usually, the
element they will return as their focusEl will not be able to recieve focus // However, if the FocusManager is invoked, its non-default navigation handlers (invoked when // tabbing/arrowing off of certain Components) may explicitly focus a Panel or Container or FieldSet etc. // Add listeners to the focus and blur events on the focus element // If this Component returns a focusEl, we might need to add a focus listener to it. if (focusEl) { // getFocusEl might return a Component if a Container wishes to delegate focus to a descendant. // Window can do this via its defaultFocus configuration which can reference a Button. if (focusEl.isComponent) { return focusEl.addFocusListener(); } // If the focusEl is naturally focusable, then we always need a focus listener to drive the Component's // onFocus handling. // If *not* naturally focusable, then we only need the focus listener if the FocusManager is enabled. needsTabIndex = focusEl.needsTabIndex(); if (!me.focusListenerAdded && (!needsTabIndex || Ext.FocusManager.enabled)) { if (needsTabIndex) { focusEl.dom.tabIndex = -1; } focusEl.on({ focus: me.onFocus, blur: me.onBlur, scope: me }); me.focusListenerAdded = true; } } }, /** * @private *

Returns the focus holder element associated with this Component. At the Component base class level, this function returns undefined.

*

Subclasses which use embedded focusable elements (such as Window, Field and Button) should override this for use by the {@link #focus} method.

*

Containers which need to participate in the {@link Ext.FocusManager FocusManager}'s navigation and Container focusing scheme also * need to return a focusEl, although focus is only listened for in this case if the {@link Ext.FocusManager FocusManager} is {@link Ext.FocusManager#method-enable enable}d.

* @returns {undefined} undefined because raw Components cannot by default hold focus. */ getFocusEl: Ext.emptyFn, isFocusable: function(c) { var me = this, focusEl; if ((me.focusable !== false) && (focusEl = me.getFocusEl()) && me.rendered && !me.destroying && !me.isDestroyed && !me.disabled && me.isVisible(true)) { // getFocusEl might return a Component if a Container wishes to delegate focus to a descendant. // Window can do this via its defaultFocus configuration which can reference a Button. if (focusEl.isComponent) { return focusEl.isFocusable(); } return focusEl && focusEl.dom && focusEl.isVisible(); } }, // private preFocus: Ext.emptyFn, // private onFocus: function(e) { var me = this, focusCls = me.focusCls, focusEl = me.getFocusEl(); if (!me.disabled) { me.preFocus(e); if (focusCls && focusEl) { focusEl.addCls(me.addClsWithUI(focusCls, true)); } if (!me.hasFocus) { me.hasFocus = true; me.fireEvent('focus', me, e); } } }, // private beforeBlur : Ext.emptyFn, // private onBlur : function(e) { var me = this, focusCls = me.focusCls, focusEl = me.getFocusEl(); if (me.destroying) { return; } me.beforeBlur(e); if (focusCls && focusEl) { focusEl.removeCls(me.removeClsWithUI(focusCls, true)); } if (me.validateOnBlur) { me.validate(); } me.hasFocus = false; me.fireEvent('blur', me, e); me.postBlur(e); }, // private postBlur : Ext.emptyFn, /** * Tests whether this Component matches the selector string. * @param {String} selector The selector string to test against. * @return {Boolean} True if this Component matches the selector. */ is: function(selector) { return Ext.ComponentQuery.is(this, selector); }, /** * Walks up the `ownerCt` axis looking for an ancestor Container which matches the passed simple selector. * * Example: * * var owningTabPanel = grid.up('tabpanel'); * * @param {String} [selector] The simple selector to test. * @return {Ext.container.Container} The matching ancestor Container (or `undefined` if no match was found). */ up: function(selector) { // Use bubble target to navigate upwards so that Components can implement their own hierarchy. // For example Menus implement getBubbleTarget because they have a parentMenu or ownerButton as an // upward link depending upon how they are owned and triggered. var result = this.getBubbleTarget(); if (selector) { for (; result; result = result.getBubbleTarget()) { if (Ext.ComponentQuery.is(result, selector)) { return result; } } } return result; }, /** * Returns the next sibling of this Component. * * Optionally selects the next sibling which matches the passed {@link Ext.ComponentQuery ComponentQuery} selector. * * May also be refered to as **`next()`** * * Note that this is limited to siblings, and if no siblings of the item match, `null` is returned. Contrast with * {@link #nextNode} * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the following items. * @return {Ext.Component} 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; }, /** * Returns the previous sibling of this Component. * * Optionally selects the previous sibling which matches the passed {@link Ext.ComponentQuery ComponentQuery} * selector. * * May also be refered to as **`prev()`** * * Note that this is limited to siblings, and if no siblings of the item match, `null` is returned. Contrast with * {@link #previousNode} * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the preceding items. * @return {Ext.Component} 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; }, /** * Returns the previous node in the Component tree in tree traversal order. * * Note that this is not limited to siblings, and if invoked upon a node with no matching siblings, will walk the * tree in reverse order to attempt to find a match. Contrast with {@link #previousSibling}. * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the preceding nodes. * @return {Ext.Component} The previous node (or the previous node which matches the selector). * Returns null if there is no matching node. */ previousNode: function(selector, includeSelf) { var node = this, result, it, i, sib; // If asked to include self, test me if (includeSelf && node.is(selector)) { return node; } if (node.ownerCt) { for (it = node.ownerCt.items.items, i = Ext.Array.indexOf(it, node) - 1; i > -1; i--) { sib = it[i]; if (sib.query) { result = sib.query(selector); result = result[result.length - 1]; if (result) { return result; } if (sib.is(selector)) { return sib; } } } return node.ownerCt.previousNode(selector, true); } }, /** * Returns the next node in the Component tree in tree traversal order. * * Note that this is not limited to siblings, and if invoked upon a node with no matching siblings, will walk the * tree to attempt to find a match. Contrast with {@link #nextSibling}. * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the following nodes. * @return {Ext.Component} The next node (or the next node which matches the selector). * Returns null if there is no matching node. */ nextNode: function(selector, includeSelf) { var node = this, result, it, len, i, sib; // If asked to include self, test me if (includeSelf && node.is(selector)) { return node; } if (node.ownerCt) { for (it = node.ownerCt.items, i = it.indexOf(node) + 1, it = it.items, len = it.length; i < len; i++) { sib = it[i]; if (sib.is(selector)) { return sib; } if (sib.down) { result = sib.down(selector); if (result) { return result; } } } return node.ownerCt.nextNode(selector); } }, /** * Retrieves the id of this component. Will autogenerate an id if one has not already been set. * @return {String} */ 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. * @return {Ext.dom.Element} */ 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; }, /** * @private * Returns the CSS style object which will set the Component's scroll styles. This must be applied * to the {@link #getTargetEl target element}. */ getOverflowStyle: function() { var me = this, result = null; if (typeof me.autoScroll == 'boolean') { result = { overflow: me.autoScroll ? 'auto' : '' }; } else if (me.overflowX !== undefined || me.overflowY !== undefined) { result = { 'overflow-x': (me.overflowX||''), 'overflow-y': (me.overflowY||'') }; } // The scrollable container element must be non-statically positioned or IE6/7 will make // positioned children stay in place rather than scrolling with the rest of the content if (result && (Ext.isIE6 || Ext.isIE7)) { result.position = 'relative'; } return result; }, /** * 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). * * **If using your own subclasses, be aware that a Component must register its own xtype to participate in * determination of inherited xtypes.** * * For a list of all available xtypes, see the {@link Ext.Component} header. * * Example usage: * * var t = new Ext.form.field.Text(); * var isText = t.isXType('textfield'); // true * var isBoxSubclass = t.isXType('field'); // true, descended from Ext.form.field.Base * var isBoxInstance = t.isXType('field', true); // false, not a direct Ext.form.field.Base instance * * @param {String} xtype The xtype to check for this Component * @param {Boolean} [shallow=false] True to check whether this Component is directly of the specified xtype, false to * check whether this Component is descended from the xtype. * @return {Boolean} True if this component descends from the specified xtype, false otherwise. */ isXType: function(xtype, shallow) { if (shallow) { return this.xtype === xtype; } else { return this.xtypesMap[xtype]; } }, /** * Returns this Component's xtype hierarchy as a slash-delimited string. For a list of all available xtypes, see the * {@link Ext.Component} header. * * **If using your own subclasses, be aware that a Component must register its own xtype to participate in * determination of inherited xtypes.** * * Example usage: * * var t = new Ext.form.field.Text(); * alert(t.getXTypes()); // alerts 'component/field/textfield' * * @return {String} The xtype hierarchy string */ getXTypes: function() { var self = this.self, xtypes, parentPrototype, parentXtypes; if (!self.xtypes) { xtypes = []; parentPrototype = this; while (parentPrototype) { parentXtypes = parentPrototype.xtypes; if (parentXtypes !== undefined) { xtypes.unshift.apply(xtypes, parentXtypes); } parentPrototype = parentPrototype.superclass; } self.xtypeChain = xtypes; self.xtypes = xtypes.join('/'); } return self.xtypes; }, /** * Update the content area of a component. * @param {String/Object} 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.Element update * @param {Boolean} [loadScripts=false] Only legitimate when using the html configuration. * @param {Function} [callback] 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.DomHelper.markup(htmlOrData) : htmlOrData; if (me.rendered) { me.getTargetEl().update(me.html, loadScripts, cb); } } if (me.rendered) { me.updateLayout(); } }, /** * 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=false] Pass `true` to interrogate the visibility status of all parent Containers to * determine whether this Component is truly visible to the user. * * 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. * * @return {Boolean} True if this component is visible, false otherwise. */ isVisible: function(deep) { var me = this, child = me, visible = me.rendered && !me.hidden, ancestor = me.ownerCt; // Clear hiddenOwnerCt property me.hiddenAncestor = false; if (me.destroyed) { return false; } if (deep && visible && 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; }, onBoxReady: function(){ var me = this; if (me.disableOnBoxReady) { me.onDisable(); } else if (me.enableOnBoxReady) { me.onEnable(); } if (me.resizable) { me.initResizable(me.resizable); } // Draggability must be initialized after resizability // Because if we have to be wrapped, the resizer wrapper must be dragged as a pseudo-Component if (me.draggable) { me.initDraggable(); } }, /** * Enable the component * @param {Boolean} [silent=false] Passing true will supress the 'enable' event from being fired. */ enable: function(silent) { var me = this; delete me.disableOnBoxReady; me.removeCls(me.disabledCls); if (me.rendered) { me.onEnable(); } else { me.enableOnBoxReady = true; } me.disabled = false; delete me.resetDisable; if (silent !== true) { me.fireEvent('enable', me); } return me; }, /** * Disable the component. * @param {Boolean} [silent=false] Passing true will supress the 'disable' event from being fired. */ disable: function(silent) { var me = this; delete me.enableOnBoxReady; me.addCls(me.disabledCls); if (me.rendered) { me.onDisable(); } else { me.disableOnBoxReady = true; } me.disabled = true; if (silent !== true) { delete me.resetDisable; me.fireEvent('disable', me); } return me; }, /** * Allows addition of behavior to the enable operation. * After calling the superclass’s onEnable, the Component will be enabled. * * @template * @protected */ onEnable: function() { if (this.maskOnDisable) { this.el.dom.disabled = false; this.unmask(); } }, /** * Allows addition of behavior to the disable operation. * After calling the superclass’s onDisable, the Component will be disabled. * * @template * @protected */ onDisable : function() { if (this.maskOnDisable) { this.el.dom.disabled = true; this.mask(); } }, mask: function() { var box = this.lastBox, target = this.getMaskTarget(), args = []; // Pass it the height of our element if we know it. if (box) { args[2] = box.height; } target.mask.apply(target, args); }, unmask: function() { this.getMaskTarget().unmask(); }, getMaskTarget: function(){ return this.el; }, /** * 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 True to disable. */ 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. * @param {String/String[]} cls The CSS class name to add * @return {Ext.Component} Returns the Component to allow method chaining. */ addCls : function(cls) { var me = this, el = me.rendered ? me.el : me.protoEl; el.addCls.apply(el, arguments); return me; }, /** * @inheritdoc Ext.AbstractComponent#addCls * @deprecated 4.1 Use {@link #addCls} instead. */ addClass : function() { return this.addCls.apply(this, arguments); }, /** * Checks if the specified CSS class exists on this element's DOM node. * @param {String} className The CSS class to check for * @return {Boolean} True if the class exists, else false * @method */ hasCls: function (cls) { var me = this, el = me.rendered ? me.el : me.protoEl; return el.hasCls.apply(el, arguments); }, /** * Removes a CSS class from the top level element representing this component. * @param {String/String[]} cls The CSS class name to remove * @returns {Ext.Component} Returns the Component to allow method chaining. */ removeCls : function(cls) { var me = this, el = me.rendered ? me.el : me.protoEl; el.removeCls.apply(el, arguments); return me; }, // removeClass : function() { if (Ext.isDefined(Ext.global.console)) { Ext.global.console.warn('Ext.Component: removeClass has been deprecated. Please use removeCls.'); } return this.removeCls.apply(this, arguments); }, // addOverCls: function() { var me = this; if (!me.disabled) { me.el.addCls(me.overCls); } }, removeOverCls: function() { this.el.removeCls(this.overCls); }, 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)) { 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 || {}; if (!me.afterRenderEvents[element]) { me.afterRenderEvents[element] = []; } me.afterRenderEvents[element].push(listeners); } } return me.mixins.observable.addListener.apply(me, arguments); }, // inherit docs removeManagedListenerItem: function(isClear, managedListener, item, ename, fn, scope){ var me = this, element = managedListener.options ? managedListener.options.element : null; if (element) { element = me[element]; if (element && element.un) { if (isClear || (managedListener.item === item && managedListener.ename === ename && (!fn || managedListener.fn === fn) && (!scope || managedListener.scope === scope))) { element.un(managedListener.ename, managedListener.fn, managedListener.scope); if (!isClear) { Ext.Array.remove(me.managedListeners, managedListener); } } } } else { return me.mixins.observable.removeManagedListenerItem.apply(me, arguments); } }, /** * 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; }, /** * 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. * * Allows addition of behavior when a Component is added to a * Container. At this stage, the Component is in the parent * Container's collection of child items. After calling the * superclass's onAdded, the ownerCt reference will be present, * and if configured with a ref, the refOwner will be set. * * @param {Ext.container.Container} container Container which holds the component * @param {Number} pos Position at which the component was added * * @template * @protected */ onAdded : function(container, pos) { var me = this; me.ownerCt = container; if (me.hasListeners.added) { me.fireEvent('added', me, container, pos); } }, /** * Method to manage awareness of when components are removed from their * respective Container, firing a #removed event. References are properly * cleaned up after removing a component from its owning container. * * Allows addition of behavior when a Component is removed from * its parent Container. At this stage, the Component has been * removed from its parent Container's collection of child items, * but has not been destroyed (It will be destroyed if the parent * Container's autoDestroy is true, or if the remove call was * passed a truthy second parameter). After calling the * superclass's onRemoved, the ownerCt and the refOwner will not * be present. * @param {Boolean} destroying Will be passed as true if the Container performing the remove operation will delete this * Component upon remove. * * @template * @protected */ onRemoved : function(destroying) { var me = this; if (me.hasListeners.removed) { me.fireEvent('removed', me, me.ownerCt); } delete me.ownerCt; delete me.ownerLayout; }, /** * Invoked before the Component is destroyed. * * @method * @template * @protected */ beforeDestroy : Ext.emptyFn, /** * Allows addition of behavior to the resize operation. * * Called when Ext.resizer.Resizer#drag event is fired. * * @method * @template * @protected */ 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 `{width:10, height:20}`. * * @param {Number/String/Object} width The new width to set. This may be one of: * * - A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels). * - A String used to set the CSS width style. * - A size object in the format `{width: widthValue, height: heightValue}`. * - `undefined` to leave the width unchanged. * * @param {Number/String} height The new height to set (not required if a size object is passed as the first arg). * This may be one of: * * - A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels). * - A String used to set the CSS height style. Animation may **not** be used. * - `undefined` to leave the height unchanged. * * @return {Ext.Component} this */ setSize : function(width, height) { var me = this; // support for standard size objects if (width && typeof width == 'object') { height = width.height; width = width.width; } // Constrain within configured maxima if (typeof width == 'number') { me.width = Ext.Number.constrain(width, me.minWidth, me.maxWidth); } else if (width === null) { delete me.width; } if (typeof height == 'number') { me.height = Ext.Number.constrain(height, me.minHeight, me.maxHeight); } else if (height === null) { delete me.height; } // If not rendered, all we need to is set the properties. // The initial layout will set the size if (me.rendered && me.isVisible()) { // If we are changing size, then we are not the root. me.updateLayout({ isRoot: false }); } return me; }, /** * Determines whether this Component is the root of a layout. This returns `true` if * this component can run its layout without assistance from or impact on its owner. * If this component cannot run its layout given these restrictions, `false` is returned * and its owner will be considered as the next candidate for the layout root. * * Setting the {@link #_isLayoutRoot} property to `true` causes this method to always * return `true`. This may be useful when updating a layout of a Container which shrink * wraps content, and you know that it will not change size, and so can safely be the * topmost participant in the layout run. * @protected */ isLayoutRoot: function() { var me = this, ownerLayout = me.ownerLayout; // Return true if we have been explicitly flagged as the layout root, or if we are floating. // Sometimes floating Components get an ownerCt ref injected into them which is *not* a true ownerCt, merely // an upward link for reference purposes. For example a grid column menu is linked to the // owning header via an ownerCt reference. if (!ownerLayout || me._isLayoutRoot || me.floating) { return true; } return ownerLayout.isItemLayoutRoot(me); }, /** * Returns true if layout is suspended for this component. This can come from direct * suspension of this component's layout activity ({@link #suspendLayouts}) or if one * of this component's containers is suspended. * * @return {Boolean} True layout of this component is suspended. */ isLayoutSuspended: function () { var comp = this, ownerLayout; while (comp) { if (comp.layoutSuspendCount || comp.suspendLayout) { return true; } ownerLayout = comp.ownerLayout; if (!ownerLayout) { break; } // TODO - what about suspending a Layout instance? // this works better than ownerCt since ownerLayout means "is managed by" in // the proper sense... some floating components have ownerCt but won't have an // ownerLayout comp = ownerLayout.owner; } return false; }, /** * Updates this component's layout. If this update effects this components {@link #ownerCt}, * that component's `updateLayout` method will be called to perform the layout instead. * Otherwise, just this component (and its child items) will layout. * * @param {Object} options An object with layout options. * @param {Boolean} options.defer True if this layout should be deferred. * @param {Boolean} options.isRoot True if this layout should be the root of the layout. */ updateLayout: function (options) { var me = this, defer, isRoot = options && options.isRoot; if (!me.rendered || me.layoutSuspendCount || me.suspendLayout) { return; } if (me.hidden) { Ext.AbstractComponent.cancelLayout(me); } else if (typeof isRoot != 'boolean') { isRoot = me.isLayoutRoot(); } // if we aren't the root, see if our ownerLayout will handle it... if (isRoot || !me.ownerLayout || !me.ownerLayout.onContentChange(me)) { // either we are the root or our ownerLayout doesn't care if (!me.isLayoutSuspended()) { // we aren't suspended (knew that), but neither is any of our ownerCt's... defer = (options && options.hasOwnProperty('defer')) ? options.defer : me.deferLayouts; Ext.AbstractComponent.updateLayout(me, defer); } } }, /** * Returns an object that describes how this component's width and height are managed. * These objects are shared and should not be modified. * * @return {Object} The size model for this component. * @return {Ext.layout.SizeModel} return.width The {@link Ext.layout.SizeModel size model} for the width. * @return {Ext.layout.SizeModel} return.height The {@link Ext.layout.SizeModel size model} for the height. */ getSizeModel: function (ownerCtSizeModel) { var me = this, models = Ext.layout.SizeModel, ownerCtx = me.componentLayout.ownerContext, hasWidth, hasHeight, heightModel, ownerLayout, policy, shrinkWrap, widthModel; if (ownerCtx) { widthModel = ownerCtx.widthModel; heightModel = ownerCtx.heightModel; } if (!widthModel || !heightModel) { hasWidth = (typeof me.width == 'number'); hasHeight = (typeof me.height == 'number'); // Floating or no owner layout, e.g. rendered using renderTo if (me.floating || !(ownerLayout = me.ownerLayout)) { if (hasWidth) { widthModel = models.configured; } if (hasHeight) { heightModel = models.configured; } policy = Ext.layout.Layout.prototype.autoSizePolicy; shrinkWrap = me.floating ? 3 : me.shrinkWrap; } else { policy = ownerLayout.getItemSizePolicy(me, ownerCtSizeModel); shrinkWrap = ownerLayout.isItemShrinkWrap(me); } shrinkWrap = (shrinkWrap === true) ? 3 : (shrinkWrap || 0); // false->0, true->3 if (shrinkWrap !== 3) { if (!ownerCtSizeModel) { ownerCtSizeModel = me.ownerCt && me.ownerCt.getSizeModel(); } if (ownerCtSizeModel) { shrinkWrap |= (ownerCtSizeModel.width.shrinkWrap ? 1 : 0) | (ownerCtSizeModel.height.shrinkWrap ? 2 : 0); } } if (!widthModel) { if (!policy.setsWidth) { if (hasWidth) { widthModel = models.configured; } else { widthModel = (shrinkWrap & 1) ? models.shrinkWrap : models.natural; } } else if (policy.readsWidth) { if (hasWidth) { widthModel = models.calculatedFromConfigured; } else { widthModel = (shrinkWrap & 1) ? models.calculatedFromShrinkWrap : models.calculatedFromNatural; } } else { widthModel = models.calculated; } } if (!heightModel) { if (!policy.setsHeight) { if (hasHeight) { heightModel = models.configured; } else { heightModel = (shrinkWrap & 2) ? models.shrinkWrap : models.natural; } } else if (policy.readsHeight) { if (hasHeight) { heightModel = models.calculatedFromConfigured; } else { heightModel = (shrinkWrap & 2) ? models.calculatedFromShrinkWrap : models.calculatedFromNatural; } } else { heightModel = models.calculated; } } } return { width: widthModel, height: heightModel }; }, isDescendant: function(ancestor) { if (ancestor.isContainer) { for (var c = this.ownerCt; c; c = c.ownerCt) { if (c === ancestor) { return true; } } } return false; }, /** * 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() { this.updateLayout(); return this; }, /** * Forces this component to redo its componentLayout. * @deprecated 4.1.0 Use {@link #updateLayout} instead. */ forceComponentLayout: function () { this.updateLayout(); }, // @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.Layout.create(me.componentLayout, 'autocomponent')); } return me.componentLayout; }, /** * Called by the layout system after the Component has been layed out. * * @param {Number} width The width that was set * @param {Number} height The height that was set * @param {Number} oldWidth The old width. undefined if this was the initial layout. * @param {Number} oldHeight The old height. undefined if this was the initial layout. * * @template * @protected */ afterComponentLayout: function(width, height, oldWidth, oldHeight) { var me = this; if (++me.componentLayoutCounter === 1) { me.afterFirstLayout(width, height); } if (me.hasListeners.resize && (width !== oldWidth || height !== oldHeight)) { me.fireEvent('resize', me, width, height, oldWidth, oldHeight); } }, /** * Occurs before componentLayout is run. Returning false from this method will prevent the componentLayout from * being executed. * * @param {Number} adjWidth The box-adjusted width that was set * @param {Number} adjHeight The box-adjusted height that was set * * @template * @protected */ beforeComponentLayout: function(width, height) { return true; }, /** * 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 * @param {Boolean/Object} [animate] If true, the Component is _animated_ into its new position. You may also pass an * animation configuration. * @return {Ext.Component} this */ setPosition : function(x, y, animate) { var me = this, pos = me.beforeSetPosition.apply(me, arguments); if (pos && me.rendered) { // Convert position WRT RTL pos = me.convertPosition(pos); if (animate) { me.stopAnimation(); me.animate(Ext.apply({ duration: 1000, listeners: { afteranimate: Ext.Function.bind(me.afterSetPosition, me, [pos.left, pos.top]) }, to: pos }, animate)); } else { // Must use Element's methods to set element position because, if it is a Layer (floater), it may need to sync a shadow // We must also only set the properties which are defined because Element.setLeftTop autos any undefined coordinates if (pos.left !== undefined && pos.top !== undefined) { me.el.setLeftTop(pos.left, pos.top); } else if (pos.left !== undefined) { me.el.setLeft(pos.left); } else if (pos.top !==undefined) { me.el.setTop(pos.top); } me.afterSetPosition(pos.left, pos.top); } } return me; }, /** * @private Template method called before a Component is positioned. */ beforeSetPosition: function (x, y, animate) { var pos, x0; // decode the position arguments: if (!x || Ext.isNumber(x)) { pos = { x: x, y : y, anim: animate }; } else if (Ext.isNumber(x0 = x[0])) { // an array of [x, y] pos = { x : x0, y : x[1], anim: y }; } else { pos = { x: x.x, y: x.y, anim: y }; // already an object w/ x & y properties } pos.hasX = Ext.isNumber(pos.x); pos.hasY = Ext.isNumber(pos.y); // store the position as specified: this.x = pos.x; this.y = pos.y; return (pos.hasX || pos.hasY) ? pos : null; }, /** * Template method called after a Component has been positioned. * * @param {Number} x * @param {Number} y * * @template * @protected */ afterSetPosition: function(x, y) { var me = this; me.onPosition(x, y); if (me.hasListeners.move) { me.fireEvent('move', me, x, y); } }, /** * This method converts an "{x: x, y: y}" object to a "{left: x+'px', top: y+'px'}" object. * The returned object contains the styles to set to effect the position. This is * overridden in RTL mode to be "{right: x, top: y}". * @private */ convertPosition: function (pos, withUnits) { var ret = {}, El = Ext.Element; if (pos.hasX) { ret.left = withUnits ? El.addUnits(pos.x) : pos.x; } if (pos.hasY) { ret.top = withUnits ? El.addUnits(pos.y) : pos.y; } return ret; }, /** * 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 * * @template * @protected */ 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: * * - A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels). * - A String used to set the CSS width style. * * @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: * * - A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels). * - A String used to set the CSS height style. * - _undefined_ to leave the height unchanged. * * @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 = new Ext.ComponentLoader(Ext.apply({ target: me, autoLoad: autoLoad }, loader)); } else { loader.setTarget(me); } return me.loader; } return null; }, /** * 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) * @param {Object} dock The dock position. * @param {Boolean} [layoutParent=false] True to re-layout parent. * @return {Ext.Component} this */ setDocked : function(dock, layoutParent) { var me = this; me.dock = dock; if (layoutParent && me.ownerCt && me.rendered) { me.ownerCt.updateLayout(); } return me; }, /** * * @param {String/Number} border The border, see {@link #border}. If a falsey value is passed * the border will be removed. */ setBorder: function(border, /* private */ targetEl) { var me = this, initial = !!targetEl; if (me.rendered || initial) { if (!initial) { targetEl = me.el; } if (!border) { border = 0; } else { border = Ext.Element.unitizeBox((border === true) ? 1 : border); } targetEl.setStyle('border-width', border); if (!initial) { me.updateLayout(); } } me.border = border; }, onDestroy : function() { var me = this; if (me.monitorResize && Ext.EventManager.resizeEvent) { Ext.EventManager.resizeEvent.removeListener(me.setSize, me); } // Destroying the floatingItems ZIndexManager will also destroy descendant floating Components Ext.destroy( me.componentLayout, me.loadMask, me.floatingItems ); }, /** * Destroys the Component. */ destroy : function() { var me = this, selectors = me.renderSelectors, selector, el; if (!me.isDestroyed) { if (!me.hasListeners.beforedestroy || me.fireEvent('beforedestroy', me) !== false) { me.destroying = true; me.beforeDestroy(); if (me.floating) { delete me.floatParent; // A zIndexManager is stamped into a *floating* Component when it is added to a Container. // If it has no zIndexManager at render time, it is assigned to the global Ext.WindowManager instance. if (me.zIndexManager) { me.zIndexManager.unregister(me); } } else if (me.ownerCt && me.ownerCt.remove) { me.ownerCt.remove(me, false); } me.onDestroy(); // Attempt to destroy all plugins Ext.destroy(me.plugins); if (me.hasListeners.destroy) { me.fireEvent('destroy', me); } Ext.ComponentManager.unregister(me); me.mixins.state.destroy.call(me); me.clearListeners(); // make sure we clean up the element references after removing all events if (me.rendered) { // In case we are queued for a layout. Ext.AbstractComponent.cancelLayout(me); if (!me.preserveElOnDestroy) { me.el.remove(); } me.mixins.elementCt.destroy.call(me); // removes childEls if (selectors) { for (selector in selectors) { if (selectors.hasOwnProperty(selector)) { el = me[selector]; if (el) { // in case any other code may have already removed it delete me[selector]; el.remove(); } } } } delete me.el; delete me.frameBody; delete me.rendered; } me.destroying = false; me.isDestroyed = true; } } }, /** * Retrieves a plugin by its pluginId which has been bound to this component. * @param {String} pluginId * @return {Ext.AbstractPlugin} plugin instance. */ getPlugin: function(pluginId) { var i = 0, plugins = this.plugins, ln = plugins.length; for (; i < ln; i++) { if (plugins[i].pluginId === pluginId) { return plugins[i]; } } }, /** * Determines whether this component is the descendant of a particular container. * @param {Ext.Container} container * @return {Boolean} True if it is. */ isDescendantOf: function(container) { return !!this.findParentBy(function(p){ return p === container; }); } }, function() { var abstractComponent = this; abstractComponent.createAlias({ on: 'addListener', prev: 'previousSibling', next: 'nextSibling' }); Ext.resumeLayouts = function (flush) { abstractComponent.resumeLayouts(flush); }; Ext.suspendLayouts = function () { abstractComponent.suspendLayouts(); }; /** * * Utility wrapper that suspends layouts of all components for the duration of a given function. * @param {Function} fn The function to execute. * @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed. */ Ext.batchLayouts = function(fn, scope) { abstractComponent.suspendLayouts(); // Invoke the function fn.call(scope); abstractComponent.resumeLayouts(true); }; });