X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/0494b8d9b9bb03ab6c22b34dae81261e3cd7e3e6..7a654f8d43fdb43d78b63d90528bed6e86b608cc:/src/Component.js?ds=sidebyside diff --git a/src/Component.js b/src/Component.js new file mode 100644 index 00000000..30aa2e55 --- /dev/null +++ b/src/Component.js @@ -0,0 +1,1031 @@ +/** + * @class Ext.Component + * @extends Ext.AbstractComponent + *
Base class for all Ext components. All subclasses of Component may participate in the automated + * Ext component lifecycle of creation, rendering and destruction which is provided by the {@link Ext.container.Container Container} class. + * Components may be added to a Container through the {@link Ext.container.Container#items items} config option at the time the Container is created, + * or they may be added dynamically via the {@link Ext.container.Container#add add} method.
+ *The Component base class has built-in support for basic hide/show and enable/disable and size control behavior.
+ *All Components are registered with the {@link Ext.ComponentManager} on construction so that they can be referenced at any time via + * {@link Ext#getCmp Ext.getCmp}, passing the {@link #id}.
+ *All user-developed visual widgets that are required to participate in automated lifecycle and size management should subclass Component.
+ *See the Creating new UI controls tutorial for details on how + * and to either extend or augment ExtJs base classes to create custom Components.
+ *Every component has a specific xtype, which is its Ext-specific type name, along with methods for checking the + * xtype like {@link #getXType} and {@link #isXType}. This is the list of all valid xtypes:
+ *+xtype Class +------------- ------------------ +button {@link Ext.button.Button} +buttongroup {@link Ext.container.ButtonGroup} +colorpalette {@link Ext.picker.Color} +component {@link Ext.Component} +container {@link Ext.container.Container} +cycle {@link Ext.button.Cycle} +dataview {@link Ext.view.View} +datepicker {@link Ext.picker.Date} +editor {@link Ext.Editor} +editorgrid {@link Ext.grid.plugin.Editing} +grid {@link Ext.grid.Panel} +multislider {@link Ext.slider.Multi} +panel {@link Ext.panel.Panel} +progress {@link Ext.ProgressBar} +slider {@link Ext.slider.Single} +spacer {@link Ext.toolbar.Spacer} +splitbutton {@link Ext.button.Split} +tabpanel {@link Ext.tab.Panel} +treepanel {@link Ext.tree.Panel} +viewport {@link Ext.container.Viewport} +window {@link Ext.window.Window} + +Toolbar components +--------------------------------------- +paging {@link Ext.toolbar.Paging} +toolbar {@link Ext.toolbar.Toolbar} +tbfill {@link Ext.toolbar.Fill} +tbitem {@link Ext.toolbar.Item} +tbseparator {@link Ext.toolbar.Separator} +tbspacer {@link Ext.toolbar.Spacer} +tbtext {@link Ext.toolbar.TextItem} + +Menu components +--------------------------------------- +menu {@link Ext.menu.Menu} +menucheckitem {@link Ext.menu.CheckItem} +menuitem {@link Ext.menu.Item} +menuseparator {@link Ext.menu.Separator} +menutextitem {@link Ext.menu.Item} + +Form components +--------------------------------------- +form {@link Ext.form.Panel} +checkbox {@link Ext.form.field.Checkbox} +combo {@link Ext.form.field.ComboBox} +datefield {@link Ext.form.field.Date} +displayfield {@link Ext.form.field.Display} +field {@link Ext.form.field.Base} +fieldset {@link Ext.form.FieldSet} +hidden {@link Ext.form.field.Hidden} +htmleditor {@link Ext.form.field.HtmlEditor} +label {@link Ext.form.Label} +numberfield {@link Ext.form.field.Number} +radio {@link Ext.form.field.Radio} +radiogroup {@link Ext.form.RadioGroup} +textarea {@link Ext.form.field.TextArea} +textfield {@link Ext.form.field.Text} +timefield {@link Ext.form.field.Time} +trigger {@link Ext.form.field.Trigger} + +Chart components +--------------------------------------- +chart {@link Ext.chart.Chart} +barchart {@link Ext.chart.series.Bar} +columnchart {@link Ext.chart.series.Column} +linechart {@link Ext.chart.series.Line} +piechart {@link Ext.chart.series.Pie} + +
+ * It should not usually be necessary to instantiate a Component because there are provided subclasses which implement specialized Component + * use cases which over most application needs. However it is possible to instantiate a base Component, and it will be renderable, + * or will particpate in layouts as the child item of a Container: +{@img Ext.Component/Ext.Component.png Ext.Component component} +
+ Ext.create('Ext.Component', {
+ html: 'Hello world!',
+ width: 300,
+ height: 200,
+ padding: 20,
+ style: {
+ color: '#FFFFFF',
+ backgroundColor:'#000000'
+ },
+ renderTo: Ext.getBody()
+ });
+
+ *
+ *The Component above creates its encapsulating div
upon render, and use the configured HTML as content. More complex
+ * internal structure may be created using the {@link #renderTpl} configuration, although to display database-derived mass
+ * data, it is recommended that an ExtJS data-backed Component such as a {Ext.view.DataView DataView}, or {Ext.grid.Panel GridPanel},
+ * or {@link Ext.tree.Panel TreePanel} be used.
it is set as the internal element and its id used as the component id
it is assumed to be the id of an existing element and is used as the component id
it is assumed to be a standard config object and is applied to the component
Specify as true
to apply a {@link Ext.resizer.Resizer Resizer} to this Component
+ * after rendering.
May also be specified as a config object to be passed to the constructor of {@link Ext.resizer.Resizer Resizer}
+ * to override any defaults. By default the Component passes its minimum and maximum size, and uses
+ * {@link Ext.resizer.Resizer#dynamic}: false
true
to use overflow:'auto' on the components layout element and show scroll bars automatically when
+ * necessary, false
to clip any overflowing content (defaults to false
).
+ */
+
+ /**
+ * @cfg {Boolean} floating
+ * Specify as true to float the Component outside of the document flow using CSS absolute positioning.
+ *Components such as {@link Ext.window.Window Window}s and {@link Ext.menu.Menu Menu}s are floating + * by default.
+ *Floating Components that are programatically {@link Ext.Component#render rendered} will register themselves with the global + * {@link Ext.WindowManager ZIndexManager}
+ *A floating Component may be used as a child item of a Container. This just allows the floating Component to seek a ZIndexManager by + * examining the ownerCt chain.
+ *When configured as floating, Components acquire, at render time, a {@link Ext.ZIndexManager ZIndexManager} which manages a stack + * of related floating Components. The ZIndexManager brings a single floating Component to the top of its stack when + * the Component's {@link #toFront} method is called.
+ *The ZIndexManager is found by traversing up the {@link #ownerCt} chain to find an ancestor which itself is floating. This is so that + * descendant floating Components of floating Containers (Such as a ComboBox dropdown within a Window) can have its zIndex managed relative + * to any siblings, but always above that floating ancestor Container.
+ *If no floating ancestor is found, a floating Component registers itself with the default {@link Ext.WindowManager ZIndexManager}.
+ *Floating components do not participate in the Container's layout. Because of this, they are not rendered until you explicitly + * {@link #show} them.
+ *After rendering, the ownerCt reference is deleted, and the {@link #floatParent} property is set to the found floating ancestor Container. + * If no floating ancestor Container was found the {@link #floatParent} property will not be set.
+ */ + floating: false, + + /** + * @cfg {Boolean} toFrontOnShow + *True to automatically call {@link #toFront} when the {@link #show} method is called
+ * on an already visible, floating component (default is true
).
Optional. Only present for {@link #floating} Components after they have been rendered.
+ *A reference to the ZIndexManager which is managing this Component's z-index.
+ *The {@link Ext.ZIndexManager ZIndexManager} maintains a stack of floating Component z-indices, and also provides a single modal + * mask which is insert just beneath the topmost visible modal floating Component.
+ *Floating Components may be {@link #toFront brought to the front} or {@link #toBack sent to the back} of the z-index stack.
+ *This defaults to the global {@link Ext.WindowManager ZIndexManager} for floating Components that are programatically + * {@link Ext.Component#render rendered}.
+ *For {@link #floating} Components which are added to a Container, the ZIndexManager is acquired from the first ancestor Container found + * which is floating, or if not found the global {@link Ext.WindowManager ZIndexManager} is used.
+ *See {@link #floating} and {@link #floatParent}
+ * @property zIndexManager + * @type Ext.ZIndexManager + */ + + /** + *Optional. Only present for {@link #floating} Components which were inserted as descendant items of floating Containers.
+ *Floating Components that are programatically {@link Ext.Component#render rendered} will not have a floatParent
property.
For {@link #floating} Components which are child items of a Container, the floatParent will be the floating ancestor Container which is + * responsible for the base z-index value of all its floating descendants. It provides a {@link Ext.ZIndexManager ZIndexManager} which provides + * z-indexing services for all its descendant floating Components.
+ *For example, the dropdown {@link Ext.view.BoundList BoundList} of a ComboBox which is in a Window will have the Window as its
+ * floatParent
See {@link #floating} and {@link #zIndexManager}
+ * @property floatParent + * @type Ext.Container + */ + + /** + * @cfg {Mixed} draggable + *Specify as true to make a {@link #floating} Component draggable using the Component's encapsulating element as the drag handle.
+ *This may also be specified as a config object for the {@link Ext.util.ComponentDragger ComponentDragger} which is instantiated to perform dragging.
+ *For example to create a Component which may only be dragged around using a certain internal element as the drag handle, + * use the delegate option:
+ *
+new Ext.Component({
+ constrain: true,
+ floating:true,
+ style: {
+ backgroundColor: '#fff',
+ border: '1px solid black'
+ },
+ html: '<h1 style="cursor:move">The title</h1><p>The content</p>',
+ draggable: {
+ delegate: 'h1'
+ }
+}).show();
+
+ */
+
+ /**
+ * @cfg {Boolean} maintainFlex
+ * Only valid when a sibling element of a {@link Ext.resizer.Splitter Splitter} within a {@link Ext.layout.container.VBox VBox} or + * {@link Ext.layout.container.HBox HBox} layout.
+ *Specifies that if an immediate sibling Splitter is moved, the Component on the other side is resized, and this + * Component maintains its configured {@link Ext.layout.container.Box#flex flex} value.
+ */ + + hideMode: 'display', + // Deprecate 5.0 + hideParent: false, + + ariaRole: 'presentation', + + bubbleEvents: [], + + actionMode: 'el', + monPropRe: /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/, + + //renderTpl: new Ext.XTemplate( + // 'Shows this Component, rendering it first if {@link #autoRender} or {{@link "floating} are true
.
After being shown, a {@link #floating} Component (such as a {@link Ext.window.Window}), is activated it and brought to the front of + * its {@link #ZIndexManager z-index stack}.
+ * @param {String/Element} animateTarget Optional, and only valid for {@link #floating} Components such as + * {@link Ext.window.Window Window}s or {@link Ext.tip.ToolTip ToolTip}s, or regular Components which have been configured + * withfloating: true
. The target from which the Component should
+ * animate from while opening (defaults to null with no animation)
+ * @param {Function} callback (optional) A callback function to call after the Component is displayed. Only necessary if animation was specified.
+ * @param {Object} scope (optional) The scope (this
reference) in which the callback is executed. Defaults to this Component.
+ * @return {Component} this
+ */
+ show: function(animateTarget, cb, scope) {
+ if (this.rendered && this.isVisible()) {
+ if (this.toFrontOnShow && this.floating) {
+ this.toFront();
+ }
+ } else if (this.fireEvent('beforeshow', this) !== false) {
+ this.hidden = false;
+
+ // Render on first show if there is an autoRender config, or if this is a floater (Window, Menu, BoundList etc).
+ if (!this.rendered && (this.autoRender || this.floating)) {
+ this.doAutoRender();
+ }
+ if (this.rendered) {
+ this.beforeShow();
+ this.onShow.apply(this, arguments);
+
+ // Notify any owning Container unless it's suspended.
+ // Floating Components do not participate in layouts.
+ if (this.ownerCt && !this.floating && !(this.ownerCt.suspendLayout || this.ownerCt.layout.layoutBusy)) {
+ this.ownerCt.doLayout();
+ }
+ this.afterShow.apply(this, arguments);
+ }
+ }
+ return this;
+ },
+
+ beforeShow: Ext.emptyFn,
+
+ // Private. Override in subclasses where more complex behaviour is needed.
+ onShow: function() {
+ var me = this;
+
+ me.el.show();
+ if (this.floating && this.constrain) {
+ this.doConstrain();
+ }
+ me.callParent(arguments);
+ },
+
+ afterShow: function(animateTarget, cb, scope) {
+ var me = this,
+ fromBox,
+ toBox,
+ ghostPanel;
+
+ // Default to configured animate target if none passed
+ animateTarget = animateTarget || me.animateTarget;
+
+ // Need to be able to ghost the Component
+ if (!me.ghost) {
+ animateTarget = null;
+ }
+ // If we're animating, kick of an animation of the ghost from the target to the *Element* current box
+ if (animateTarget) {
+ animateTarget = animateTarget.el ? animateTarget.el : Ext.get(animateTarget);
+ toBox = me.el.getBox();
+ fromBox = animateTarget.getBox();
+ fromBox.width += 'px';
+ fromBox.height += 'px';
+ toBox.width += 'px';
+ toBox.height += 'px';
+ me.el.addCls(Ext.baseCSSPrefix + 'hide-offsets');
+ ghostPanel = me.ghost();
+ ghostPanel.el.stopAnimation();
+
+ ghostPanel.el.animate({
+ from: fromBox,
+ to: toBox,
+ listeners: {
+ afteranimate: function() {
+ delete ghostPanel.componentLayout.lastComponentSize;
+ me.unghost();
+ me.el.removeCls(Ext.baseCSSPrefix + 'hide-offsets');
+ if (me.floating) {
+ me.toFront();
+ }
+ Ext.callback(cb, scope || me);
+ }
+ }
+ });
+ }
+ else {
+ if (me.floating) {
+ me.toFront();
+ }
+ Ext.callback(cb, scope || me);
+ }
+ me.fireEvent('show', me);
+ },
+
+ /**
+ * Hides this Component, setting it to invisible using the configured {@link #hideMode}.
+ * @param {String/Element/Component} animateTarget Optional, and only valid for {@link #floating} Components such as
+ * {@link Ext.window.Window Window}s or {@link Ext.tip.ToolTip ToolTip}s, or regular Components which have been configured
+ * with floating: true
..
+ * The target to which the Component should animate while hiding (defaults to null with no animation)
+ * @param {Function} callback (optional) A callback function to call after the Component is hidden.
+ * @param {Object} scope (optional) The scope (this
reference) in which the callback is executed. Defaults to this Component.
+ * @return {Ext.Component} this
+ */
+ hide: function() {
+
+ // Clear the flag which is set if a floatParent was hidden while this is visible.
+ // If a hide operation was subsequently called, that pending show must be hidden.
+ this.showOnParentShow = false;
+
+ if (!(this.rendered && !this.isVisible()) && this.fireEvent('beforehide', this) !== false) {
+ this.hidden = true;
+ if (this.rendered) {
+ this.onHide.apply(this, arguments);
+
+ // Notify any owning Container unless it's suspended.
+ // Floating Components do not participate in layouts.
+ if (this.ownerCt && !this.floating && !(this.ownerCt.suspendLayout || this.ownerCt.layout.layoutBusy)) {
+ this.ownerCt.doLayout();
+ }
+ }
+ }
+ return this;
+ },
+
+ // Possibly animate down to a target element.
+ onHide: function(animateTarget, cb, scope) {
+ var me = this,
+ ghostPanel,
+ toBox;
+
+ // Default to configured animate target if none passed
+ animateTarget = animateTarget || me.animateTarget;
+
+ // Need to be able to ghost the Component
+ if (!me.ghost) {
+ animateTarget = null;
+ }
+ // If we're animating, kick off an animation of the ghost down to the target
+ if (animateTarget) {
+ animateTarget = animateTarget.el ? animateTarget.el : Ext.get(animateTarget);
+ ghostPanel = me.ghost();
+ ghostPanel.el.stopAnimation();
+ toBox = animateTarget.getBox();
+ toBox.width += 'px';
+ toBox.height += 'px';
+ ghostPanel.el.animate({
+ to: toBox,
+ listeners: {
+ afteranimate: function() {
+ delete ghostPanel.componentLayout.lastComponentSize;
+ ghostPanel.el.hide();
+ me.afterHide(cb, scope);
+ }
+ }
+ });
+ }
+ me.el.hide();
+ if (!animateTarget) {
+ me.afterHide(cb, scope);
+ }
+ },
+
+ afterHide: function(cb, scope) {
+ Ext.callback(cb, scope || this);
+ this.fireEvent('hide', this);
+ },
+
+ /**
+ * @private
+ * Template method to contribute functionality at destroy time.
+ */
+ onDestroy: function() {
+ var me = this;
+
+ // Ensure that any ancillary components are destroyed.
+ if (me.rendered) {
+ Ext.destroy(
+ me.proxy,
+ me.resizer
+ );
+ // Different from AbstractComponent
+ if (me.actionMode == 'container' || me.removeMode == 'container') {
+ me.container.remove();
+ }
+ }
+ me.callParent();
+ },
+
+ deleteMembers: function() {
+ var args = arguments,
+ len = args.length,
+ i = 0;
+ for (; i < len; ++i) {
+ delete this[args[i]];
+ }
+ },
+
+ /**
+ * Try to focus this component.
+ * @param {Boolean} selectText (optional) If applicable, true to also select the text in this component
+ * @param {Boolean/Number} delay (optional) Delay the focus this number of milliseconds (true for 10 milliseconds).
+ * @return {Ext.Component} this
+ */
+ focus: function(selectText, delay) {
+ var me = this,
+ focusEl;
+
+ if (delay) {
+ me.focusTask.delay(Ext.isNumber(delay) ? delay: 10, null, me, [selectText, false]);
+ return me;
+ }
+
+ if (me.rendered && !me.isDestroyed) {
+ // getFocusEl could return a Component.
+ focusEl = me.getFocusEl();
+ focusEl.focus();
+ if (focusEl.dom && selectText === true) {
+ focusEl.dom.select();
+ }
+
+ // Focusing a floating Component brings it to the front of its stack.
+ // this is performed by its zIndexManager. Pass preventFocus true to avoid recursion.
+ if (me.floating) {
+ me.toFront(true);
+ }
+ }
+ return me;
+ },
+
+ /**
+ * @private
+ * Returns the focus holder element associated with this Component. By default, this is the Component's encapsulating
+ * element. Subclasses which use embedded focusable elements (such as Window and Button) should override this for use
+ * by the {@link #focus} method.
+ * @returns {Ext.core.Element} the focus holing element.
+ */
+ getFocusEl: function() {
+ return this.el;
+ },
+
+ // private
+ blur: function() {
+ if (this.rendered) {
+ this.getFocusEl().blur();
+ }
+ return this;
+ },
+
+ getEl: function() {
+ return this.el;
+ },
+
+ // Deprecate 5.0
+ getResizeEl: function() {
+ return this.el;
+ },
+
+ // Deprecate 5.0
+ getPositionEl: function() {
+ return this.el;
+ },
+
+ // Deprecate 5.0
+ getActionEl: function() {
+ return this.el;
+ },
+
+ // Deprecate 5.0
+ getVisibilityEl: function() {
+ return this.el;
+ },
+
+ // Deprecate 5.0
+ onResize: Ext.emptyFn,
+
+ // private
+ getBubbleTarget: function() {
+ return this.ownerCt;
+ },
+
+ // private
+ getContentTarget: function() {
+ return this.el;
+ },
+
+ /**
+ * Clone the current component using the original config values passed into this instance by default.
+ * @param {Object} overrides A new config containing any properties to override in the cloned version.
+ * An id property can be passed on this object, otherwise one will be generated to avoid duplicates.
+ * @return {Ext.Component} clone The cloned copy of this component
+ */
+ cloneConfig: function(overrides) {
+ overrides = overrides || {};
+ var id = overrides.id || Ext.id();
+ var cfg = Ext.applyIf(overrides, this.initialConfig);
+ cfg.id = id;
+
+ var self = Ext.getClass(this);
+
+ // prevent dup id
+ return new self(cfg);
+ },
+
+ /**
+ * Gets the xtype for this component as registered with {@link Ext.ComponentManager}. For a list of all
+ * available xtypes, see the {@link Ext.Component} header. Example usage:
+ *
+var t = new Ext.form.field.Text();
+alert(t.getXType()); // alerts 'textfield'
+
+ * @return {String} The xtype
+ */
+ getXType: function() {
+ return this.self.xtype;
+ },
+
+ /**
+ * Find a container above this component at any level by a custom function. If the passed function returns
+ * true, the container will be returned.
+ * @param {Function} fn The custom function to call with the arguments (container, this component).
+ * @return {Ext.container.Container} The first Container for which the custom function returns true
+ */
+ findParentBy: function(fn) {
+ var p;
+
+ // Iterate up the ownerCt chain until there's no ownerCt, or we find an ancestor which matches using the selector function.
+ for (p = this.ownerCt; p && !fn(p, this); p = p.ownerCt);
+ return p || null;
+ },
+
+ /**
+ * Find a container above this component at any level by xtype or class
+ *See also the {@link Ext.Component#up up} method.
+ * @param {String/Class} xtype The xtype string for a component, or the class of the component directly + * @return {Ext.container.Container} The first Container which matches the given xtype or class + */ + findParentByType: function(xtype) { + return Ext.isFunction(xtype) ? + this.findParentBy(function(p) { + return p.constructor === xtype; + }) + : + this.up(xtype); + }, + + /** + * Bubbles up the component/container heirarchy, calling the specified function with each component. The scope (this) of + * function call will be the scope provided or the current component. The arguments to the function + * will be the args provided or the current component. If the function returns false at any point, + * the bubble is stopped. + * @param {Function} fn The function to call + * @param {Object} scope (optional) The scope of the function (defaults to current node) + * @param {Array} args (optional) The args to call the function with (default to passing the current component) + * @return {Ext.Component} this + */ + bubble: function(fn, scope, args) { + var p = this; + while (p) { + if (fn.apply(scope || p, args || [p]) === false) { + break; + } + p = p.ownerCt; + } + return this; + }, + + getProxy: function() { + if (!this.proxy) { + this.proxy = this.el.createProxy(Ext.baseCSSPrefix + 'proxy-el', Ext.getBody(), true); + } + return this.proxy; + } + +}, function() { + + // A single focus delayer for all Components. + this.prototype.focusTask = Ext.create('Ext.util.DelayedTask', this.prototype.focus); + +});