/*!
- * 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
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}
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}
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.
* @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
}
if(this.stateful !== false){
- this.initState(config);
+ this.initState();
}
if(this.applyTo){
</code></pre>
*/
- // Configs below are used for all Components when rendered by AnchorLayout.
- /**
- * @cfg {String} anchor <p><b>Note</b>: this config is only used when this Component is rendered
- * by a Container which has been configured to use an <b>{@link Ext.layout.AnchorLayout AnchorLayout}</b>
- * based layout manager, for example:<div class="mdetail-params"><ul>
- * <li>{@link Ext.form.FormPanel}</li>
- * <li>specifying <code>layout: 'anchor' // or 'form', or 'absolute'</code></li>
- * </ul></div></p>
- * <p>See {@link Ext.layout.AnchorLayout}.{@link Ext.layout.AnchorLayout#anchor anchor} also.</p>
- */
-
/**
* @cfg {String} id
* <p>The <b>unique</b> id of this component (defaults to an {@link #getId auto-assigned id}).
*/
rendered : false,
+ /**
+ * @cfg {String} contentEl
+ * <p>Optional. Specify an existing HTML element, or the <code>id</code> of an existing HTML element to use as the content
+ * for this component.</p>
+ * <ul>
+ * <li><b>Description</b> :
+ * <div class="sub-desc">This config option is used to take an existing HTML element and place it in the layout element
+ * of a new component (it simply moves the specified DOM element <i>after the Component is rendered</i> to use as the content.</div></li>
+ * <li><b>Notes</b> :
+ * <div class="sub-desc">The specified HTML element is appended to the layout element of the component <i>after any configured
+ * {@link #html HTML} has been inserted</i>, and so the document will not contain this element at the time the {@link #render} event is fired.</div>
+ * <div class="sub-desc">The specified HTML element used will not participate in any <code><b>{@link Ext.Container#layout layout}</b></code>
+ * scheme that the Component may use. It is just HTML. Layouts operate on child <code><b>{@link Ext.Container#items items}</b></code>.</div>
+ * <div class="sub-desc">Add either the <code>x-hidden</code> or the <code>x-hide-display</code> CSS class to
+ * prevent a brief flicker of the content before it is rendered to the panel.</div></li>
+ * </ul>
+ */
+ /**
+ * @cfg {String/Object} html
+ * An HTML fragment, or a {@link Ext.DomHelper DomHelper} specification to use as the layout element
+ * content (defaults to ''). The HTML content is added after the component is rendered,
+ * so the document will not contain this HTML at the time the {@link #render} event is fired.
+ * This content is inserted into the body <i>before</i> any configured {@link #contentEl} is appended.
+ */
+
+ /**
+ * @cfg {Mixed} tpl
+ * An <bold>{@link Ext.Template}</bold>, <bold>{@link Ext.XTemplate}</bold>
+ * or an array of strings to form an Ext.XTemplate.
+ * Used in conjunction with the <code>{@link #data}</code> and
+ * <code>{@link #tplWriteMode}</code> configurations.
+ */
+
+ /**
+ * @cfg {String} tplWriteMode The Ext.(X)Template method to use when
+ * updating the content area of the Component. Defaults to <tt>'overwrite'</tt>
+ * (see <code>{@link Ext.XTemplate#overwrite}</code>).
+ */
+ tplWriteMode : 'overwrite',
+
+ /**
+ * @cfg {Mixed} data
+ * The initial set of data to apply to the <code>{@link #tpl}</code> to
+ * update the content area of the Component.
+ */
+
+ /**
+ * @cfg {Array} bubbleEvents
+ * <p>An array of events that, when fired, should be bubbled to any parent container.
+ * See {@link Ext.util.Observable#enableBubble}.
+ * Defaults to <tt>[]</tt>.
+ */
+ bubbleEvents: [],
+
+
// private
ctype : 'Ext.Component',
}
</code></pre>
*/
- 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);
+ },
/**
* <p>Render this Component into the passed HTML element.</p>
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();
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
- * <p>A path specification, relative to the Component's {@link #ownerCt} specifying into which
- * ancestor Container to place a named reference to this Component.</p>
+ * <p>A path specification, relative to the Component's <code>{@link #ownerCt}</code>
+ * specifying into which ancestor Container to place a named reference to this Component.</p>
* <p>The ancestor axis can be traversed by using '/' characters in the path.
* For example, to put a reference to a Toolbar Button into <i>the Panel which owns the Toolbar</i>:</p><pre><code>
var myGrid = new Ext.grid.EditorGridPanel({
}
});
</code></pre>
- * <p>In the code above, if the ref had been <code>'saveButton'</code> the reference would
- * have been placed into the Toolbar. Each '/' in the ref moves up one level from the
- * Component's {@link #ownerCt}.</p>
+ * <p>In the code above, if the <code>ref</code> had been <code>'saveButton'</code>
+ * the reference would have been placed into the Toolbar. Each '/' in the <code>ref</code>
+ * moves up one level from the Component's <code>{@link #ownerCt}</code>.</p>
+ * <p>Also see the <code>{@link #added}</code> and <code>{@link #removed}</code> events.</p>
*/
- if(this.ref){
- var levels = this.ref.split('/');
- var last = levels.length, i = 0;
- var t = this;
- while(i < last){
- if(t.ownerCt){
- t = t.ownerCt;
- }
- i++;
+ if(this.ref && !this.refOwner){
+ var levels = this.ref.split('/'),
+ last = levels.length,
+ i = 0,
+ t = this;
+
+ while(t && i < last){
+ t = t.ownerCt;
+ ++i;
+ }
+ if(t){
+ t[this.refName = levels[--i]] = this;
+ /**
+ * @type Ext.Container
+ * @property refOwner
+ * The ancestor Container into which the {@link #ref} reference was inserted if this Component
+ * is a child of a Container, and has been configured with a <code>ref</code>.
+ */
+ 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);
}
}
// 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
this.el = Ext.get(this.el);
if(this.allowDomMove !== false){
ct.dom.insertBefore(this.el.dom, position);
+ if (div) {
+ Ext.removeNode(div);
+ div = null;
+ }
}
}
},
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,
return this.el;
},
+ // private
+ getContentTarget : function(){
+ return this.el;
+ },
+
/**
* Returns the <code>id</code> of this component or automatically generates and
* returns an <code>id</code> if an <code>id</code> is not defined yet:<pre><code>
*/
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();
var isBoxSubclass = t.isXType('box'); // true, descended from BoxComponent
var isBoxInstance = t.isXType('box', true); // false, not a direct BoxComponent instance
</code></pre>
- * @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:
+ * <pre><code>
+var c = new Ext.Component();
+console.log(c.isXType(c));
+console.log(c.isXType(Ext.Component));
+</code></pre>
* @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.
/**
* 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 (<i>this</i>) 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
}, this);
this.mons = [];
},
-
+
// private
createMons: function(){
if(!this.mons){
}
},
- // internal function for auto removal of assigned event handlers on destruction
+ /**
+ * <p>Adds listeners to any Observable object (or Elements) which are automatically removed when this Component
+ * is destroyed. Usage:</p><code><pre>
+myGridPanel.mon(myGridPanel.getSelectionModel(), 'selectionchange', handleSelectionChange, null, {buffer: 50});
+</pre></code>
+ * <p>or:</p><code><pre>
+myGridPanel.mon(myGridPanel.getSelectionModel(), {
+ selectionchange: handleSelectionChange,
+ buffer: 50
+});
+</pre></code>
+ * @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 <code>ename</code> parameter was an event name, this
+ * is the handler function.
+ * @param {Object} scope Optional. If the <code>ename</code> parameter was an event name, this
+ * is the scope (<code>this</code> reference) in which the handler function is executed.
+ * @param {Object} opt Optional. If the <code>ename</code> 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)){
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 <code>ename</code> parameter was an event name, this
+ * is the handler function.
+ * @param {Object} scope Optional. If the <code>ename</code> parameter was an event name, this
+ * is the scope (<code>this</code> reference) in which the handler function is executed.
+ */
mun : function(item, ename, fn, scope){
var found, mon;
this.createMons();