X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/25ef3491bd9ae007ff1fc2b0d7943e6eaaccf775..6b044c28b5f26fb99c86c237ffad19741c0f7f3d:/src/widgets/Component.js?ds=inline diff --git a/src/widgets/Component.js b/src/widgets/Component.js index 287e3c4b..e5dbf5af 100644 --- a/src/widgets/Component.js +++ b/src/widgets/Component.js @@ -1,8 +1,8 @@ /*! - * Ext JS Library 3.0.3 - * Copyright(c) 2006-2009 Ext JS, LLC - * licensing@extjs.com - * http://www.extjs.com/license + * Ext JS Library 3.3.1 + * Copyright(c) 2006-2010 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license */ /** * @class Ext.Component @@ -37,10 +37,11 @@ editorgrid {@link Ext.grid.EditorGridPanel} flash {@link Ext.FlashComponent} grid {@link Ext.grid.GridPanel} listview {@link Ext.ListView} +multislider {@link Ext.slider.MultiSlider} panel {@link Ext.Panel} progress {@link Ext.ProgressBar} propertygrid {@link Ext.grid.PropertyGrid} -slider {@link Ext.Slider} +slider {@link Ext.slider.SingleSlider} spacer {@link Ext.Spacer} splitbutton {@link Ext.SplitButton} tabpanel {@link Ext.TabPanel} @@ -73,10 +74,11 @@ menutextitem {@link Ext.menu.TextItem} Form components --------------------------------------- -form {@link Ext.FormPanel} +form {@link Ext.form.FormPanel} checkbox {@link Ext.form.Checkbox} checkboxgroup {@link Ext.form.CheckboxGroup} combo {@link Ext.form.ComboBox} +compositefield {@link Ext.form.CompositeField} datefield {@link Ext.form.DateField} displayfield {@link Ext.form.DisplayField} field {@link Ext.form.Field} @@ -142,6 +144,14 @@ Ext.Component = function(config){ Ext.apply(this, config); this.addEvents( + /** + * @event added + * Fires when a component is added to an Ext.Container + * @param {Ext.Component} this + * @param {Ext.Container} ownerCt Container which holds the component + * @param {number} index Position at which the component was added + */ + 'added', /** * @event disable * Fires after the component is disabled. @@ -181,6 +191,13 @@ Ext.Component = function(config){ * @param {Ext.Component} this */ 'hide', + /** + * @event removed + * Fires when a component is removed from an Ext.Container + * @param {Ext.Component} this + * @param {Ext.Container} ownerCt Container which holds the component + */ + 'removed', /** * @event beforerender * Fires before the component is {@link #rendered}. Return false from an @@ -276,7 +293,7 @@ Ext.Component = function(config){ } if(this.stateful !== false){ - this.initState(config); + this.initState(); } if(this.applyTo){ @@ -425,17 +442,6 @@ new Ext.FormPanel({ */ - // Configs below are used for all Components when rendered by AnchorLayout. - /** - * @cfg {String} anchor
Note: this config is only used when this Component is rendered - * by a Container which has been configured to use an {@link Ext.layout.AnchorLayout AnchorLayout} - * based layout manager, for example:
layout: 'anchor' // or 'form', or 'absolute'
See {@link Ext.layout.AnchorLayout}.{@link Ext.layout.AnchorLayout#anchor anchor} also.
- */ - /** * @cfg {String} id *The unique id of this component (defaults to an {@link #getId auto-assigned id}). @@ -787,6 +793,61 @@ new Ext.Panel({ */ rendered : false, + /** + * @cfg {String} contentEl + *
Optional. Specify an existing HTML element, or the id
of an existing HTML element to use as the content
+ * for this component.
{@link Ext.Container#layout layout}
+ * scheme that the Component may use. It is just HTML. Layouts operate on child {@link Ext.Container#items items}
.x-hidden
or the x-hide-display
CSS class to
+ * prevent a brief flicker of the content before it is rendered to the panel.{@link #data}
and
+ * {@link #tplWriteMode}
configurations.
+ */
+
+ /**
+ * @cfg {String} tplWriteMode The Ext.(X)Template method to use when
+ * updating the content area of the Component. Defaults to 'overwrite'
+ * (see {@link Ext.XTemplate#overwrite}
).
+ */
+ tplWriteMode : 'overwrite',
+
+ /**
+ * @cfg {Mixed} data
+ * The initial set of data to apply to the {@link #tpl}
to
+ * update the content area of the Component.
+ */
+
+ /**
+ * @cfg {Array} bubbleEvents
+ * An array of events that, when fired, should be bubbled to any parent container. + * See {@link Ext.util.Observable#enableBubble}. + * Defaults to []. + */ + bubbleEvents: [], + + // private ctype : 'Ext.Component', @@ -839,7 +900,22 @@ Ext.Foo = Ext.extend(Ext.Bar, { } */ - initComponent : Ext.emptyFn, + initComponent : function(){ + /* + * this is double processing, however it allows people to be able to do + * Ext.apply(this, { + * listeners: { + * //here + * } + * }); + * MyClass.superclass.initComponent.call(this); + */ + if(this.listeners){ + this.on(this.listeners); + delete this.listeners; + } + this.enableBubble(this.bubbleEvents); + }, /** *
Render this Component into the passed HTML element.
@@ -902,7 +978,32 @@ Ext.Foo = Ext.extend(Ext.Bar, { this.el.addClassOnOver(this.overCls); } this.fireEvent('render', this); + + + // Populate content of the component with html, contentEl or + // a tpl. + var contentTarget = this.getContentTarget(); + if (this.html){ + contentTarget.update(Ext.DomHelper.markup(this.html)); + delete this.html; + } + if (this.contentEl){ + var ce = Ext.getDom(this.contentEl); + Ext.fly(ce).removeClass(['x-hidden', 'x-hide-display']); + contentTarget.appendChild(ce); + } + if (this.tpl) { + if (!this.tpl.compile) { + this.tpl = new Ext.XTemplate(this.tpl); + } + if (this.data) { + this.tpl[this.tplWriteMode](contentTarget, this.data); + delete this.data; + } + } this.afterRender(this.container); + + if(this.hidden){ // call this so we don't fire initial hide events. this.doHide(); @@ -915,17 +1016,70 @@ Ext.Foo = Ext.extend(Ext.Bar, { if(this.stateful !== false){ this.initStateEvents(); } - this.initRef(); this.fireEvent('afterrender', this); } return this; }, - initRef : function(){ + + /** + * Update the content area of a component. + * @param {Mixed} htmlOrData + * If this component has been configured with a template via the tpl config + * then it will use this argument as data to populate the template. + * If this component was not configured with a template, the components + * content area will be updated via Ext.Element update + * @param {Boolean} loadScripts + * (optional) Only legitimate when using the html configuration. Defaults to false + * @param {Function} callback + * (optional) Only legitimate when using the html configuration. Callback to execute when scripts have finished loading + */ + update: function(htmlOrData, loadScripts, cb) { + var contentTarget = this.getContentTarget(); + if (this.tpl && typeof htmlOrData !== "string") { + this.tpl[this.tplWriteMode](contentTarget, htmlOrData || {}); + } else { + var html = Ext.isObject(htmlOrData) ? Ext.DomHelper.markup(htmlOrData) : htmlOrData; + contentTarget.update(html, loadScripts, cb); + } + }, + + + /** + * @private + * Method to manage awareness of when components are added to their + * respective Container, firing an added event. + * References are established at add time rather than at render time. + * @param {Ext.Container} container Container which holds the component + * @param {number} pos Position at which the component was added + */ + onAdded : function(container, pos) { + this.ownerCt = container; + this.initRef(); + this.fireEvent('added', this, container, pos); + }, + + /** + * @private + * Method to manage awareness of when components are removed from their + * respective Container, firing an removed event. References are properly + * cleaned up after removing a component from its owning container. + */ + onRemoved : function() { + this.removeRef(); + this.fireEvent('removed', this, this.ownerCt); + delete this.ownerCt; + }, + + /** + * @private + * Method to establish a reference to a component. + */ + initRef : function() { /** * @cfg {String} ref - *A path specification, relative to the Component's {@link #ownerCt} specifying into which - * ancestor Container to place a named reference to this Component.
+ *A path specification, relative to the Component's {@link #ownerCt}
+ * specifying into which ancestor Container to place a named reference to this Component.
The ancestor axis can be traversed by using '/' characters in the path. * For example, to put a reference to a Toolbar Button into the Panel which owns the Toolbar:
var myGrid = new Ext.grid.EditorGridPanel({
@@ -946,33 +1100,50 @@ var myGrid = new Ext.grid.EditorGridPanel({
}
});
- * In the code above, if the ref had been 'saveButton'
the reference would
- * have been placed into the Toolbar. Each '/' in the ref moves up one level from the
- * Component's {@link #ownerCt}.
In the code above, if the ref
had been 'saveButton'
+ * the reference would have been placed into the Toolbar. Each '/' in the ref
+ * moves up one level from the Component's {@link #ownerCt}
.
Also see the {@link #added}
and {@link #removed}
events.
ref
.
+ */
+ this.refOwner = t;
}
- t[levels[--i]] = this;
+ }
+ },
+
+ removeRef : function() {
+ if (this.refOwner && this.refName) {
+ delete this.refOwner[this.refName];
+ delete this.refOwner;
}
},
// private
- initState : function(config){
+ initState : function(){
if(Ext.state.Manager){
var id = this.getStateId();
if(id){
var state = Ext.state.Manager.get(id);
if(state){
if(this.fireEvent('beforestaterestore', this, state) !== false){
- this.applyState(state);
+ this.applyState(Ext.apply({}, state));
this.fireEvent('staterestore', this, state);
}
}
@@ -982,7 +1153,7 @@ var myGrid = new Ext.grid.EditorGridPanel({
// private
getStateId : function(){
- return this.stateId || ((this.id.indexOf('ext-comp-') == 0 || this.id.indexOf('ext-gen') == 0) ? null : this.id);
+ return this.stateId || ((/^(ext-comp-|ext-gen)/).test(String(this.id)) ? null : this.id);
},
// private
@@ -1077,6 +1248,10 @@ var myGrid = new Ext.grid.EditorGridPanel({
this.el = Ext.get(this.el);
if(this.allowDomMove !== false){
ct.dom.insertBefore(this.el.dom, position);
+ if (div) {
+ Ext.removeNode(div);
+ div = null;
+ }
}
}
},
@@ -1104,23 +1279,38 @@ var myGrid = new Ext.grid.EditorGridPanel({
destroy : function(){
if(!this.isDestroyed){
if(this.fireEvent('beforedestroy', this) !== false){
+ this.destroying = true;
this.beforeDestroy();
+ if(this.ownerCt && this.ownerCt.remove){
+ this.ownerCt.remove(this, false);
+ }
if(this.rendered){
- this.el.removeAllListeners();
this.el.remove();
if(this.actionMode == 'container' || this.removeMode == 'container'){
this.container.remove();
}
}
+ // Stop any buffered tasks
+ if(this.focusTask && this.focusTask.cancel){
+ this.focusTask.cancel();
+ }
this.onDestroy();
Ext.ComponentMgr.unregister(this);
this.fireEvent('destroy', this);
this.purgeListeners();
+ this.destroying = false;
this.isDestroyed = true;
}
}
},
+ deleteMembers : function(){
+ var args = arguments;
+ for(var i = 0, len = args.length; i < len; ++i){
+ delete this[args[i]];
+ }
+ },
+
// private
beforeDestroy : Ext.emptyFn,
@@ -1152,6 +1342,11 @@ new Ext.Panel({
return this.el;
},
+ // private
+ getContentTarget : function(){
+ return this.el;
+ },
+
/**
* Returns the id
of this component or automatically generates and
* returns an id
if an id
is not defined yet:
@@ -1181,10 +1376,11 @@ new Ext.Panel({
*/
focus : function(selectText, delay){
if(delay){
- this.focus.defer(Ext.isNumber(delay) ? delay : 10, this, [selectText, false]);
- return;
+ this.focusTask = new Ext.util.DelayedTask(this.focus, this, [selectText, false]);
+ this.focusTask.delay(Ext.isNumber(delay) ? delay : 10);
+ return this;
}
- if(this.rendered){
+ if(this.rendered && !this.isDestroyed){
this.el.focus();
if(selectText === true){
this.el.dom.select();
@@ -1365,7 +1561,13 @@ var isText = t.isXType('textfield'); // true
var isBoxSubclass = t.isXType('box'); // true, descended from BoxComponent
var isBoxInstance = t.isXType('box', true); // false, not a direct BoxComponent instance
- * @param {String} xtype The xtype to check for this Component
+ * @param {String/Ext.Component/Class} xtype The xtype to check for this Component. Note that the the component can either be an instance
+ * or a component class:
+ *
+var c = new Ext.Component();
+console.log(c.isXType(c));
+console.log(c.isXType(Ext.Component));
+
* @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
* the default), or true to check whether this Component is directly of the specified xtype.
* @return {Boolean} True if this component descends from the specified xtype, false otherwise.
@@ -1420,21 +1622,42 @@ alert(t.getXTypes()); // alerts 'component/box/field/textfield'
/**
* Find a container above this component at any level by xtype or class
- * @param {String/Class} xtype The xtype string for a component, or the class of the component directly
+ * @param {String/Ext.Component/Class} xtype The xtype to check for this Component. Note that the the component can either be an instance
+ * or a component class:
+ * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
+ * the default), or true to check whether this Component is directly of the specified xtype.
* @return {Ext.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.findParentBy(function(p){
- return p.constructor.xtype === xtype;
- });
+ findParentByType : function(xtype, shallow){
+ return this.findParentBy(function(c){
+ return c.isXType(xtype, shallow);
+ });
+ },
+
+ /**
+ * 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;
},
- getDomPositionEl : function(){
- return this.getPositionEl ? this.getPositionEl() : this.getEl();
+ // protected
+ getPositionEl : function(){
+ return this.positionEl || this.el;
},
// private
@@ -1452,7 +1675,7 @@ alert(t.getXTypes()); // alerts 'component/box/field/textfield'
}, this);
this.mons = [];
},
-
+
// private
createMons: function(){
if(!this.mons){
@@ -1461,7 +1684,26 @@ alert(t.getXTypes()); // alerts 'component/box/field/textfield'
}
},
- // internal function for auto removal of assigned event handlers on destruction
+ /**
+ * Adds listeners to any Observable object (or Elements) which are automatically removed when this Component + * is destroyed. Usage:
+myGridPanel.mon(myGridPanel.getSelectionModel(), 'selectionchange', handleSelectionChange, null, {buffer: 50});
+
+ * or:
+myGridPanel.mon(myGridPanel.getSelectionModel(), {
+ selectionchange: handleSelectionChange,
+ buffer: 50
+});
+
+ * @param {Observable|Element} item The item to which to add a listener/listeners.
+ * @param {Object|String} ename The event name, or an object containing event name properties.
+ * @param {Function} fn Optional. If the ename
parameter was an event name, this
+ * is the handler function.
+ * @param {Object} scope Optional. If the ename
parameter was an event name, this
+ * is the scope (this
reference) in which the handler function is executed.
+ * @param {Object} opt Optional. If the ename
parameter was an event name, this
+ * is the {@link Ext.util.Observable#addListener addListener} options.
+ */
mon : function(item, ename, fn, scope, opt){
this.createMons();
if(Ext.isObject(ename)){
@@ -1495,7 +1737,15 @@ alert(t.getXTypes()); // alerts 'component/box/field/textfield'
item.on(ename, fn, scope, opt);
},
- // protected, opposite of mon
+ /**
+ * Removes listeners that were added by the {@link #mon} method.
+ * @param {Observable|Element} item The item from which to remove a listener/listeners.
+ * @param {Object|String} ename The event name, or an object containing event name properties.
+ * @param {Function} fn Optional. If the ename
parameter was an event name, this
+ * is the handler function.
+ * @param {Object} scope Optional. If the ename
parameter was an event name, this
+ * is the scope (this
reference) in which the handler function is executed.
+ */
mun : function(item, ename, fn, scope){
var found, mon;
this.createMons();