X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/7a654f8d43fdb43d78b63d90528bed6e86b608cc..6746dc89c47ed01b165cc1152533605f97eb8e8d:/src/AbstractComponent.js diff --git a/src/AbstractComponent.js b/src/AbstractComponent.js index a51c936a..48915877 100644 --- a/src/AbstractComponent.js +++ b/src/AbstractComponent.js @@ -1,8 +1,21 @@ +/* + +This file is part of Ext JS 4 + +Copyright (c) 2011 Sencha Inc + +Contact: http://www.sencha.com/contact + +GNU General Public License Usage +This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html. + +If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact. + +*/ /** * @class Ext.AbstractComponent *
An abstract base class which provides shared methods for Components across the Sencha product line.
*Please refer to sub class's documentation
- * @constructor */ Ext.define('Ext.AbstractComponent', { @@ -47,6 +60,7 @@ Ext.define('Ext.AbstractComponent', { return ++Ext.AbstractComponent.AUTO_ID; }, + /** * @cfg {String} id *The unique id of this component instance (defaults to an {@link #getId auto-assigned id}).
@@ -94,7 +108,8 @@ var c = new Ext.panel.Panel({ // 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 #query}
, {@link #down}
and {@link #child}
.
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}.
*/ @@ -106,6 +121,26 @@ p2 = p1.{@link #ownerCt}.{@link Ext.container.Container#getComponent getComponen * @property ownerCt */ + /** + * @private + * Flag set by the container layout to which this Component is added. + * If the layout manages this Component's width, it sets the value to 1. + * If it does NOT manage the width, it sets it to 2. + * If the layout MAY affect the width, but only if the owning Container has a fixed width, this is set to 0. + * @type boolean + * @property layoutManagedWidth + */ + + /** + * @private + * Flag set by the container layout to which this Component is added. + * If the layout manages this Component's height, it sets the value to 1. + * If it does NOT manage the height, it sets it to 2. + * If the layout MAY affect the height, but only if the owning Container has a fixed height, this is set to 0. + * @type boolean + * @property layoutManagedHeight + */ + /** * @cfg {Mixed} autoEl *A tag name or {@link Ext.core.DomHelper DomHelper} spec used to create the {@link #getEl Element} which will
@@ -289,14 +324,14 @@ and a property `descEl` referencing the `div` Element which contains the descrip
* A set style for a component. Can be a string or an Array of multiple strings (UIs)
*/
ui: 'default',
-
+
/**
* @cfg {Array} uiCls
* An array of of classNames which are currently applied to this component
* @private
*/
uiCls: [],
-
+
/**
* @cfg {String} style
* A custom style specification to be applied to this component's Element. Should be a valid argument to
@@ -425,7 +460,7 @@ and a property `descEl` referencing the `div` Element which contains the descrip
*/
/**
- * @cfg {String} styleHtmlContent
+ * @cfg {Boolean} styleHtmlContent
* True to automatically style the html inside the content target of this component (body for panels).
* Defaults to false.
*/
@@ -508,8 +543,8 @@ and a property `descEl` referencing the `div` Element which contains the descrip
trimRe: /^\s+|\s+$/g,
spacesRe: /\s+/,
-
-
+
+
/**
* 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.
@@ -517,9 +552,13 @@ and a property `descEl` referencing the `div` Element which contains the descrip
* since they want to implement custom disable logic.
* @property maskOnDisable
* @type {Boolean}
- */
+ */
maskOnDisable: true,
+ /**
+ * Creates new Component.
+ * @param {Object} config (optional) Config object.
+ */
constructor : function(config) {
var me = this,
i, len;
@@ -675,7 +714,7 @@ and a property `descEl` referencing the `div` Element which contains the descrip
me.plugins[i] = me.constructPlugin(me.plugins[i]);
}
}
-
+
me.initComponent();
// ititComponent gets a chance to change the id property before registering
@@ -685,6 +724,9 @@ and a property `descEl` referencing the `div` Element which contains the descrip
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);
@@ -697,12 +739,15 @@ and a property `descEl` referencing the `div` Element which contains the descrip
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();
}
-
+
//
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.
+ */ + getState: function() { + var me = this, + layout = me.ownerCt ? (me.shadowOwnerCt || me.ownerCt).getLayout() : null, + state = { + collapsed: me.collapsed + }, + width = me.width, + height = me.height, + cm = me.collapseMemento, + anchors; + + // If a Panel-local collapse has taken place, use remembered values as the dimensions. + // TODO: remove this coupling with Panel's privates! All collapse/expand logic should be refactored into one place. + if (me.collapsed && cm) { + if (Ext.isDefined(cm.data.width)) { + width = cm.width; + } + if (Ext.isDefined(cm.data.height)) { + height = cm.height; + } + } + + // If we have flex, only store the perpendicular dimension. + if (layout && me.flex) { + state.flex = me.flex; + state[layout.perpendicularPrefix] = me['get' + layout.perpendicularPrefixCap](); + } + // If we have anchor, only store dimensions which are *not* being anchored + else if (layout && me.anchor) { + state.anchor = me.anchor; + anchors = me.anchor.split(' ').concat(null); + if (!anchors[0]) { + if (me.width) { + state.width = width; + } + } + if (!anchors[1]) { + if (me.height) { + state.height = height; + } + } + } + // Store dimensions. + else { + if (me.width) { + state.width = width; + } + if (me.height) { + state.height = height; + } + } + + // Don't save dimensions if they are unchanged from the original configuration. + if (state.width == me.initialConfig.width) { + delete state.width; + } + if (state.height == me.initialConfig.height) { + delete state.height; + } + + // If a Box layout was managing the perpendicular dimension, don't save that dimension + if (layout && layout.align && (layout.align.indexOf('stretch') !== -1)) { + delete state[layout.perpendicularPrefix]; + } + return state; + }, + show: Ext.emptyFn, animate: function(animObj) { @@ -803,7 +924,6 @@ and a property `descEl` referencing the `div` Element which contains the descrip return plugin; }, - // @private initPlugin : function(plugin) { plugin.init(this); @@ -881,7 +1001,6 @@ and a property `descEl` referencing the `div` Element which contains the descrip onRender : function(container, position) { var me = this, el = me.el, - cls = me.initCls(), styles = me.initStyles(), renderTpl, renderData, i; @@ -916,7 +1035,9 @@ and a property `descEl` referencing the `div` Element which contains the descrip } } - el.addCls(cls); + me.setUI(me.ui); + + el.addCls(me.initCls()); el.setStyle(styles); // Here we check if the component has a height set through style or css. @@ -931,14 +1052,7 @@ and a property `descEl` referencing the `div` Element which contains the descrip // } me.el = el; - - me.rendered = true; - me.addUIToElement(true); - //loop through all exisiting uiCls and update the ui in them - for (i = 0; i < me.uiCls.length; i++) { - me.addUIClsToElement(me.uiCls[i], true); - } - me.rendered = false; + me.initFrame(); renderTpl = me.initRenderTpl(); @@ -948,10 +1062,8 @@ and a property `descEl` referencing the `div` Element which contains the descrip } me.applyRenderSelectors(); - + me.rendered = true; - - me.setUI(me.ui); }, // @private @@ -968,7 +1080,7 @@ and a property `descEl` referencing the `div` Element which contains the descrip } // For floaters, calculate x and y if they aren't defined by aligning - // the sized element to the center of either the the container or the ownerCt + // the sized element to the center of either the container or the ownerCt if (me.floating && (me.x === undefined || me.y === undefined)) { if (me.floatParent) { xy = me.el.getAlignToXY(me.floatParent.getTargetEl(), 'c-c'); @@ -992,6 +1104,18 @@ and a property `descEl` referencing the `div` Element which contains the descrip frameCls: Ext.baseCSSPrefix + 'frame', + frameElementCls: { + tl: [], + tc: [], + tr: [], + ml: [], + mc: [], + mr: [], + bl: [], + bc: [], + br: [] + }, + frameTpl: [ '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 #pnextSibling}.
+ * walk the tree to attempt to find a match. Contrast with {@link #nextSibling}. * @param {String} selector Optional A {@link Ext.ComponentQuery ComponentQuery} selector to filter the following nodes. * @returns The next node (or the next node which matches the selector). Returns null if there is no matching node. */ @@ -2091,12 +2278,12 @@ alert(t.getXTypes()); // alerts 'component/field/textfield' return me; }, - + // @private onEnable: function() { if (this.maskOnDisable) { this.el.unmask(); - } + } }, // @private @@ -2105,7 +2292,7 @@ alert(t.getXTypes()); // alerts 'component/field/textfield' this.el.mask(); } }, - + /** * Method to determine whether this Component is currently disabled. * @return {Boolean} the disabled state of this Component. @@ -2153,7 +2340,7 @@ alert(t.getXTypes()); // alerts 'component/field/textfield' }, /** - * @deprecated 4.0 Replaced by {link:#addCls} + * @deprecated 4.0 Replaced by {@link #addCls} * Adds a CSS class to the top level element representing this component. * @param {String} cls The CSS class name to add * @return {Ext.Component} Returns the Component to allow method chaining. @@ -2237,14 +2424,35 @@ alert(t.getXTypes()); // alerts 'component/field/textfield' me.mon(me[element], listeners); } else { me.afterRenderEvents = me.afterRenderEvents || {}; - me.afterRenderEvents[element] = listeners; + if (!me.afterRenderEvents[element]) { + me.afterRenderEvents[element] = []; + } + me.afterRenderEvents[element].push(listeners); } } return me.mixins.observable.addListener.apply(me, arguments); }, - // @TODO: implement removelistener to support the dom event stuff + // 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. @@ -2368,13 +2576,39 @@ alert(t.getXTypes()); // alerts 'component/field/textfield' return me; }, - setCalculatedSize : function(width, height, ownerCt) { + isFixedWidth: function() { + var me = this, + layoutManagedWidth = me.layoutManagedWidth; + + if (Ext.isDefined(me.width) || layoutManagedWidth == 1) { + return true; + } + if (layoutManagedWidth == 2) { + return false; + } + return (me.ownerCt && me.ownerCt.isFixedWidth()); + }, + + isFixedHeight: function() { + var me = this, + layoutManagedHeight = me.layoutManagedHeight; + + if (Ext.isDefined(me.height) || layoutManagedHeight == 1) { + return true; + } + if (layoutManagedHeight == 2) { + return false; + } + return (me.ownerCt && me.ownerCt.isFixedHeight()); + }, + + setCalculatedSize : function(width, height, callingContainer) { var me = this, layoutCollection; // support for standard size objects if (Ext.isObject(width)) { - ownerCt = width.ownerCt; + callingContainer = width.ownerCt; height = width.height; width = width.width; } @@ -2398,11 +2632,11 @@ alert(t.getXTypes()); // alerts 'component/field/textfield' width: width, height: height, isSetSize: false, - ownerCt: ownerCt + ownerCt: callingContainer }; return me; } - me.doComponentLayout(width, height, false, ownerCt); + me.doComponentLayout(width, height, false, callingContainer); return me; }, @@ -2412,26 +2646,51 @@ alert(t.getXTypes()); // alerts 'component/field/textfield' * layout to be recalculated. * @return {Ext.container.Container} this */ - doComponentLayout : function(width, height, isSetSize, ownerCt) { + doComponentLayout : function(width, height, isSetSize, callingContainer) { var me = this, - componentLayout = me.getComponentLayout(); + componentLayout = me.getComponentLayout(), + lastComponentSize = componentLayout.lastComponentSize || { + width: undefined, + height: undefined + }; // collapsed state is not relevant here, so no testing done. // Only Panels have a collapse method, and that just sets the width/height such that only // a single docked Header parallel to the collapseTo side are visible, and the Panel body is hidden. if (me.rendered && componentLayout) { - width = (width !== undefined) ? width : me.width; - height = (height !== undefined) ? height : me.height; + + + // If no width passed, then only insert a value if the Component is NOT ALLOWED to autowidth itself. + if (!Ext.isDefined(width)) { + if (me.isFixedWidth()) { + width = Ext.isDefined(me.width) ? me.width : lastComponentSize.width; + } + } + + // If no height passed, then only insert a value if the Component is NOT ALLOWED to autoheight itself. + if (!Ext.isDefined(height)) { + if (me.isFixedHeight()) { + height = Ext.isDefined(me.height) ? me.height : lastComponentSize.height; + } + } + if (isSetSize) { me.width = width; me.height = height; } - componentLayout.layout(width, height, isSetSize, ownerCt); + componentLayout.layout(width, height, isSetSize, callingContainer); } return me; }, + /** + * Forces this component to redo its componentLayout. + */ + forceComponentLayout: function () { + this.doComponentLayout(); + }, + // @private setComponentLayout : function(layout) { var currentLayout = this.componentLayout; @@ -2455,9 +2714,9 @@ alert(t.getXTypes()); // alerts 'component/field/textfield' * @param {Number} adjWidth The box-adjusted width that was set * @param {Number} adjHeight The box-adjusted height that was set * @param {Boolean} isSetSize Whether or not the height/width are stored on the component permanently - * @param {Ext.Component} layoutOwner Component which sent the layout. Only used when isSetSize is false. + * @param {Ext.Component} callingContainer Container requesting the layout. Only used when isSetSize is false. */ - afterComponentLayout: function(width, height, isSetSize, layoutOwner) { + afterComponentLayout: function(width, height, isSetSize, callingContainer) { this.fireEvent('resize', this, width, height); }, @@ -2467,14 +2726,15 @@ alert(t.getXTypes()); // alerts 'component/field/textfield' * @param {Number} adjWidth The box-adjusted width that was set * @param {Number} adjHeight The box-adjusted height that was set * @param {Boolean} isSetSize Whether or not the height/width are stored on the component permanently - * @param {Ext.Component} layoutOwner Component which sent the layout. Only used when isSetSize is false. + * @param {Ext.Component} callingContainer Container requesting sent the layout. Only used when isSetSize is false. */ - beforeComponentLayout: function(width, height, isSetSize, layoutOwner) { + beforeComponentLayout: function(width, height, isSetSize, callingContainer) { return true; }, /** - * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}. + * Sets the left and top of the component. To set the page XY position instead, use + * {@link Ext.Component#setPagePosition setPagePosition}. * This method fires the {@link #move} event. * @param {Number} left The new left * @param {Number} top The new top @@ -2664,15 +2924,15 @@ alert(t.getXTypes()); // alerts 'component/field/textfield' me.ownerCt.remove(me, false); } - if (me.rendered) { - me.el.remove(); - } - me.onDestroy(); // Attempt to destroy all plugins Ext.destroy(me.plugins); + if (me.rendered) { + me.el.remove(); + } + Ext.ComponentManager.unregister(me); me.fireEvent('destroy', me); @@ -2700,7 +2960,7 @@ alert(t.getXTypes()); // alerts 'component/field/textfield' } } }, - + /** * Determines whether this component is the descendant of a particular container. * @param {Ext.Container} container @@ -2718,3 +2978,4 @@ alert(t.getXTypes()); // alerts 'component/field/textfield' next: 'nextSibling' }); }); +