X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/25ef3491bd9ae007ff1fc2b0d7943e6eaaccf775..10a866c12701c0a0afd0ac85dcdcf32a421514ac:/pkgs/cmp-foundation-debug.js
diff --git a/pkgs/cmp-foundation-debug.js b/pkgs/cmp-foundation-debug.js
index 22f6c94c..b791522b 100644
--- a/pkgs/cmp-foundation-debug.js
+++ b/pkgs/cmp-foundation-debug.js
@@ -1,5 +1,5 @@
/*!
- * Ext JS Library 3.0.3
+ * Ext JS Library 3.1.0
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
@@ -53,10 +53,10 @@ Ext.ComponentMgr = function(){
},
/**
- * Registers a function that will be called when a specified component is added to ComponentMgr
+ * Registers a function that will be called when a Component with the specified id is added to ComponentMgr. This will happen on instantiation.
* @param {String} id The component {@link Ext.Component#id id}
* @param {Function} fn The callback function
- * @param {Object} scope The scope of the callback
+ * @param {Object} scope The scope (this
reference) in which the callback is executed. Defaults to the Component.
*/
onAvailable : function(id, fn, scope){
all.on("add", function(index, o){
@@ -133,7 +133,12 @@ Ext.ComponentMgr = function(){
* @return {Ext.Component} The newly instantiated Plugin.
*/
createPlugin : function(config, defaultType){
- return new ptypes[config.ptype || defaultType](config);
+ var PluginCls = ptypes[config.ptype || defaultType];
+ if (PluginCls.init) {
+ return PluginCls;
+ } else {
+ return new PluginCls(config);
+ }
}
};
}();
@@ -236,7 +241,7 @@ 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}
@@ -305,6 +310,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.
@@ -344,6 +357,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
@@ -439,7 +459,7 @@ Ext.Component = function(config){
}
if(this.stateful !== false){
- this.initState(config);
+ this.initState();
}
if(this.applyTo){
@@ -950,6 +970,53 @@ 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.
+ */
+
+
// private
ctype : 'Ext.Component',
@@ -1065,7 +1132,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();
@@ -1078,17 +1170,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({
@@ -1109,33 +1254,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);
}
}
@@ -1240,6 +1402,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;
+ }
}
}
},
@@ -1267,9 +1433,12 @@ 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();
@@ -1279,11 +1448,19 @@ var myGrid = new Ext.grid.EditorGridPanel({
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,
@@ -1315,6 +1492,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:
@@ -1596,8 +1778,9 @@ alert(t.getXTypes()); // alerts 'component/box/field/textfield'
});
},
- getDomPositionEl : function(){
- return this.getPositionEl ? this.getPositionEl() : this.getEl();
+ // protected
+ getPositionEl : function(){
+ return this.positionEl || this.el;
},
// private
@@ -1615,7 +1798,7 @@ alert(t.getXTypes()); // alerts 'component/box/field/textfield'
}, this);
this.mons = [];
},
-
+
// private
createMons: function(){
if(!this.mons){
@@ -1624,7 +1807,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)){
@@ -1658,7 +1860,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();
@@ -1711,8 +1921,7 @@ alert(t.getXTypes()); // alerts 'component/box/field/textfield'
}
});
-Ext.reg('component', Ext.Component);
-/**
+Ext.reg('component', Ext.Component);/**
* @class Ext.Action
* An Action is a piece of reusable functionality that can be abstracted out of any particular component so that it
* can be usefully shared among multiple components. Actions let you share handlers, configuration options and UI
@@ -1765,13 +1974,7 @@ aRef.setText('New text');
* @constructor
* @param {Object} config The configuration options
*/
-Ext.Action = function(config){
- this.initialConfig = config;
- this.itemId = config.itemId = (config.itemId || config.id || Ext.id());
- this.items = [];
-}
-
-Ext.Action.prototype = {
+Ext.Action = Ext.extend(Object, {
/**
* @cfg {String} text The text to set for all components using this action (defaults to '').
*/
@@ -1804,9 +2007,16 @@ Ext.Action.prototype = {
* See {@link Ext.Component}.{@link Ext.Component#itemId itemId}.
*/
/**
- * @cfg {Object} scope The scope in which the {@link #handler} function will execute.
+ * @cfg {Object} scope The scope (this reference) in which the
+ * {@link #handler}
is executed. Defaults to this Button.
*/
+ constructor : function(config){
+ this.initialConfig = config;
+ this.itemId = config.itemId = (config.itemId || config.id || Ext.id());
+ this.items = [];
+ },
+
// private
isAction : true,
@@ -1906,10 +2116,10 @@ Ext.Action.prototype = {
},
/**
- * Sets the function that will be called by each component using this action when its primary event is triggered.
+ * Sets the function that will be called by each Component using this action when its primary event is triggered.
* @param {Function} fn The function that will be invoked by the action's components. The function
* will be called with no arguments.
- * @param {Object} scope The scope in which the function will execute
+ * @param {Object} scope The scope (this
reference) in which the function is executed. Defaults to the Component firing the event.
*/
setHandler : function(fn, scope){
this.initialConfig.handler = fn;
@@ -1918,10 +2128,10 @@ Ext.Action.prototype = {
},
/**
- * Executes the specified function once for each component currently tied to this action. The function passed
+ * Executes the specified function once for each Component currently tied to this action. The function passed
* in should accept a single argument that will be an object that supports the basic Action config/method interface.
* @param {Function} fn The function to execute for each component
- * @param {Object} scope The scope in which the function will execute
+ * @param {Object} scope The scope (this
reference) in which the function is executed. Defaults to the Component.
*/
each : function(fn, scope){
Ext.each(this.items, fn, scope);
@@ -1957,7 +2167,7 @@ Ext.Action.prototype = {
execute : function(){
this.initialConfig.handler.apply(this.initialConfig.scope || window, arguments);
}
-};
+});
/**
* @class Ext.Layer
* @extends Ext.Element
@@ -2128,7 +2338,7 @@ Ext.extend(Ext.Layer, Ext.Element, {
}
this.removeAllListeners();
Ext.removeNode(this.dom);
- Ext.Element.uncache(this.id);
+ delete this.dom;
},
remove : function(){
@@ -2417,7 +2627,8 @@ Ext.extend(Ext.Layer, Ext.Element, {
return this;
}
});
-})();/**
+})();
+/**
* @class Ext.Shadow
* Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
* and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
@@ -2700,6 +2911,26 @@ Ext.BoxComponent = Ext.extend(Ext.Component, {
* The width of this component in pixels (defaults to auto).
* Note to express this dimension as a percentage or offset see {@link Ext.Component#anchor}.
*/
+ /**
+ * @cfg {Number} boxMinHeight
+ *
The minimum value in pixels which this BoxComponent will set its height to.
+ * Warning: This will override any size management applied by layout managers.
+ */
+ /**
+ * @cfg {Number} boxMinWidth
+ * The minimum value in pixels which this BoxComponent will set its width to.
+ * Warning: This will override any size management applied by layout managers.
+ */
+ /**
+ * @cfg {Number} boxMaxHeight
+ * The maximum value in pixels which this BoxComponent will set its height to.
+ * Warning: This will override any size management applied by layout managers.
+ */
+ /**
+ * @cfg {Number} boxMaxWidth
+ * The maximum value in pixels which this BoxComponent will set its width to.
+ * Warning: This will override any size management applied by layout managers.
+ */
/**
* @cfg {Boolean} autoHeight
* True to use height:'auto', false to use fixed height (or allow it to be managed by its parent
@@ -2774,6 +3005,11 @@ var myPanel = new Ext.Panel({
});
*/
+ /**
+ * @cfg {Boolean} autoScroll
+ * 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
).
+ */
/* // private internal config
* {Boolean} deferHeight
@@ -2829,15 +3065,26 @@ var myPanel = new Ext.Panel({
* @return {Ext.BoxComponent} this
*/
setSize : function(w, h){
+
// support for standard size objects
if(typeof w == 'object'){
- h = w.height;
- w = w.width;
+ h = w.height, w = w.width;
+ }
+ if (Ext.isDefined(w) && Ext.isDefined(this.boxMinWidth) && (w < this.boxMinWidth)) {
+ w = this.boxMinWidth;
+ }
+ if (Ext.isDefined(h) && Ext.isDefined(this.boxMinHeight) && (h < this.boxMinHeight)) {
+ h = this.boxMinHeight;
+ }
+ if (Ext.isDefined(w) && Ext.isDefined(this.boxMaxWidth) && (w > this.boxMaxWidth)) {
+ w = this.boxMaxWidth;
+ }
+ if (Ext.isDefined(h) && Ext.isDefined(this.boxMaxHeight) && (h > this.boxMaxHeight)) {
+ h = this.boxMaxHeight;
}
// not rendered
if(!this.boxReady){
- this.width = w;
- this.height = h;
+ this.width = w, this.height = h;
return this;
}
@@ -2846,10 +3093,12 @@ var myPanel = new Ext.Panel({
return this;
}
this.lastSize = {width: w, height: h};
- var adj = this.adjustSize(w, h);
- var aw = adj.width, ah = adj.height;
+ var adj = this.adjustSize(w, h),
+ aw = adj.width,
+ ah = adj.height,
+ rz;
if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
- var rz = this.getResizeEl();
+ rz = this.getResizeEl();
if(!this.deferHeight && aw !== undefined && ah !== undefined){
rz.setSize(aw, ah);
}else if(!this.deferHeight && ah !== undefined){
@@ -2858,7 +3107,6 @@ var myPanel = new Ext.Panel({
rz.setWidth(aw);
}
this.onResize(aw, ah, w, h);
- this.fireEvent('resize', this, aw, ah, w, h);
}
return this;
},
@@ -2968,14 +3216,23 @@ var myPanel = new Ext.Panel({
* contains both the <input>
Element (which is what would be returned
* by its {@link #getEl}
method, and the trigger button Element.
* This Element is returned as the resizeEl
.
+ * @return {Ext.Element} The Element which is to be resized by size managing layouts.
*/
getResizeEl : function(){
return this.resizeEl || this.el;
},
- // protected
- getPositionEl : function(){
- return this.positionEl || this.el;
+ /**
+ * Sets the overflow on the content element of the component.
+ * @param {Boolean} scroll True to allow the Component to auto scroll.
+ * @return {Ext.BoxComponent} this
+ */
+ setAutoScroll : function(scroll){
+ if(this.rendered){
+ this.getContentTarget().setOverflow(scroll ? 'auto' : '');
+ }
+ this.autoScroll = scroll;
+ return this;
},
/**
@@ -3048,6 +3305,7 @@ var myPanel = new Ext.Panel({
this.positionEl = Ext.get(this.positionEl);
}
this.boxReady = true;
+ this.setAutoScroll(this.autoScroll);
this.setSize(this.width, this.height);
if(this.x || this.y){
this.setPosition(this.x, this.y);
@@ -3075,7 +3333,7 @@ var myPanel = new Ext.Panel({
* @param {Number} rawHeight The height that was originally specified
*/
onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
-
+ this.fireEvent('resize', this, adjWidth, adjHeight, rawWidth, rawHeight);
},
/* // protected
@@ -3137,12 +3395,12 @@ split.on('moved', splitterMoved);
* @param {Mixed} dragElement The element to be dragged and act as the SplitBar.
* @param {Mixed} resizingElement The element to be resized based on where the SplitBar element is dragged
* @param {Number} orientation (optional) Either Ext.SplitBar.HORIZONTAL or Ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
- * @param {Number} placement (optional) Either Ext.SplitBar.LEFT or Ext.SplitBar.RIGHT for horizontal or
+ * @param {Number} placement (optional) Either Ext.SplitBar.LEFT or Ext.SplitBar.RIGHT for horizontal or
Ext.SplitBar.TOP or Ext.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
position of the SplitBar).
*/
Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
-
+
/** @private */
this.el = Ext.get(dragElement, true);
this.el.dom.unselectable = "on";
@@ -3156,7 +3414,7 @@ Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, ex
* @type Number
*/
this.orientation = orientation || Ext.SplitBar.HORIZONTAL;
-
+
/**
* The increment, in pixels by which to move this SplitBar. When undefined, the SplitBar moves smoothly.
* @type Number
@@ -3167,28 +3425,28 @@ Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, ex
* @type Number
*/
this.minSize = 0;
-
+
/**
* The maximum size of the resizing element. (Defaults to 2000)
* @type Number
*/
this.maxSize = 2000;
-
+
/**
* Whether to animate the transition to the new size
* @type Boolean
*/
this.animate = false;
-
+
/**
* Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
* @type Boolean
*/
this.useShim = false;
-
+
/** @private */
this.shim = null;
-
+
if(!existingProxy){
/** @private */
this.proxy = Ext.SplitBar.createProxy(this.orientation);
@@ -3197,22 +3455,22 @@ Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, ex
}
/** @private */
this.dd = new Ext.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
-
+
/** @private */
this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
-
+
/** @private */
this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
-
+
/** @private */
this.dragSpecs = {};
-
+
/**
* @private The adapter to use to positon and resize elements
*/
this.adapter = new Ext.SplitBar.BasicLayoutAdapter();
this.adapter.init(this);
-
+
if(this.orientation == Ext.SplitBar.HORIZONTAL){
/** @private */
this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Ext.SplitBar.LEFT : Ext.SplitBar.RIGHT);
@@ -3222,7 +3480,7 @@ Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, ex
this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Ext.SplitBar.TOP : Ext.SplitBar.BOTTOM);
this.el.addClass("x-splitbar-v");
}
-
+
this.addEvents(
/**
* @event resize
@@ -3267,7 +3525,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, {
if(this.orientation == Ext.SplitBar.HORIZONTAL){
this.dd.resetConstraints();
this.dd.setXConstraint(
- this.placement == Ext.SplitBar.LEFT ? c1 : c2,
+ this.placement == Ext.SplitBar.LEFT ? c1 : c2,
this.placement == Ext.SplitBar.LEFT ? c2 : c1,
this.tickSize
);
@@ -3276,7 +3534,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, {
this.dd.resetConstraints();
this.dd.setXConstraint(0, 0);
this.dd.setYConstraint(
- this.placement == Ext.SplitBar.TOP ? c1 : c2,
+ this.placement == Ext.SplitBar.TOP ? c1 : c2,
this.placement == Ext.SplitBar.TOP ? c2 : c1,
this.tickSize
);
@@ -3285,8 +3543,8 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, {
this.dragSpecs.startPoint = [x, y];
Ext.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
},
-
- /**
+
+ /**
* @private Called after the drag operation by the DDProxy
*/
onEndProxyDrag : function(e){
@@ -3298,13 +3556,13 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, {
}
var newSize;
if(this.orientation == Ext.SplitBar.HORIZONTAL){
- newSize = this.dragSpecs.startSize +
+ newSize = this.dragSpecs.startSize +
(this.placement == Ext.SplitBar.LEFT ?
endPoint[0] - this.dragSpecs.startPoint[0] :
this.dragSpecs.startPoint[0] - endPoint[0]
);
}else{
- newSize = this.dragSpecs.startSize +
+ newSize = this.dragSpecs.startSize +
(this.placement == Ext.SplitBar.TOP ?
endPoint[1] - this.dragSpecs.startPoint[1] :
this.dragSpecs.startPoint[1] - endPoint[1]
@@ -3319,7 +3577,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, {
}
}
},
-
+
/**
* Get the adapter this SplitBar uses
* @return The adapter object
@@ -3327,7 +3585,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, {
getAdapter : function(){
return this.adapter;
},
-
+
/**
* Set the adapter this SplitBar uses
* @param {Object} adapter A SplitBar adapter object
@@ -3336,7 +3594,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, {
this.adapter = adapter;
this.adapter.init(this);
},
-
+
/**
* Gets the minimum size for the resizing element
* @return {Number} The minimum size
@@ -3344,7 +3602,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, {
getMinimumSize : function(){
return this.minSize;
},
-
+
/**
* Sets the minimum size for the resizing element
* @param {Number} minSize The minimum size
@@ -3352,7 +3610,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, {
setMinimumSize : function(minSize){
this.minSize = minSize;
},
-
+
/**
* Gets the maximum size for the resizing element
* @return {Number} The maximum size
@@ -3360,7 +3618,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, {
getMaximumSize : function(){
return this.maxSize;
},
-
+
/**
* Sets the maximum size for the resizing element
* @param {Number} maxSize The maximum size
@@ -3368,7 +3626,7 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, {
setMaximumSize : function(maxSize){
this.maxSize = maxSize;
},
-
+
/**
* Sets the initialize size for the resizing element
* @param {Number} size The initial size
@@ -3379,18 +3637,18 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, {
this.adapter.setElementSize(this, size);
this.animate = oldAnimate;
},
-
+
/**
- * Destroy this splitbar.
+ * Destroy this splitbar.
* @param {Boolean} removeEl True to remove the element
*/
destroy : function(removeEl){
- Ext.destroy(this.shim, Ext.get(this.proxy));
+ Ext.destroy(this.shim, Ext.get(this.proxy));
this.dd.unreg();
if(removeEl){
this.el.remove();
}
- this.purgeListeners();
+ this.purgeListeners();
}
});
@@ -3399,14 +3657,14 @@ Ext.extend(Ext.SplitBar, Ext.util.Observable, {
*/
Ext.SplitBar.createProxy = function(dir){
var proxy = new Ext.Element(document.createElement("div"));
+ document.body.appendChild(proxy.dom);
proxy.unselectable();
var cls = 'x-splitbar-proxy';
proxy.addClass(cls + ' ' + (dir == Ext.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
- document.body.appendChild(proxy.dom);
return proxy.dom;
};
-/**
+/**
* @class Ext.SplitBar.BasicLayoutAdapter
* Default Adapter. It assumes the splitter and resizing element are not positioned
* elements and only gets/sets the width of the element. Generally used for table based layouts.
@@ -3417,10 +3675,10 @@ Ext.SplitBar.BasicLayoutAdapter = function(){
Ext.SplitBar.BasicLayoutAdapter.prototype = {
// do nothing for now
init : function(s){
-
+
},
/**
- * Called before drag operations to get the current size of the resizing element.
+ * Called before drag operations to get the current size of the resizing element.
* @param {Ext.SplitBar} s The SplitBar using this adapter
*/
getElementSize : function(s){
@@ -3430,7 +3688,7 @@ Ext.SplitBar.BasicLayoutAdapter.prototype = {
return s.resizingEl.getHeight();
}
},
-
+
/**
* Called after drag operations to set the size of the resizing element.
* @param {Ext.SplitBar} s The SplitBar using this adapter
@@ -3448,7 +3706,7 @@ Ext.SplitBar.BasicLayoutAdapter.prototype = {
s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
}
}else{
-
+
if(!s.animate){
s.resizingEl.setHeight(newSize);
if(onComplete){
@@ -3461,10 +3719,10 @@ Ext.SplitBar.BasicLayoutAdapter.prototype = {
}
};
-/**
+/**
*@class Ext.SplitBar.AbsoluteLayoutAdapter
* @extends Ext.SplitBar.BasicLayoutAdapter
- * Adapter that moves the splitter element to align with the resized sizing element.
+ * Adapter that moves the splitter element to align with the resized sizing element.
* Used with an absolute positioned SplitBar.
* @param {Mixed} container The container that wraps around the absolute positioned content. If it's
* document.body, make sure you assign an id to the body element.
@@ -3478,15 +3736,15 @@ Ext.SplitBar.AbsoluteLayoutAdapter.prototype = {
init : function(s){
this.basic.init(s);
},
-
+
getElementSize : function(s){
return this.basic.getElementSize(s);
},
-
+
setElementSize : function(s, newSize, onComplete){
this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
},
-
+
moveSplitter : function(s){
var yes = Ext.SplitBar;
switch(s.placement){
@@ -3547,1180 +3805,1255 @@ Ext.SplitBar.TOP = 3;
* @type Number
*/
Ext.SplitBar.BOTTOM = 4;
-/**
- * @class Ext.Container
- * @extends Ext.BoxComponent
- * Base class for any {@link Ext.BoxComponent} that may contain other Components. Containers handle the - * basic behavior of containing items, namely adding, inserting and removing items.
- * - *The most commonly used Container classes are {@link Ext.Panel}, {@link Ext.Window} and {@link Ext.TabPanel}. - * If you do not need the capabilities offered by the aforementioned classes you can create a lightweight - * Container to be encapsulated by an HTML element to your specifications by using the - * {@link Ext.Component#autoEl autoEl} config option. This is a useful technique when creating - * embedded {@link Ext.layout.ColumnLayout column} layouts inside {@link Ext.form.FormPanel FormPanels} - * for example.
- * - *The code below illustrates both how to explicitly create a Container, and how to implicitly - * create one using the 'container' xtype:
-// explicitly create a Container
-var embeddedColumns = new Ext.Container({
- autoEl: 'div', // This is the default
- layout: 'column',
- defaults: {
- // implicitly create Container by specifying xtype
- xtype: 'container',
- autoEl: 'div', // This is the default.
- layout: 'form',
- columnWidth: 0.5,
- style: {
- padding: '10px'
- }
- },
-// The two items below will be Ext.Containers, each encapsulated by a <DIV> element.
- items: [{
- items: {
- xtype: 'datefield',
- name: 'startDate',
- fieldLabel: 'Start date'
- }
- }, {
- items: {
- xtype: 'datefield',
- name: 'endDate',
- fieldLabel: 'End date'
- }
- }]
-});
- *
- * Layout
- *Container classes delegate the rendering of child Components to a layout
- * manager class which must be configured into the Container using the
- * {@link #layout}
configuration property.
When either specifying child {@link #items}
of a Container,
- * or dynamically {@link #add adding} Components to a Container, remember to
- * consider how you wish the Container to arrange those child elements, and
- * whether those child elements need to be sized using one of Ext's built-in
- * {@link #layout}
schemes. By default, Containers use the
- * {@link Ext.layout.ContainerLayout ContainerLayout} scheme which only
- * renders child components, appending them one after the other inside the
- * Container, and does not apply any sizing at all.
A common mistake is when a developer neglects to specify a
- * {@link #layout}
(e.g. widgets like GridPanels or
- * TreePanels are added to Containers for which no {@link #layout}
- * has been specified). If a Container is left to use the default
- * {@link Ext.layout.ContainerLayout ContainerLayout} scheme, none of its
- * child components will be resized, or changed in any way when the Container
- * is resized.
Certain layout managers allow dynamic addition of child components. - * Those that do include {@link Ext.layout.CardLayout}, - * {@link Ext.layout.AnchorLayout}, {@link Ext.layout.FormLayout}, and - * {@link Ext.layout.TableLayout}. For example:
-// Create the GridPanel.
-var myNewGrid = new Ext.grid.GridPanel({
- store: myStore,
- columns: myColumnModel,
- title: 'Results', // the title becomes the title of the tab
-});
-
-myTabPanel.add(myNewGrid); // {@link Ext.TabPanel} implicitly uses {@link Ext.layout.CardLayout CardLayout}
-myTabPanel.{@link Ext.TabPanel#setActiveTab setActiveTab}(myNewGrid);
- *
- * The example above adds a newly created GridPanel to a TabPanel. Note that - * a TabPanel uses {@link Ext.layout.CardLayout} as its layout manager which - * means all its child items are sized to {@link Ext.layout.FitLayout fit} - * exactly into its client area. - *
Overnesting is a common problem. - * An example of overnesting occurs when a GridPanel is added to a TabPanel - * by wrapping the GridPanel inside a wrapping Panel (that has no - * {@link #layout} specified) and then add that wrapping Panel - * to the TabPanel. The point to realize is that a GridPanel is a - * Component which can be added directly to a Container. If the wrapping Panel - * has no {@link #layout} configuration, then the overnested - * GridPanel will not be sized as expected.
- * - *
Adding via remote configuration
- * - *A server side script can be used to add Components which are generated dynamically on the server. - * An example of adding a GridPanel to a TabPanel where the GridPanel is generated by the server - * based on certain parameters: - *
-// execute an Ajax request to invoke server side script:
-Ext.Ajax.request({
- url: 'gen-invoice-grid.php',
- // send additional parameters to instruct server script
- params: {
- startDate: Ext.getCmp('start-date').getValue(),
- endDate: Ext.getCmp('end-date').getValue()
- },
- // process the response object to add it to the TabPanel:
- success: function(xhr) {
- var newComponent = eval(xhr.responseText); // see discussion below
- myTabPanel.add(newComponent); // add the component to the TabPanel
- myTabPanel.setActiveTab(newComponent);
- },
- failure: function() {
- Ext.Msg.alert("Grid create failed", "Server communication failure");
- }
-});
-
- * The server script needs to return an executable Javascript statement which, when processed - * using eval(), will return either a config object with an {@link Ext.Component#xtype xtype}, - * or an instantiated Component. The server might return this for example:
-(function() {
- function formatDate(value){
- return value ? value.dateFormat('M d, Y') : '';
- };
-
- var store = new Ext.data.Store({
- url: 'get-invoice-data.php',
- baseParams: {
- startDate: '01/01/2008',
- endDate: '01/31/2008'
- },
- reader: new Ext.data.JsonReader({
- record: 'transaction',
- idProperty: 'id',
- totalRecords: 'total'
- }, [
- 'customer',
- 'invNo',
- {name: 'date', type: 'date', dateFormat: 'm/d/Y'},
- {name: 'value', type: 'float'}
- ])
- });
-
- var grid = new Ext.grid.GridPanel({
- title: 'Invoice Report',
- bbar: new Ext.PagingToolbar(store),
- store: store,
- columns: [
- {header: "Customer", width: 250, dataIndex: 'customer', sortable: true},
- {header: "Invoice Number", width: 120, dataIndex: 'invNo', sortable: true},
- {header: "Invoice Date", width: 100, dataIndex: 'date', renderer: formatDate, sortable: true},
- {header: "Value", width: 120, dataIndex: 'value', renderer: 'usMoney', sortable: true}
- ],
- });
- store.load();
- return grid; // return instantiated component
-})();
-
- * When the above code fragment is passed through the eval function in the success handler - * of the Ajax request, the code is executed by the Javascript processor, and the anonymous function - * runs, and returns the instantiated grid component.
- *Note: since the code above is generated by a server script, the baseParams for - * the Store, the metadata to allow generation of the Record layout, and the ColumnModel - * can all be generated into the code since these are all known on the server.
- * - * @xtype container - */ -Ext.Container = Ext.extend(Ext.BoxComponent, { - /** - * @cfg {Boolean} monitorResize - * True to automatically monitor window resize events to handle anything that is sensitive to the current size - * of the viewport. This value is typically managed by the chosen{@link #layout}
and should not need
- * to be set manually.
- */
- /**
- * @cfg {String/Object} layout
- * *Important: In order for child items to be correctly sized and
- * positioned, typically a layout manager must be specified through
- * the layout
configuration option.
The sizing and positioning of child {@link items} is the responsibility of - * the Container's layout manager which creates and manages the type of layout - * you have in mind. For example:
-new Ext.Window({
- width:300, height: 300,
- layout: 'fit', // explicitly set layout manager: override the default (layout:'auto')
- items: [{
- title: 'Panel inside a Window'
- }]
-}).show();
- *
- * If the {@link #layout} configuration is not explicitly specified for
- * a general purpose container (e.g. Container or Panel) the
- * {@link Ext.layout.ContainerLayout default layout manager} will be used
- * which does nothing but render child components sequentially into the
- * Container (no sizing or positioning will be performed in this situation).
- * Some container classes implicitly specify a default layout
- * (e.g. FormPanel specifies layout:'form'
). Other specific
- * purpose classes internally specify/manage their internal layout (e.g.
- * GridPanel, TabPanel, TreePanel, Toolbar, Menu, etc.).
layout
may be specified as either as an Object or
- * as a String:
-layout: {
- type: 'vbox',
- padding: '5',
- align: 'left'
-}
-
- *
- * The layout type to be used for this container. If not specified, - * a default {@link Ext.layout.ContainerLayout} will be created and used.
- *Valid layout type values are:
- *Additional layout specific configuration properties may also be - * specified. For complete details regarding the valid config options for - * each layout type, see the layout class corresponding to the type - * specified.
- * - *
-layout: 'vbox',
-layoutConfig: {
- padding: '5',
- align: 'left'
-}
-
- * The layout type to be used for this container (see list - * of valid layout type values above).
Additional layout specific configuration properties. For complete - * details regarding the valid config options for each layout type, see the - * layout class corresponding to the layout specified.
- *{@link #layout}
if {@link #layout}
- * has been specified as a string.
- */
- /**
- * @cfg {Boolean/Number} bufferResize
- * When set to true (50 milliseconds) or a number of milliseconds, the layout assigned for this container will buffer
- * the frequency it calculates and does a re-layout of components. This is useful for heavy containers or containers
- * with a large quantity of sub-components for which frequent layout calls would be expensive. Defaults to 50.
- */
- bufferResize: 50,
-
- /**
- * @cfg {String/Number} activeItem
- * A string component id or the numeric index of the component that should be initially activated within the
- * container's layout on render. For example, activeItem: 'item-1' or activeItem: 0 (index 0 = the first
- * item in the container's collection). activeItem only applies to layout styles that can display
- * items one at a time (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout} and
- * {@link Ext.layout.FitLayout}). Related to {@link Ext.layout.ContainerLayout#activeItem}.
- */
- /**
- * @cfg {Object/Array} items
- * ** IMPORTANT: be sure to {@link #layout specify a layout
} if needed ! **
- * A single item, or an array of child Components to be added to this container, - * for example:
- *
-// specifying a single item
-items: {...},
-layout: 'fit', // specify a layout!
-
-// specifying multiple items
-items: [{...}, {...}],
-layout: 'anchor', // specify a layout!
- *
- * Each item may be:
- *{@link Ext.Component#xtype xtype}
{@link Ext.Component#xtype xtype}
is not explicitly
- * specified, the {@link #defaultType} for that Container is used.Notes:
- *{@link Ext.Panel#contentEl contentEl}
/
- * {@link Ext.Panel#html html}
with items
.A config object that will be applied to all components added to this container either via the {@link #items} - * config or via the {@link #add} or {@link #insert} methods. The defaults config can contain any - * number of name/value property pairs to be added to each item, and should be valid for the types of items - * being added to the container. For example, to automatically apply padding to the body of each of a set of - * contained {@link Ext.Panel} items, you could pass: defaults: {bodyStyle:'padding:15px'}.
Note: defaults will not be applied to config objects if the option is already specified. - * For example:
-defaults: { // defaults are applied to items, not the container
- autoScroll:true
-},
-items: [
- {
- xtype: 'panel', // defaults do not have precedence over
- id: 'panel1', // options in config objects, so the defaults
- autoScroll: false // will not be applied here, panel1 will be autoScroll:false
- },
- new Ext.Panel({ // defaults do have precedence over options
- id: 'panel2', // options in components, so the defaults
- autoScroll: false // will be applied here, panel2 will be autoScroll:true.
- })
-]
- *
- */
-
-
- /** @cfg {Boolean} autoDestroy
- * If true the container will automatically destroy any contained component that is removed from it, else
- * destruction must be handled manually (defaults to true).
- */
- autoDestroy : true,
-
- /** @cfg {Boolean} forceLayout
- * If true the container will force a layout initially even if hidden or collapsed. This option
- * is useful for forcing forms to render in collapsed or hidden containers. (defaults to false).
- */
- forceLayout: false,
-
- /** @cfg {Boolean} hideBorders
- * True to hide the borders of each contained component, false to defer to the component's existing
- * border settings (defaults to false).
- */
- /** @cfg {String} defaultType
- * The default {@link Ext.Component xtype} of child Components to create in this Container when - * a child item is specified as a raw configuration object, rather than as an instantiated Component.
- *Defaults to 'panel', except {@link Ext.menu.Menu} which defaults to 'menuitem', - * and {@link Ext.Toolbar} and {@link Ext.ButtonGroup} which default to 'button'.
- */ - defaultType : 'panel', - - /** @cfg {String} resizeEvent - * The event to listen to for resizing in layouts. Defaults to 'resize'. - */ - resizeEvent: 'resize', - - /** - * @cfg {Array} bubbleEvents - *An array of events that, when fired, should be bubbled to any parent container. - * Defaults to ['add', 'remove']. - */ - bubbleEvents: ['add', 'remove'], - - // private - initComponent : function(){ - Ext.Container.superclass.initComponent.call(this); - - this.addEvents( - /** - * @event afterlayout - * Fires when the components in this container are arranged by the associated layout manager. - * @param {Ext.Container} this - * @param {ContainerLayout} layout The ContainerLayout implementation for this container - */ - 'afterlayout', - /** - * @event beforeadd - * Fires before any {@link Ext.Component} is added or inserted into the container. - * A handler can return false to cancel the add. - * @param {Ext.Container} this - * @param {Ext.Component} component The component being added - * @param {Number} index The index at which the component will be added to the container's items collection - */ - 'beforeadd', - /** - * @event beforeremove - * Fires before any {@link Ext.Component} is removed from the container. A handler can return - * false to cancel the remove. - * @param {Ext.Container} this - * @param {Ext.Component} component The component being removed - */ - 'beforeremove', - /** - * @event add - * @bubbles - * Fires after any {@link Ext.Component} is added or inserted into the container. - * @param {Ext.Container} this - * @param {Ext.Component} component The component that was added - * @param {Number} index The index at which the component was added to the container's items collection - */ - 'add', - /** - * @event remove - * @bubbles - * Fires after any {@link Ext.Component} is removed from the container. - * @param {Ext.Container} this - * @param {Ext.Component} component The component that was removed - */ - 'remove' - ); - - this.enableBubble(this.bubbleEvents); - - /** - * The collection of components in this container as a {@link Ext.util.MixedCollection} - * @type MixedCollection - * @property items - */ - var items = this.items; - if(items){ - delete this.items; - this.add(items); - } - }, - - // private - initItems : function(){ - if(!this.items){ - this.items = new Ext.util.MixedCollection(false, this.getComponentId); - this.getLayout(); // initialize the layout - } - }, - - // private - setLayout : function(layout){ - if(this.layout && this.layout != layout){ - this.layout.setContainer(null); - } - this.initItems(); - this.layout = layout; - layout.setContainer(this); - }, - - afterRender: function(){ - Ext.Container.superclass.afterRender.call(this); - if(!this.layout){ - this.layout = 'auto'; - } - if(Ext.isObject(this.layout) && !this.layout.layout){ - this.layoutConfig = this.layout; - this.layout = this.layoutConfig.type; - } - if(Ext.isString(this.layout)){ - this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig); - } - this.setLayout(this.layout); - - if(this.activeItem !== undefined){ - var item = this.activeItem; - delete this.activeItem; - this.layout.setActiveItem(item); - } - if(!this.ownerCt){ - // force a layout if no ownerCt is set - this.doLayout(false, true); - } - if(this.monitorResize === true){ - Ext.EventManager.onWindowResize(this.doLayout, this, [false]); - } - }, - - /** - *
Returns the Element to be used to contain the child Components of this Container.
- *An implementation is provided which returns the Container's {@link #getEl Element}, but - * if there is a more complex structure to a Container, this may be overridden to return - * the element into which the {@link #layout layout} renders child Components.
- * @return {Ext.Element} The Element to render child Components into. - */ - getLayoutTarget : function(){ - return this.el; - }, - - // private - used as the key lookup function for the items collection - getComponentId : function(comp){ - return comp.getItemId(); - }, - - /** - *Adds {@link Ext.Component Component}(s) to this Container.
- *Description : - *
{@link #defaults}
for details).Notes : - *
-var tb = new {@link Ext.Toolbar}();
-tb.render(document.body); // toolbar is rendered
-tb.add({text:'Button 1'}); // add multiple items ({@link #defaultType} for {@link Ext.Toolbar Toolbar} is 'button')
-tb.add({text:'Button 2'});
-tb.{@link #doLayout}(); // refresh the layout
- *
Either a single component or an Array of components to add. See
- * {@link #items}
for additional information.
{@link #items}
property
- * and gets a direct child component of this container.
- * @param {String/Number} comp This parameter may be any of the following:
- * {@link Ext.Component#itemId itemId}
- * or {@link Ext.Component#id id}
of the child component {@link #items}
propertyFor additional information see {@link Ext.util.MixedCollection#get}. - * @return Ext.Component The component (if found). - */ - getComponent : function(comp){ - if(Ext.isObject(comp)){ - comp = comp.getItemId(); - } - return this.items.get(comp); - }, - - // private - lookupComponent : function(comp){ - if(Ext.isString(comp)){ - return Ext.ComponentMgr.get(comp); - }else if(!comp.events){ - return this.createComponent(comp); - } - return comp; - }, - - // private - createComponent : function(config){ - return Ext.create(config, this.defaultType); - }, - - // private - canLayout: function() { - var el = this.getVisibilityEl(); - return el && !el.isStyle("display", "none"); - }, - - - /** - * Force this container's layout to be recalculated. A call to this function is required after adding a new component - * to an already rendered container, or possibly after changing sizing/position properties of child components. - * @param {Boolean} shallow (optional) True to only calc the layout of this component, and let child components auto - * calc layouts as required (defaults to false, which calls doLayout recursively for each subcontainer) - * @param {Boolean} force (optional) True to force a layout to occur, even if the item is hidden. - * @return {Ext.Container} this - */ - doLayout: function(shallow, force){ - var rendered = this.rendered; - forceLayout = force || this.forceLayout; - - if(!this.canLayout() || this.collapsed){ - this.deferLayout = this.deferLayout || !shallow; - if(!forceLayout){ - return; - } - shallow = shallow && !this.deferLayout; - } else { - delete this.deferLayout; - } - if(rendered && this.layout){ - this.layout.layout(); - } - if(shallow !== true && this.items){ - var cs = this.items.items; - for(var i = 0, len = cs.length; i < len; i++){ - var c = cs[i]; - if(c.doLayout){ - c.doLayout(false, forceLayout); - } - } - } - if(rendered){ - this.onLayout(shallow, forceLayout); - } - // Initial layout completed - this.hasLayout = true; - delete this.forceLayout; - }, - - //private - onLayout : Ext.emptyFn, - - // private - shouldBufferLayout: function(){ - /* - * Returns true if the container should buffer a layout. - * This is true only if the container has previously been laid out - * and has a parent container that is pending a layout. - */ - var hl = this.hasLayout; - if(this.ownerCt){ - // Only ever buffer if we've laid out the first time and we have one pending. - return hl ? !this.hasLayoutPending() : false; - } - // Never buffer initial layout - return hl; - }, - - // private - hasLayoutPending: function(){ - // Traverse hierarchy to see if any parent container has a pending layout. - var pending = false; - this.ownerCt.bubble(function(c){ - if(c.layoutPending){ - pending = true; - return false; - } - }); - return pending; - }, - - onShow : function(){ - Ext.Container.superclass.onShow.call(this); - if(this.deferLayout !== undefined){ - this.doLayout(true); - } - }, - - /** - * Returns the layout currently in use by the container. If the container does not currently have a layout - * set, a default {@link Ext.layout.ContainerLayout} will be created and set as the container's layout. - * @return {ContainerLayout} layout The container's layout - */ - getLayout : function(){ - if(!this.layout){ - var layout = new Ext.layout.ContainerLayout(this.layoutConfig); - this.setLayout(layout); - } - return this.layout; - }, - - // private - beforeDestroy : function(){ - if(this.items){ - Ext.destroy.apply(Ext, this.items.items); - } - if(this.monitorResize){ - Ext.EventManager.removeResizeListener(this.doLayout, this); - } - Ext.destroy(this.layout); - Ext.Container.superclass.beforeDestroy.call(this); - }, - - /** - * 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.Container} 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; - }, - - /** - * Cascades down the component/container heirarchy from this component (called first), 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 cascade is stopped on that branch. - * @param {Function} fn The function to call - * @param {Object} scope (optional) The scope of the function (defaults to current component) - * @param {Array} args (optional) The args to call the function with (defaults to passing the current component) - * @return {Ext.Container} this - */ - cascade : function(fn, scope, args){ - if(fn.apply(scope || this, args || [this]) !== false){ - if(this.items){ - var cs = this.items.items; - for(var i = 0, len = cs.length; i < len; i++){ - if(cs[i].cascade){ - cs[i].cascade(fn, scope, args); - }else{ - fn.apply(scope || cs[i], args || [cs[i]]); - } - } - } - } - return this; - }, - - /** - * Find a component under this container at any level by id - * @param {String} id - * @return Ext.Component - */ - findById : function(id){ - var m, ct = this; - this.cascade(function(c){ - if(ct != c && c.id === id){ - m = c; - return false; - } - }); - return m || null; - }, - - /** - * Find a component under this container 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 {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 {Array} Array of Ext.Components - */ - findByType : function(xtype, shallow){ - return this.findBy(function(c){ - return c.isXType(xtype, shallow); - }); - }, - - /** - * Find a component under this container at any level by property - * @param {String} prop - * @param {String} value - * @return {Array} Array of Ext.Components - */ - find : function(prop, value){ - return this.findBy(function(c){ - return c[prop] === value; - }); - }, - - /** - * Find a component under this container at any level by a custom function. If the passed function returns - * true, the component will be included in the results. The passed function is called with the arguments (component, this container). - * @param {Function} fn The function to call - * @param {Object} scope (optional) - * @return {Array} Array of Ext.Components - */ - findBy : function(fn, scope){ - var m = [], ct = this; - this.cascade(function(c){ - if(ct != c && fn.call(scope || c, c, ct) === true){ - m.push(c); - } - }); - return m; - }, - - /** - * Get a component contained by this container (alias for items.get(key)) - * @param {String/Number} key The index or id of the component - * @return {Ext.Component} Ext.Component - */ - get : function(key){ - return this.items.get(key); - } -}); - -Ext.Container.LAYOUTS = {}; -Ext.reg('container', Ext.Container); /** - * @class Ext.layout.ContainerLayout - *
The ContainerLayout class is the default layout manager delegated by {@link Ext.Container} to - * render any child Components when no {@link Ext.Container#layout layout} is configured into - * a {@link Ext.Container Container}. ContainerLayout provides the basic foundation for all other layout - * classes in Ext. It simply renders all child Components into the Container, performing no sizing or - * positioning services. To utilize a layout that provides sizing and positioning of child Components, - * specify an appropriate {@link Ext.Container#layout layout}.
- *This class is intended to be extended or created via the {@link Ext.Container#layout layout} - * configuration property. See {@link Ext.Container#layout} for additional details.
- */ -Ext.layout.ContainerLayout = function(config){ - Ext.apply(this, config); -}; + * @class Ext.Container + * @extends Ext.BoxComponent + *Base class for any {@link Ext.BoxComponent} that may contain other Components. Containers handle the + * basic behavior of containing items, namely adding, inserting and removing items.
+ * + *The most commonly used Container classes are {@link Ext.Panel}, {@link Ext.Window} and {@link Ext.TabPanel}.
+ * If you do not need the capabilities offered by the aforementioned classes you can create a lightweight
+ * Container to be encapsulated by an HTML element to your specifications by using the
+ * {@link Ext.Component#autoEl autoEl}
config option. This is a useful technique when creating
+ * embedded {@link Ext.layout.ColumnLayout column} layouts inside {@link Ext.form.FormPanel FormPanels}
+ * for example.
The code below illustrates both how to explicitly create a Container, and how to implicitly
+ * create one using the 'container'
xtype:
+// explicitly create a Container
+var embeddedColumns = new Ext.Container({
+ autoEl: 'div', // This is the default
+ layout: 'column',
+ defaults: {
+ // implicitly create Container by specifying xtype
+ xtype: 'container',
+ autoEl: 'div', // This is the default.
+ layout: 'form',
+ columnWidth: 0.5,
+ style: {
+ padding: '10px'
+ }
+ },
+// The two items below will be Ext.Containers, each encapsulated by a <DIV> element.
+ items: [{
+ items: {
+ xtype: 'datefield',
+ name: 'startDate',
+ fieldLabel: 'Start date'
+ }
+ }, {
+ items: {
+ xtype: 'datefield',
+ name: 'endDate',
+ fieldLabel: 'End date'
+ }
+ }]
+});
+ *
+ * Layout
+ *Container classes delegate the rendering of child Components to a layout
+ * manager class which must be configured into the Container using the
+ * {@link #layout}
configuration property.
When either specifying child {@link #items}
of a Container,
+ * or dynamically {@link #add adding} Components to a Container, remember to
+ * consider how you wish the Container to arrange those child elements, and
+ * whether those child elements need to be sized using one of Ext's built-in
+ * {@link #layout}
schemes. By default, Containers use the
+ * {@link Ext.layout.ContainerLayout ContainerLayout} scheme which only
+ * renders child components, appending them one after the other inside the
+ * Container, and does not apply any sizing at all.
A common mistake is when a developer neglects to specify a
+ * {@link #layout}
(e.g. widgets like GridPanels or
+ * TreePanels are added to Containers for which no {@link #layout}
+ * has been specified). If a Container is left to use the default
+ * {@link Ext.layout.ContainerLayout ContainerLayout} scheme, none of its
+ * child components will be resized, or changed in any way when the Container
+ * is resized.
Certain layout managers allow dynamic addition of child components. + * Those that do include {@link Ext.layout.CardLayout}, + * {@link Ext.layout.AnchorLayout}, {@link Ext.layout.FormLayout}, and + * {@link Ext.layout.TableLayout}. For example:
+// Create the GridPanel.
+var myNewGrid = new Ext.grid.GridPanel({
+ store: myStore,
+ columns: myColumnModel,
+ title: 'Results', // the title becomes the title of the tab
+});
-Ext.layout.ContainerLayout.prototype = {
- /**
- * @cfg {String} extraCls
- * An optional extra CSS class that will be added to the container. This can be useful for adding
- * customized styles to the container or any of its children using standard CSS rules. See
- * {@link Ext.Component}.{@link Ext.Component#ctCls ctCls} also.
- * Note: extraCls defaults to '' except for the following classes
- * which assign a value by default:
- *
- * - {@link Ext.layout.AbsoluteLayout Absolute Layout} : 'x-abs-layout-item'
- * - {@link Ext.layout.Box Box Layout} : 'x-box-item'
- * - {@link Ext.layout.ColumnLayout Column Layout} : 'x-column'
- *
- * To configure the above Classes with an extra CSS class append to the default. For example,
- * for ColumnLayout:
- * extraCls: 'x-column custom-class'
+myTabPanel.add(myNewGrid); // {@link Ext.TabPanel} implicitly uses {@link Ext.layout.CardLayout CardLayout}
+myTabPanel.{@link Ext.TabPanel#setActiveTab setActiveTab}(myNewGrid);
+ *
+ * The example above adds a newly created GridPanel to a TabPanel. Note that
+ * a TabPanel uses {@link Ext.layout.CardLayout} as its layout manager which
+ * means all its child items are sized to {@link Ext.layout.FitLayout fit}
+ * exactly into its client area.
+ *
Overnesting is a common problem.
+ * An example of overnesting occurs when a GridPanel is added to a TabPanel
+ * by wrapping the GridPanel inside a wrapping Panel (that has no
+ * {@link #layout}
specified) and then add that wrapping Panel
+ * to the TabPanel. The point to realize is that a GridPanel is a
+ * Component which can be added directly to a Container. If the wrapping Panel
+ * has no {@link #layout}
configuration, then the overnested
+ * GridPanel will not be sized as expected.
+ *
+ *
Adding via remote configuration
+ *
+ * A server side script can be used to add Components which are generated dynamically on the server.
+ * An example of adding a GridPanel to a TabPanel where the GridPanel is generated by the server
+ * based on certain parameters:
+ *
+// execute an Ajax request to invoke server side script:
+Ext.Ajax.request({
+ url: 'gen-invoice-grid.php',
+ // send additional parameters to instruct server script
+ params: {
+ startDate: Ext.getCmp('start-date').getValue(),
+ endDate: Ext.getCmp('end-date').getValue()
+ },
+ // process the response object to add it to the TabPanel:
+ success: function(xhr) {
+ var newComponent = eval(xhr.responseText); // see discussion below
+ myTabPanel.add(newComponent); // add the component to the TabPanel
+ myTabPanel.setActiveTab(newComponent);
+ },
+ failure: function() {
+ Ext.Msg.alert("Grid create failed", "Server communication failure");
+ }
+});
+
+ * The server script needs to return an executable Javascript statement which, when processed
+ * using eval()
, will return either a config object with an {@link Ext.Component#xtype xtype},
+ * or an instantiated Component. The server might return this for example:
+(function() {
+ function formatDate(value){
+ return value ? value.dateFormat('M d, Y') : '';
+ };
+
+ var store = new Ext.data.Store({
+ url: 'get-invoice-data.php',
+ baseParams: {
+ startDate: '01/01/2008',
+ endDate: '01/31/2008'
+ },
+ reader: new Ext.data.JsonReader({
+ record: 'transaction',
+ idProperty: 'id',
+ totalRecords: 'total'
+ }, [
+ 'customer',
+ 'invNo',
+ {name: 'date', type: 'date', dateFormat: 'm/d/Y'},
+ {name: 'value', type: 'float'}
+ ])
+ });
+
+ var grid = new Ext.grid.GridPanel({
+ title: 'Invoice Report',
+ bbar: new Ext.PagingToolbar(store),
+ store: store,
+ columns: [
+ {header: "Customer", width: 250, dataIndex: 'customer', sortable: true},
+ {header: "Invoice Number", width: 120, dataIndex: 'invNo', sortable: true},
+ {header: "Invoice Date", width: 100, dataIndex: 'date', renderer: formatDate, sortable: true},
+ {header: "Value", width: 120, dataIndex: 'value', renderer: 'usMoney', sortable: true}
+ ],
+ });
+ store.load();
+ return grid; // return instantiated component
+})();
+
+ * When the above code fragment is passed through the eval
function in the success handler
+ * of the Ajax request, the code is executed by the Javascript processor, and the anonymous function
+ * runs, and returns the instantiated grid component.
+ * Note: since the code above is generated by a server script, the baseParams
for
+ * the Store, the metadata to allow generation of the Record layout, and the ColumnModel
+ * can all be generated into the code since these are all known on the server.
+ *
+ * @xtype container
+ */
+Ext.Container = Ext.extend(Ext.BoxComponent, {
+ /**
+ * @cfg {Boolean} monitorResize
+ * True to automatically monitor window resize events to handle anything that is sensitive to the current size
+ * of the viewport. This value is typically managed by the chosen {@link #layout}
and should not need
+ * to be set manually.
+ */
+ /**
+ * @cfg {String/Object} layout
+ * *Important: In order for child items to be correctly sized and
+ * positioned, typically a layout manager must be specified through
+ * the layout
configuration option.
+ *
The sizing and positioning of child {@link items} is the responsibility of
+ * the Container's layout manager which creates and manages the type of layout
+ * you have in mind. For example:
+new Ext.Window({
+ width:300, height: 300,
+ layout: 'fit', // explicitly set layout manager: override the default (layout:'auto')
+ items: [{
+ title: 'Panel inside a Window'
+ }]
+}).show();
*
- *
+ * If the {@link #layout} configuration is not explicitly specified for
+ * a general purpose container (e.g. Container or Panel) the
+ * {@link Ext.layout.ContainerLayout default layout manager} will be used
+ * which does nothing but render child components sequentially into the
+ * Container (no sizing or positioning will be performed in this situation).
+ * Some container classes implicitly specify a default layout
+ * (e.g. FormPanel specifies layout:'form'
). Other specific
+ * purpose classes internally specify/manage their internal layout (e.g.
+ * GridPanel, TabPanel, TreePanel, Toolbar, Menu, etc.).
+ *
layout
may be specified as either as an Object or
+ * as a String:
+ *
+ * - Specify as an Object
+ *
+ * - Example usage:
+
+layout: {
+ type: 'vbox',
+ padding: '5',
+ align: 'left'
+}
+
+ *
+ * type
+ *
The layout type to be used for this container. If not specified,
+ * a default {@link Ext.layout.ContainerLayout} will be created and used.
+ *
Valid layout type
values are:
+ *
+ * {@link Ext.layout.AbsoluteLayout absolute}
+ * {@link Ext.layout.AccordionLayout accordion}
+ * {@link Ext.layout.AnchorLayout anchor}
+ * {@link Ext.layout.ContainerLayout auto}
Default
+ * {@link Ext.layout.BorderLayout border}
+ * {@link Ext.layout.CardLayout card}
+ * {@link Ext.layout.ColumnLayout column}
+ * {@link Ext.layout.FitLayout fit}
+ * {@link Ext.layout.FormLayout form}
+ * {@link Ext.layout.HBoxLayout hbox}
+ * {@link Ext.layout.MenuLayout menu}
+ * {@link Ext.layout.TableLayout table}
+ * {@link Ext.layout.ToolbarLayout toolbar}
+ * {@link Ext.layout.VBoxLayout vbox}
+ *
+ *
+ * - Layout specific configuration properties
+ *
Additional layout specific configuration properties may also be
+ * specified. For complete details regarding the valid config options for
+ * each layout type, see the layout class corresponding to the type
+ * specified.
+ *
+ *
+ *
+ * - Specify as a String
+ *
+ * - Example usage:
+
+layout: 'vbox',
+layoutConfig: {
+ padding: '5',
+ align: 'left'
+}
+
+ * layout
+ *
The layout type
to be used for this container (see list
+ * of valid layout type values above).
+ * {@link #layoutConfig}
+ *
Additional layout specific configuration properties. For complete
+ * details regarding the valid config options for each layout type, see the
+ * layout class corresponding to the layout
specified.
+ *
*/
/**
- * @cfg {Boolean} renderHidden
- * True to hide each contained item on render (defaults to false).
+ * @cfg {Object} layoutConfig
+ * This is a config object containing properties specific to the chosen
+ * {@link #layout}
if {@link #layout}
+ * has been specified as a string.
+ */
+ /**
+ * @cfg {Boolean/Number} bufferResize
+ * When set to true (50 milliseconds) or a number of milliseconds, the layout assigned for this container will buffer
+ * the frequency it calculates and does a re-layout of components. This is useful for heavy containers or containers
+ * with a large quantity of sub-components for which frequent layout calls would be expensive. Defaults to 50
.
*/
+ bufferResize: 50,
/**
- * A reference to the {@link Ext.Component} that is active. For example,
- * if(myPanel.layout.activeItem.id == 'item-1') { ... }
- *
- * activeItem only applies to layout styles that can display items one at a time
- * (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout}
- * and {@link Ext.layout.FitLayout}). Read-only. Related to {@link Ext.Container#activeItem}.
- * @type {Ext.Component}
- * @property activeItem
+ * @cfg {String/Number} activeItem
+ * A string component id or the numeric index of the component that should be initially activated within the
+ * container's layout on render. For example, activeItem: 'item-1' or activeItem: 0 (index 0 = the first
+ * item in the container's collection). activeItem only applies to layout styles that can display
+ * items one at a time (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout} and
+ * {@link Ext.layout.FitLayout}). Related to {@link Ext.layout.ContainerLayout#activeItem}.
*/
+ /**
+ * @cfg {Object/Array} items
+ * ** IMPORTANT: be sure to {@link #layout specify a layout
} if needed ! **
+ * A single item, or an array of child Components to be added to this container,
+ * for example:
+ *
+// specifying a single item
+items: {...},
+layout: 'fit', // specify a layout!
- // private
- monitorResize:false,
- // private
- activeItem : null,
+// specifying multiple items
+items: [{...}, {...}],
+layout: 'anchor', // specify a layout!
+ *
+ * Each item may be:
+ *
+ * - any type of object based on {@link Ext.Component}
+ * - a fully instanciated object or
+ * - an object literal that:
+ *
+ * - has a specified
{@link Ext.Component#xtype xtype}
+ * - the {@link Ext.Component#xtype} specified is associated with the Component
+ * desired and should be chosen from one of the available xtypes as listed
+ * in {@link Ext.Component}.
+ * - If an
{@link Ext.Component#xtype xtype}
is not explicitly
+ * specified, the {@link #defaultType} for that Container is used.
+ * - will be "lazily instanciated", avoiding the overhead of constructing a fully
+ * instanciated Component object
+ *
+ * Notes:
+ *
+ * - Ext uses lazy rendering. Child Components will only be rendered
+ * should it become necessary. Items are automatically laid out when they are first
+ * shown (no sizing is done while hidden), or in response to a {@link #doLayout} call.
+ * - Do not specify
{@link Ext.Panel#contentEl contentEl}
/
+ * {@link Ext.Panel#html html}
with items
.
+ *
+ */
+ /**
+ * @cfg {Object|Function} defaults
+ * This option is a means of applying default settings to all added items whether added through the {@link #items}
+ * config or via the {@link #add} or {@link #insert} methods.
+ * If an added item is a config object, and not an instantiated Component, then the default properties are
+ * unconditionally applied. If the added item is an instantiated Component, then the default properties are
+ * applied conditionally so as not to override existing properties in the item.
+ * If the defaults option is specified as a function, then the function will be called using this Container as the
+ * scope (this
reference) and passing the added item as the first parameter. Any resulting object
+ * from that call is then applied to the item as default properties.
+ * For example, to automatically apply padding to the body of each of a set of
+ * contained {@link Ext.Panel} items, you could pass: defaults: {bodyStyle:'padding:15px'}
.
+ * Usage:
+defaults: { // defaults are applied to items, not the container
+ autoScroll:true
+},
+items: [
+ {
+ xtype: 'panel', // defaults do not have precedence over
+ id: 'panel1', // options in config objects, so the defaults
+ autoScroll: false // will not be applied here, panel1 will be autoScroll:false
+ },
+ new Ext.Panel({ // defaults do have precedence over options
+ id: 'panel2', // options in components, so the defaults
+ autoScroll: false // will be applied here, panel2 will be autoScroll:true.
+ })
+]
+ *
+ */
+
+
+ /** @cfg {Boolean} autoDestroy
+ * If true the container will automatically destroy any contained component that is removed from it, else
+ * destruction must be handled manually (defaults to true).
+ */
+ autoDestroy : true,
+
+ /** @cfg {Boolean} forceLayout
+ * If true the container will force a layout initially even if hidden or collapsed. This option
+ * is useful for forcing forms to render in collapsed or hidden containers. (defaults to false).
+ */
+ forceLayout: false,
+
+ /** @cfg {Boolean} hideBorders
+ * True to hide the borders of each contained component, false to defer to the component's existing
+ * border settings (defaults to false).
+ */
+ /** @cfg {String} defaultType
+ * The default {@link Ext.Component xtype} of child Components to create in this Container when
+ * a child item is specified as a raw configuration object, rather than as an instantiated Component.
+ * Defaults to 'panel'
, except {@link Ext.menu.Menu} which defaults to 'menuitem'
,
+ * and {@link Ext.Toolbar} and {@link Ext.ButtonGroup} which default to 'button'
.
+ */
+ defaultType : 'panel',
+
+ /** @cfg {String} resizeEvent
+ * The event to listen to for resizing in layouts. Defaults to 'resize'
.
+ */
+ resizeEvent: 'resize',
+
+ /**
+ * @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 ['add', 'remove']
.
+ */
+ bubbleEvents: ['add', 'remove'],
// private
- layout : function(){
- var target = this.container.getLayoutTarget();
- this.onLayout(this.container, target);
- this.container.fireEvent('afterlayout', this.container, this);
+ initComponent : function(){
+ Ext.Container.superclass.initComponent.call(this);
+
+ this.addEvents(
+ /**
+ * @event afterlayout
+ * Fires when the components in this container are arranged by the associated layout manager.
+ * @param {Ext.Container} this
+ * @param {ContainerLayout} layout The ContainerLayout implementation for this container
+ */
+ 'afterlayout',
+ /**
+ * @event beforeadd
+ * Fires before any {@link Ext.Component} is added or inserted into the container.
+ * A handler can return false to cancel the add.
+ * @param {Ext.Container} this
+ * @param {Ext.Component} component The component being added
+ * @param {Number} index The index at which the component will be added to the container's items collection
+ */
+ 'beforeadd',
+ /**
+ * @event beforeremove
+ * Fires before any {@link Ext.Component} is removed from the container. A handler can return
+ * false to cancel the remove.
+ * @param {Ext.Container} this
+ * @param {Ext.Component} component The component being removed
+ */
+ 'beforeremove',
+ /**
+ * @event add
+ * @bubbles
+ * Fires after any {@link Ext.Component} is added or inserted into the container.
+ * @param {Ext.Container} this
+ * @param {Ext.Component} component The component that was added
+ * @param {Number} index The index at which the component was added to the container's items collection
+ */
+ 'add',
+ /**
+ * @event remove
+ * @bubbles
+ * Fires after any {@link Ext.Component} is removed from the container.
+ * @param {Ext.Container} this
+ * @param {Ext.Component} component The component that was removed
+ */
+ 'remove'
+ );
+
+ this.enableBubble(this.bubbleEvents);
+
+ /**
+ * The collection of components in this container as a {@link Ext.util.MixedCollection}
+ * @type MixedCollection
+ * @property items
+ */
+ var items = this.items;
+ if(items){
+ delete this.items;
+ this.add(items);
+ }
},
// private
- onLayout : function(ct, target){
- this.renderAll(ct, target);
+ initItems : function(){
+ if(!this.items){
+ this.items = new Ext.util.MixedCollection(false, this.getComponentId);
+ this.getLayout(); // initialize the layout
+ }
},
// private
- isValidParent : function(c, target){
- return target && c.getDomPositionEl().dom.parentNode == (target.dom || target);
+ setLayout : function(layout){
+ if(this.layout && this.layout != layout){
+ this.layout.setContainer(null);
+ }
+ this.initItems();
+ this.layout = layout;
+ layout.setContainer(this);
+ },
+
+ afterRender: function(){
+ this.layoutDone = false;
+ if(!this.layout){
+ this.layout = 'auto';
+ }
+ if(Ext.isObject(this.layout) && !this.layout.layout){
+ this.layoutConfig = this.layout;
+ this.layout = this.layoutConfig.type;
+ }
+ if(Ext.isString(this.layout)){
+ this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig);
+ }
+ this.setLayout(this.layout);
+
+ // BoxComponent's afterRender will set the size.
+ // This will will trigger a layout if the layout is configured to monitor resize
+ Ext.Container.superclass.afterRender.call(this);
+
+ if(Ext.isDefined(this.activeItem)){
+ var item = this.activeItem;
+ delete this.activeItem;
+ this.layout.setActiveItem(item);
+ }
+
+ // If we have no ownerCt and the BoxComponent's sizing did not trigger a layout, force a layout
+ if(!this.ownerCt && !this.layoutDone){
+ this.doLayout(false, true);
+ }
+
+ if(this.monitorResize === true){
+ Ext.EventManager.onWindowResize(this.doLayout, this, [false]);
+ }
+ },
+
+ /**
+ *
Returns the Element to be used to contain the child Components of this Container.
+ * An implementation is provided which returns the Container's {@link #getEl Element}, but
+ * if there is a more complex structure to a Container, this may be overridden to return
+ * the element into which the {@link #layout layout} renders child Components.
+ * @return {Ext.Element} The Element to render child Components into.
+ */
+ getLayoutTarget : function(){
+ return this.el;
+ },
+
+ // private - used as the key lookup function for the items collection
+ getComponentId : function(comp){
+ return comp.getItemId();
+ },
+
+ /**
+ * Adds {@link Ext.Component Component}(s) to this Container.
+ *
Description :
+ *
+ * - Fires the {@link #beforeadd} event before adding
+ * - The Container's {@link #defaults default config values} will be applied
+ * accordingly (see
{@link #defaults}
for details).
+ * - Fires the {@link #add} event after the component has been added.
+ *
+ *
Notes :
+ *
+ * - If the Container is already rendered when
add
+ * is called, you may need to call {@link #doLayout} to refresh the view which causes
+ * any unrendered child Components to be rendered. This is required so that you can
+ * add
multiple child components if needed while only refreshing the layout
+ * once. For example:
+var tb = new {@link Ext.Toolbar}();
+tb.render(document.body); // toolbar is rendered
+tb.add({text:'Button 1'}); // add multiple items ({@link #defaultType} for {@link Ext.Toolbar Toolbar} is 'button')
+tb.add({text:'Button 2'});
+tb.{@link #doLayout}(); // refresh the layout
+ *
+ * - Warning: Containers directly managed by the BorderLayout layout manager
+ * may not be removed or added. See the Notes for {@link Ext.layout.BorderLayout BorderLayout}
+ * for more details.
+ *
+ * @param {Object/Array} component
+ * Either a single component or an Array of components to add. See
+ * {@link #items}
for additional information.
+ * @param {Object} (Optional) component_2
+ * @param {Object} (Optional) component_n
+ * @return {Ext.Component} component The Component (or config object) that was added.
+ */
+ add : function(comp){
+ this.initItems();
+ var args = arguments.length > 1;
+ if(args || Ext.isArray(comp)){
+ var result = [];
+ Ext.each(args ? arguments : comp, function(c){
+ result.push(this.add(c));
+ }, this);
+ return result;
+ }
+ var c = this.lookupComponent(this.applyDefaults(comp));
+ var index = this.items.length;
+ if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){
+ this.items.add(c);
+ // *onAdded
+ c.onAdded(this, index);
+ this.onAdd(c);
+ this.fireEvent('add', this, c, index);
+ }
+ return c;
},
+ onAdd : function(c){
+ // Empty template method
+ },
+
// private
- renderAll : function(ct, target){
- var items = ct.items.items;
- for(var i = 0, len = items.length; i < len; i++) {
- var c = items[i];
- if(c && (!c.rendered || !this.isValidParent(c, target))){
- this.renderItem(c, i, target);
+ onAdded : function(container, pos) {
+ //overridden here so we can cascade down, not worth creating a template method.
+ this.ownerCt = container;
+ this.initRef();
+ //initialize references for child items
+ this.cascade(function(c){
+ c.initRef();
+ });
+ this.fireEvent('added', this, container, pos);
+ },
+
+ /**
+ * Inserts a Component into this Container at a specified index. Fires the
+ * {@link #beforeadd} event before inserting, then fires the {@link #add} event after the
+ * Component has been inserted.
+ * @param {Number} index The index at which the Component will be inserted
+ * into the Container's items collection
+ * @param {Ext.Component} component The child Component to insert.
+ * Ext uses lazy rendering, and will only render the inserted Component should
+ * it become necessary.
+ * A Component config object may be passed in order to avoid the overhead of
+ * constructing a real Component object if lazy rendering might mean that the
+ * inserted Component will not be rendered immediately. To take advantage of
+ * this 'lazy instantiation', set the {@link Ext.Component#xtype} config
+ * property to the registered type of the Component wanted.
+ * For a list of all available xtypes, see {@link Ext.Component}.
+ * @return {Ext.Component} component The Component (or config object) that was
+ * inserted with the Container's default config values applied.
+ */
+ insert : function(index, comp){
+ this.initItems();
+ var a = arguments, len = a.length;
+ if(len > 2){
+ var result = [];
+ for(var i = len-1; i >= 1; --i) {
+ result.push(this.insert(index, a[i]));
+ }
+ return result;
+ }
+ var c = this.lookupComponent(this.applyDefaults(comp));
+ index = Math.min(index, this.items.length);
+ if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){
+ if(c.ownerCt == this){
+ this.items.remove(c);
}
+ this.items.insert(index, c);
+ c.onAdded(this, index);
+ this.onAdd(c);
+ this.fireEvent('add', this, c, index);
}
+ return c;
},
// private
- renderItem : function(c, position, target){
- if(c && !c.rendered){
- c.render(target, position);
- this.configureItem(c, position);
- }else if(c && !this.isValidParent(c, target)){
- if(Ext.isNumber(position)){
- position = target.dom.childNodes[position];
+ applyDefaults : function(c){
+ var d = this.defaults;
+ if(d){
+ if(Ext.isFunction(d)){
+ d = d.call(this, c);
+ }
+ if(Ext.isString(c)){
+ c = Ext.ComponentMgr.get(c);
+ Ext.apply(c, d);
+ }else if(!c.events){
+ Ext.applyIf(c, d);
+ }else{
+ Ext.apply(c, d);
}
- target.dom.insertBefore(c.getDomPositionEl().dom, position || null);
- c.container = target;
- this.configureItem(c, position);
}
+ return c;
},
-
+
// private
- configureItem: function(c, position){
- if(this.extraCls){
- var t = c.getPositionEl ? c.getPositionEl() : c;
- t.addClass(this.extraCls);
+ onBeforeAdd : function(item){
+ if(item.ownerCt){
+ item.ownerCt.remove(item, false);
}
- if (this.renderHidden && c != this.activeItem) {
- c.hide();
+ if(this.hideBorders === true){
+ item.border = (item.border === true);
}
- if(c.doLayout && this.forceLayout){
- c.doLayout(false, true);
+ },
+
+ /**
+ * Removes a component from this container. Fires the {@link #beforeremove} event before removing, then fires
+ * the {@link #remove} event after the component has been removed.
+ * @param {Component/String} component The component reference or id to remove.
+ * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
+ * Defaults to the value of this Container's {@link #autoDestroy} config.
+ * @return {Ext.Component} component The Component that was removed.
+ */
+ remove : function(comp, autoDestroy){
+ this.initItems();
+ var c = this.getComponent(comp);
+ if(c && this.fireEvent('beforeremove', this, c) !== false){
+ this.doRemove(c, autoDestroy);
+ this.fireEvent('remove', this, c);
}
+ return c;
},
-
+
onRemove: function(c){
- if(this.activeItem == c){
- delete this.activeItem;
- }
- if(c.rendered && this.extraCls){
- var t = c.getPositionEl ? c.getPositionEl() : c;
- t.removeClass(this.extraCls);
- }
+ // Empty template method
},
// private
- onResize: function(){
- var ct = this.container,
- b;
-
- if(ct.collapsed){
- return;
+ doRemove: function(c, autoDestroy){
+ if(this.layout && this.rendered){
+ this.layout.onRemove(c);
}
- if(b = ct.bufferResize){
- // Only allow if we should buffer the layout
- if(ct.shouldBufferLayout()){
- if(!this.resizeTask){
- this.resizeTask = new Ext.util.DelayedTask(this.runLayout, this);
- this.resizeBuffer = Ext.isNumber(b) ? b : 50;
- }
- ct.layoutPending = true;
- this.resizeTask.delay(this.resizeBuffer);
+ this.items.remove(c);
+ c.onRemoved();
+ this.onRemove(c);
+ if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){
+ c.destroy();
+ }
+ },
+
+ /**
+ * Removes all components from this container.
+ * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
+ * Defaults to the value of this Container's {@link #autoDestroy} config.
+ * @return {Array} Array of the destroyed components
+ */
+ removeAll: function(autoDestroy){
+ this.initItems();
+ var item, rem = [], items = [];
+ this.items.each(function(i){
+ rem.push(i);
+ });
+ for (var i = 0, len = rem.length; i < len; ++i){
+ item = rem[i];
+ this.remove(item, autoDestroy);
+ if(item.ownerCt !== this){
+ items.push(item);
}
- }else{
- ct.doLayout();
}
+ return items;
},
-
+
+ /**
+ * Examines this container's {@link #items}
property
+ * and gets a direct child component of this container.
+ * @param {String/Number} comp This parameter may be any of the following:
+ *
+ * - a
String
: representing the {@link Ext.Component#itemId itemId}
+ * or {@link Ext.Component#id id}
of the child component
+ * - a
Number
: representing the position of the child component
+ * within the {@link #items}
property
+ *
+ * For additional information see {@link Ext.util.MixedCollection#get}.
+ * @return Ext.Component The component (if found).
+ */
+ getComponent : function(comp){
+ if(Ext.isObject(comp)){
+ comp = comp.getItemId();
+ }
+ return this.items.get(comp);
+ },
+
// private
- runLayout: function(){
- var ct = this.container;
- ct.doLayout();
- delete ct.layoutPending;
+ lookupComponent : function(comp){
+ if(Ext.isString(comp)){
+ return Ext.ComponentMgr.get(comp);
+ }else if(!comp.events){
+ return this.createComponent(comp);
+ }
+ return comp;
},
// private
- setContainer : function(ct){
- if(this.monitorResize && ct != this.container){
- var old = this.container;
- if(old){
- old.un(old.resizeEvent, this.onResize, this);
+ createComponent : function(config, defaultType){
+ // add in ownerCt at creation time but then immediately
+ // remove so that onBeforeAdd can handle it
+ var c = config.render ? config : Ext.create(Ext.apply({
+ ownerCt: this
+ }, config), defaultType || this.defaultType);
+ delete c.ownerCt;
+ return c;
+ },
+
+ /**
+ * We can only lay out if there is a view area in which to layout.
+ * display:none on the layout target, *or any of its parent elements* will mean it has no view area.
+ */
+ canLayout: function() {
+ var el = this.getLayoutTarget(), vs;
+ return !!(el && (vs = el.dom.offsetWidth || el.dom.offsetHeight));
+ },
+
+ /**
+ * Force this container's layout to be recalculated. A call to this function is required after adding a new component
+ * to an already rendered container, or possibly after changing sizing/position properties of child components.
+ * @param {Boolean} shallow (optional) True to only calc the layout of this component, and let child components auto
+ * calc layouts as required (defaults to false, which calls doLayout recursively for each subcontainer)
+ * @param {Boolean} force (optional) True to force a layout to occur, even if the item is hidden.
+ * @return {Ext.Container} this
+ */
+ doLayout: function(shallow, force){
+ var rendered = this.rendered,
+ forceLayout = force || this.forceLayout,
+ cs, i, len, c;
+
+ this.layoutDone = true;
+ if(!this.canLayout() || this.collapsed){
+ this.deferLayout = this.deferLayout || !shallow;
+ if(!forceLayout){
+ return;
}
- if(ct){
- ct.on(ct.resizeEvent, this.onResize, this);
+ shallow = shallow && !this.deferLayout;
+ } else {
+ delete this.deferLayout;
+ }
+
+ cs = (shallow !== true && this.items) ? this.items.items : [];
+
+// Inhibit child Containers from relaying on resize since we are about to to explicitly call doLayout on them all!
+ for(i = 0, len = cs.length; i < len; i++){
+ if ((c = cs[i]).layout) {
+ c.suspendLayoutResize = true;
}
}
- this.container = ct;
+
+// Tell the layout manager to ensure all child items are rendered, and sized according to their rules.
+// Will not cause the child items to relayout.
+ if(rendered && this.layout){
+ this.layout.layout();
+ }
+
+// Explicitly lay out all child items
+ for(i = 0; i < len; i++){
+ if((c = cs[i]).doLayout){
+ c.doLayout(false, forceLayout);
+ }
+ }
+ if(rendered){
+ this.onLayout(shallow, forceLayout);
+ }
+ // Initial layout completed
+ this.hasLayout = true;
+ delete this.forceLayout;
+
+// Re-enable child layouts relaying on resize.
+ for(i = 0; i < len; i++){
+ if ((c = cs[i]).layout) {
+ delete c.suspendLayoutResize;
+ }
+ }
+ },
+
+ //private
+ onLayout : Ext.emptyFn,
+
+ onResize: function(adjWidth, adjHeight, rawWidth, rawHeight){
+ Ext.Container.superclass.onResize.apply(this, arguments);
+ if ((this.rendered && this.layout && this.layout.monitorResize) && !this.suspendLayoutResize) {
+ this.layout.onResize();
+ }
},
// private
- parseMargins : function(v){
- if(Ext.isNumber(v)){
- v = v.toString();
+ hasLayoutPending: function(){
+ // Traverse hierarchy to see if any parent container has a pending layout.
+ var pending = this.layoutPending;
+ this.ownerCt.bubble(function(c){
+ return !(pending = c.layoutPending);
+ });
+ return pending;
+
+ },
+
+ onShow : function(){
+ Ext.Container.superclass.onShow.call(this);
+ if(Ext.isDefined(this.deferLayout)){
+ this.doLayout(true);
}
- var ms = v.split(' ');
- var len = ms.length;
- if(len == 1){
- ms[1] = ms[0];
- ms[2] = ms[0];
- ms[3] = ms[0];
+ },
+
+ /**
+ * Returns the layout currently in use by the container. If the container does not currently have a layout
+ * set, a default {@link Ext.layout.ContainerLayout} will be created and set as the container's layout.
+ * @return {ContainerLayout} layout The container's layout
+ */
+ getLayout : function(){
+ if(!this.layout){
+ var layout = new Ext.layout.ContainerLayout(this.layoutConfig);
+ this.setLayout(layout);
}
- if(len == 2){
- ms[2] = ms[0];
- ms[3] = ms[1];
+ return this.layout;
+ },
+
+ // private
+ beforeDestroy : function(){
+ var c;
+ if(this.items){
+ while(c = this.items.first()){
+ this.doRemove(c, true);
+ }
}
- if(len == 3){
- ms[3] = ms[1];
+ if(this.monitorResize){
+ Ext.EventManager.removeResizeListener(this.doLayout, this);
}
- return {
- top:parseInt(ms[0], 10) || 0,
- right:parseInt(ms[1], 10) || 0,
- bottom:parseInt(ms[2], 10) || 0,
- left:parseInt(ms[3], 10) || 0
- };
+ Ext.destroy(this.layout);
+ Ext.Container.superclass.beforeDestroy.call(this);
},
/**
- * The {@link Ext.Template Ext.Template} used by Field rendering layout classes (such as
- * {@link Ext.layout.FormLayout}) to create the DOM structure of a fully wrapped,
- * labeled and styled form Field. A default Template is supplied, but this may be
- * overriden to create custom field structures. The template processes values returned from
- * {@link Ext.layout.FormLayout#getTemplateArgs}.
- * @property fieldTpl
- * @type Ext.Template
- */
- fieldTpl: (function() {
- var t = new Ext.Template(
- '
',
- '',
- '',
- '',
- ''
- );
- t.disableFormats = true;
- return t.compile();
- })(),
-
- /*
- * Destroys this layout. This is a template method that is empty by default, but should be implemented
- * by subclasses that require explicit destruction to purge event handlers or remove DOM nodes.
- * @protected
+ * 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.Container} this
*/
- destroy : Ext.emptyFn
-};
-Ext.Container.LAYOUTS['auto'] = Ext.layout.ContainerLayout;/**
- * @class Ext.layout.FitLayout
- * @extends Ext.layout.ContainerLayout
- * This is a base class for layouts that contain a single item that automatically expands to fill the layout's
- * container. This class is intended to be extended or created via the layout:'fit' {@link Ext.Container#layout}
- * config, and should generally not need to be created directly via the new keyword.
+ bubble : function(fn, scope, args){
+ var p = this;
+ while(p){
+ if(fn.apply(scope || p, args || [p]) === false){
+ break;
+ }
+ p = p.ownerCt;
+ }
+ return this;
+ },
+
+ /**
+ * Cascades down the component/container heirarchy from this component (called first), 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 cascade is stopped on that branch.
+ * @param {Function} fn The function to call
+ * @param {Object} scope (optional) The scope of the function (defaults to current component)
+ * @param {Array} args (optional) The args to call the function with (defaults to passing the current component)
+ * @return {Ext.Container} this
+ */
+ cascade : function(fn, scope, args){
+ if(fn.apply(scope || this, args || [this]) !== false){
+ if(this.items){
+ var cs = this.items.items;
+ for(var i = 0, len = cs.length; i < len; i++){
+ if(cs[i].cascade){
+ cs[i].cascade(fn, scope, args);
+ }else{
+ fn.apply(scope || cs[i], args || [cs[i]]);
+ }
+ }
+ }
+ }
+ return this;
+ },
+
+ /**
+ * Find a component under this container at any level by id
+ * @param {String} id
+ * @return Ext.Component
+ */
+ findById : function(id){
+ var m, ct = this;
+ this.cascade(function(c){
+ if(ct != c && c.id === id){
+ m = c;
+ return false;
+ }
+ });
+ return m || null;
+ },
+
+ /**
+ * Find a component under this container 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 {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 {Array} Array of Ext.Components
+ */
+ findByType : function(xtype, shallow){
+ return this.findBy(function(c){
+ return c.isXType(xtype, shallow);
+ });
+ },
+
+ /**
+ * Find a component under this container at any level by property
+ * @param {String} prop
+ * @param {String} value
+ * @return {Array} Array of Ext.Components
+ */
+ find : function(prop, value){
+ return this.findBy(function(c){
+ return c[prop] === value;
+ });
+ },
+
+ /**
+ * Find a component under this container at any level by a custom function. If the passed function returns
+ * true, the component will be included in the results. The passed function is called with the arguments (component, this container).
+ * @param {Function} fn The function to call
+ * @param {Object} scope (optional)
+ * @return {Array} Array of Ext.Components
+ */
+ findBy : function(fn, scope){
+ var m = [], ct = this;
+ this.cascade(function(c){
+ if(ct != c && fn.call(scope || c, c, ct) === true){
+ m.push(c);
+ }
+ });
+ return m;
+ },
+
+ /**
+ * Get a component contained by this container (alias for items.get(key))
+ * @param {String/Number} key The index or id of the component
+ * @return {Ext.Component} Ext.Component
+ */
+ get : function(key){
+ return this.items.get(key);
+ }
+});
+
+Ext.Container.LAYOUTS = {};
+Ext.reg('container', Ext.Container);
+/**
+ * @class Ext.layout.ContainerLayout
+ * The ContainerLayout class is the default layout manager delegated by {@link Ext.Container} to
+ * render any child Components when no {@link Ext.Container#layout layout} is configured into
+ * a {@link Ext.Container Container}. ContainerLayout provides the basic foundation for all other layout
+ * classes in Ext. It simply renders all child Components into the Container, performing no sizing or
+ * positioning services. To utilize a layout that provides sizing and positioning of child Components,
+ * specify an appropriate {@link Ext.Container#layout layout}.
+ * This class is intended to be extended or created via the {@link Ext.Container#layout layout}
+ * configuration property. See {@link Ext.Container#layout} for additional details.
+ */
+Ext.layout.ContainerLayout = Ext.extend(Object, {
+ /**
+ * @cfg {String} extraCls
+ * An optional extra CSS class that will be added to the container. This can be useful for adding
+ * customized styles to the container or any of its children using standard CSS rules. See
+ * {@link Ext.Component}.{@link Ext.Component#ctCls ctCls} also.
+ * Note: extraCls defaults to '' except for the following classes
+ * which assign a value by default:
+ *
+ * - {@link Ext.layout.AbsoluteLayout Absolute Layout} : 'x-abs-layout-item'
+ * - {@link Ext.layout.Box Box Layout} : 'x-box-item'
+ * - {@link Ext.layout.ColumnLayout Column Layout} : 'x-column'
+ *
+ * To configure the above Classes with an extra CSS class append to the default. For example,
+ * for ColumnLayout:
+ * extraCls: 'x-column custom-class'
+ *
+ *
+ */
+ /**
+ * @cfg {Boolean} renderHidden
+ * True to hide each contained item on render (defaults to false).
+ */
+
+ /**
+ * A reference to the {@link Ext.Component} that is active. For example,
+ * if(myPanel.layout.activeItem.id == 'item-1') { ... }
+ *
+ * activeItem only applies to layout styles that can display items one at a time
+ * (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout}
+ * and {@link Ext.layout.FitLayout}). Read-only. Related to {@link Ext.Container#activeItem}.
+ * @type {Ext.Component}
+ * @property activeItem
+ */
+
+ // private
+ monitorResize:false,
+ // private
+ activeItem : null,
+
+ constructor : function(config){
+ Ext.apply(this, config);
+ },
+
+ // private
+ layout : function(){
+ var target = this.container.getLayoutTarget();
+ if(!(this.hasLayout || Ext.isEmpty(this.targetCls))){
+ target.addClass(this.targetCls)
+ }
+ this.onLayout(this.container, target);
+ this.container.fireEvent('afterlayout', this.container, this);
+ this.hasLayout = true;
+ },
+
+ // private
+ onLayout : function(ct, target){
+ this.renderAll(ct, target);
+ },
+
+ // private
+ isValidParent : function(c, target){
+ return target && c.getPositionEl().dom.parentNode == (target.dom || target);
+ },
+
+ // private
+ renderAll : function(ct, target){
+ var items = ct.items.items;
+ for(var i = 0, len = items.length; i < len; i++) {
+ var c = items[i];
+ if(c && (!c.rendered || !this.isValidParent(c, target))){
+ this.renderItem(c, i, target);
+ }
+ }
+ },
+
+ // private
+ renderItem : function(c, position, target){
+ if(c && !c.rendered){
+ c.render(target, position);
+ this.configureItem(c, position);
+ }else if(c && !this.isValidParent(c, target)){
+ if(Ext.isNumber(position)){
+ position = target.dom.childNodes[position];
+ }
+ target.dom.insertBefore(c.getPositionEl().dom, position || null);
+ c.container = target;
+ this.configureItem(c, position);
+ }
+ },
+
+ // private
+ configureItem: function(c, position){
+ if(this.extraCls){
+ var t = c.getPositionEl ? c.getPositionEl() : c;
+ t.addClass(this.extraCls);
+ }
+ // If we are forcing a layout, do so *before* we hide so elements have height/width
+ if(c.doLayout && this.forceLayout){
+ c.doLayout(false, true);
+ }
+ if (this.renderHidden && c != this.activeItem) {
+ c.hide();
+ }
+ },
+
+ onRemove: function(c){
+ if(this.activeItem == c){
+ delete this.activeItem;
+ }
+ if(c.rendered && this.extraCls){
+ var t = c.getPositionEl ? c.getPositionEl() : c;
+ t.removeClass(this.extraCls);
+ }
+ },
+
+ // private
+ onResize: function(){
+ var ct = this.container,
+ b = ct.bufferResize;
+
+ if (ct.collapsed){
+ return;
+ }
+
+ // Not having an ownerCt negates the buffering: floating and top level
+ // Containers (Viewport, Window, ToolTip, Menu) need to lay out ASAP.
+ if (b && ct.ownerCt) {
+ // If we do NOT already have a layout pending from an ancestor, schedule one.
+ // If there is a layout pending, we do nothing here.
+ // buffering to be deprecated soon
+ if (!ct.hasLayoutPending()){
+ if(!this.resizeTask){
+ this.resizeTask = new Ext.util.DelayedTask(this.runLayout, this);
+ this.resizeBuffer = Ext.isNumber(b) ? b : 50;
+ }
+ ct.layoutPending = true;
+ this.resizeTask.delay(this.resizeBuffer);
+ }
+ }else{
+ ct.doLayout(false, this.forceLayout);
+ }
+ },
+
+ // private
+ runLayout: function(){
+ var ct = this.container;
+ ct.doLayout();
+ delete ct.layoutPending;
+ },
+
+ // private
+ setContainer : function(ct){
+ // No longer use events to handle resize. Instead this will be handled through a direct function call.
+ /*
+ if(this.monitorResize && ct != this.container){
+ var old = this.container;
+ if(old){
+ old.un(old.resizeEvent, this.onResize, this);
+ }
+ if(ct){
+ ct.on(ct.resizeEvent, this.onResize, this);
+ }
+ }
+ */
+ this.container = ct;
+ },
+
+ // private
+ parseMargins : function(v){
+ if(Ext.isNumber(v)){
+ v = v.toString();
+ }
+ var ms = v.split(' ');
+ var len = ms.length;
+ if(len == 1){
+ ms[1] = ms[0];
+ ms[2] = ms[0];
+ ms[3] = ms[0];
+ }
+ if(len == 2){
+ ms[2] = ms[0];
+ ms[3] = ms[1];
+ }
+ if(len == 3){
+ ms[3] = ms[1];
+ }
+ return {
+ top:parseInt(ms[0], 10) || 0,
+ right:parseInt(ms[1], 10) || 0,
+ bottom:parseInt(ms[2], 10) || 0,
+ left:parseInt(ms[3], 10) || 0
+ };
+ },
+
+ /**
+ * The {@link Ext.Template Ext.Template} used by Field rendering layout classes (such as
+ * {@link Ext.layout.FormLayout}) to create the DOM structure of a fully wrapped,
+ * labeled and styled form Field. A default Template is supplied, but this may be
+ * overriden to create custom field structures. The template processes values returned from
+ * {@link Ext.layout.FormLayout#getTemplateArgs}.
+ * @property fieldTpl
+ * @type Ext.Template
+ */
+ fieldTpl: (function() {
+ var t = new Ext.Template(
+ '',
+ '',
+ '',
+ '',
+ ''
+ );
+ t.disableFormats = true;
+ return t.compile();
+ })(),
+
+ /*
+ * Destroys this layout. This is a template method that is empty by default, but should be implemented
+ * by subclasses that require explicit destruction to purge event handlers or remove DOM nodes.
+ * @protected
+ */
+ destroy : function(){
+ if(!Ext.isEmpty(this.targetCls)){
+ var target = this.container.getLayoutTarget();
+ if(target){
+ target.removeClass(this.targetCls);
+ }
+ }
+ }
+});
+Ext.Container.LAYOUTS['auto'] = Ext.layout.ContainerLayout;
+/**
+ * @class Ext.layout.FitLayout
+ * @extends Ext.layout.ContainerLayout
+ * This is a base class for layouts that contain a single item that automatically expands to fill the layout's
+ * container. This class is intended to be extended or created via the layout:'fit' {@link Ext.Container#layout}
+ * config, and should generally not need to be created directly via the new keyword.
* FitLayout does not have any direct config options (other than inherited ones). To fit a panel to a container
* using FitLayout, simply set layout:'fit' on the container and add a single panel to it. If the container has
* multiple panels, only the first one will be displayed. Example usage:
@@ -4744,8 +5077,7 @@ Ext.layout.FitLayout = Ext.extend(Ext.layout.ContainerLayout, {
onLayout : function(ct, target){
Ext.layout.FitLayout.superclass.onLayout.call(this, ct, target);
if(!this.container.collapsed){
- var sz = (Ext.isIE6 && Ext.isStrict && target.dom == document.body) ? target.getViewSize() : target.getStyleSize();
- this.setItemSize(this.activeItem || ct.items.itemAt(0), sz);
+ this.setItemSize(this.activeItem || ct.items.itemAt(0), target.getViewSize(true));
}
},
@@ -4845,7 +5177,7 @@ Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, {
constructor: function(config){
Ext.layout.CardLayout.superclass.constructor.call(this, config);
- this.forceLayout = (this.deferredRender === false);
+ // this.forceLayout = (this.deferredRender === false);
},
/**
@@ -4853,18 +5185,23 @@ Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, {
* @param {String/Number} item The string component id or numeric index of the item to activate
*/
setActiveItem : function(item){
+ var ai = this.activeItem;
item = this.container.getComponent(item);
- if(this.activeItem != item){
- if(this.activeItem){
- this.activeItem.hide();
+ if(ai != item){
+ if(ai){
+ ai.hide();
+ ai.fireEvent('deactivate', ai);
}
var layout = item.doLayout && (this.layoutOnCardChange || !item.rendered);
this.activeItem = item;
- item.show();
+ if(item){
+ item.show();
+ }
this.layout();
- if(layout){
+ if(item && layout){
item.doLayout();
}
+ item.fireEvent('activate', item);
}
},
@@ -4877,200 +5214,203 @@ Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, {
}
}
});
-Ext.Container.LAYOUTS['card'] = Ext.layout.CardLayout;/**
- * @class Ext.layout.AnchorLayout
- * @extends Ext.layout.ContainerLayout
- * This is a layout that enables anchoring of contained elements relative to the container's dimensions.
- * If the container is resized, all anchored items are automatically rerendered according to their
- * {@link #anchor} rules.
- * This class is intended to be extended or created via the layout:'anchor' {@link Ext.Container#layout}
- * config, and should generally not need to be created directly via the new keyword.
- * AnchorLayout does not have any direct config options (other than inherited ones). By default,
- * AnchorLayout will calculate anchor measurements based on the size of the container itself. However, the
- * container using the AnchorLayout can supply an anchoring-specific config property of anchorSize.
- * If anchorSize is specifed, the layout will use it as a virtual container for the purposes of calculating
- * anchor measurements based on it instead, allowing the container to be sized independently of the anchoring
- * logic if necessary. For example:
- *
-var viewport = new Ext.Viewport({
- layout:'anchor',
- anchorSize: {width:800, height:600},
- items:[{
- title:'Item 1',
- html:'Content 1',
- width:800,
- anchor:'right 20%'
- },{
- title:'Item 2',
- html:'Content 2',
- width:300,
- anchor:'50% 30%'
- },{
- title:'Item 3',
- html:'Content 3',
- width:600,
- anchor:'-100 50%'
- }]
-});
- *
- */
-Ext.layout.AnchorLayout = Ext.extend(Ext.layout.ContainerLayout, {
- /**
- * @cfg {String} anchor
- * This configuation option is to be applied to child items of a container managed by
- * this layout (ie. configured with layout:'anchor').
- *
- * This value is what tells the layout how an item should be anchored to the container. items
- * added to an AnchorLayout accept an anchoring-specific config property of anchor which is a string
- * containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%').
- * The following types of anchor values are supported:
- *
- * - Percentage : Any value between 1 and 100, expressed as a percentage.
- * The first anchor is the percentage width that the item should take up within the container, and the
- * second is the percentage height. For example:
-// two values specified
-anchor: '100% 50%' // render item complete width of the container and
- // 1/2 height of the container
-// one value specified
-anchor: '100%' // the width value; the height will default to auto
- *
- *
- * - Offsets : Any positive or negative integer value.
- * This is a raw adjustment where the first anchor is the offset from the right edge of the container,
- * and the second is the offset from the bottom edge. For example:
-// two values specified
-anchor: '-50 -100' // render item the complete width of the container
- // minus 50 pixels and
- // the complete height minus 100 pixels.
-// one value specified
-anchor: '-50' // anchor value is assumed to be the right offset value
- // bottom offset will default to 0
- *
- *
- * - Sides : Valid values are 'right' (or 'r') and 'bottom'
- * (or 'b').
- * Either the container must have a fixed size or an anchorSize config value defined at render time in
- * order for these to have any effect.
- *
- * - Mixed :
- * Anchor values can also be mixed as needed. For example, to render the width offset from the container
- * right edge by 50 pixels and 75% of the container's height use:
- *
-anchor: '-50 75%'
- *
- *
- *
- *
- */
-
- // private
- monitorResize:true,
-
- // private
- getAnchorViewSize : function(ct, target){
- return target.dom == document.body ?
- target.getViewSize() : target.getStyleSize();
- },
-
- // private
- onLayout : function(ct, target){
- Ext.layout.AnchorLayout.superclass.onLayout.call(this, ct, target);
-
- var size = this.getAnchorViewSize(ct, target);
-
- var w = size.width, h = size.height;
-
- if(w < 20 && h < 20){
- return;
- }
-
- // find the container anchoring size
- var aw, ah;
- if(ct.anchorSize){
- if(typeof ct.anchorSize == 'number'){
- aw = ct.anchorSize;
- }else{
- aw = ct.anchorSize.width;
- ah = ct.anchorSize.height;
- }
- }else{
- aw = ct.initialConfig.width;
- ah = ct.initialConfig.height;
- }
-
- var cs = ct.items.items, len = cs.length, i, c, a, cw, ch;
- for(i = 0; i < len; i++){
- c = cs[i];
- if(c.anchor){
- a = c.anchorSpec;
- if(!a){ // cache all anchor values
- var vs = c.anchor.split(' ');
- c.anchorSpec = a = {
- right: this.parseAnchor(vs[0], c.initialConfig.width, aw),
- bottom: this.parseAnchor(vs[1], c.initialConfig.height, ah)
- };
- }
- cw = a.right ? this.adjustWidthAnchor(a.right(w), c) : undefined;
- ch = a.bottom ? this.adjustHeightAnchor(a.bottom(h), c) : undefined;
-
- if(cw || ch){
- c.setSize(cw || undefined, ch || undefined);
- }
- }
- }
- },
-
- // private
- parseAnchor : function(a, start, cstart){
- if(a && a != 'none'){
- var last;
- if(/^(r|right|b|bottom)$/i.test(a)){ // standard anchor
- var diff = cstart - start;
- return function(v){
- if(v !== last){
- last = v;
- return v - diff;
- }
- }
- }else if(a.indexOf('%') != -1){
- var ratio = parseFloat(a.replace('%', ''))*.01; // percentage
- return function(v){
- if(v !== last){
- last = v;
- return Math.floor(v*ratio);
- }
- }
- }else{
- a = parseInt(a, 10);
- if(!isNaN(a)){ // simple offset adjustment
- return function(v){
- if(v !== last){
- last = v;
- return v + a;
- }
- }
- }
- }
- }
- return false;
- },
-
- // private
- adjustWidthAnchor : function(value, comp){
- return value;
- },
-
- // private
- adjustHeightAnchor : function(value, comp){
- return value;
- }
-
- /**
- * @property activeItem
- * @hide
- */
-});
-Ext.Container.LAYOUTS['anchor'] = Ext.layout.AnchorLayout;/**
+Ext.Container.LAYOUTS['card'] = Ext.layout.CardLayout;/**
+ * @class Ext.layout.AnchorLayout
+ * @extends Ext.layout.ContainerLayout
+ * This is a layout that enables anchoring of contained elements relative to the container's dimensions.
+ * If the container is resized, all anchored items are automatically rerendered according to their
+ * {@link #anchor} rules.
+ * This class is intended to be extended or created via the layout:'anchor' {@link Ext.Container#layout}
+ * config, and should generally not need to be created directly via the new keyword.
+ * AnchorLayout does not have any direct config options (other than inherited ones). By default,
+ * AnchorLayout will calculate anchor measurements based on the size of the container itself. However, the
+ * container using the AnchorLayout can supply an anchoring-specific config property of anchorSize.
+ * If anchorSize is specifed, the layout will use it as a virtual container for the purposes of calculating
+ * anchor measurements based on it instead, allowing the container to be sized independently of the anchoring
+ * logic if necessary. For example:
+ *
+var viewport = new Ext.Viewport({
+ layout:'anchor',
+ anchorSize: {width:800, height:600},
+ items:[{
+ title:'Item 1',
+ html:'Content 1',
+ width:800,
+ anchor:'right 20%'
+ },{
+ title:'Item 2',
+ html:'Content 2',
+ width:300,
+ anchor:'50% 30%'
+ },{
+ title:'Item 3',
+ html:'Content 3',
+ width:600,
+ anchor:'-100 50%'
+ }]
+});
+ *
+ */
+Ext.layout.AnchorLayout = Ext.extend(Ext.layout.ContainerLayout, {
+ /**
+ * @cfg {String} anchor
+ * This configuation option is to be applied to child items of a container managed by
+ * this layout (ie. configured with layout:'anchor').
+ *
+ * This value is what tells the layout how an item should be anchored to the container. items
+ * added to an AnchorLayout accept an anchoring-specific config property of anchor which is a string
+ * containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%').
+ * The following types of anchor values are supported:
+ *
+ * - Percentage : Any value between 1 and 100, expressed as a percentage.
+ * The first anchor is the percentage width that the item should take up within the container, and the
+ * second is the percentage height. For example:
+// two values specified
+anchor: '100% 50%' // render item complete width of the container and
+ // 1/2 height of the container
+// one value specified
+anchor: '100%' // the width value; the height will default to auto
+ *
+ *
+ * - Offsets : Any positive or negative integer value.
+ * This is a raw adjustment where the first anchor is the offset from the right edge of the container,
+ * and the second is the offset from the bottom edge. For example:
+// two values specified
+anchor: '-50 -100' // render item the complete width of the container
+ // minus 50 pixels and
+ // the complete height minus 100 pixels.
+// one value specified
+anchor: '-50' // anchor value is assumed to be the right offset value
+ // bottom offset will default to 0
+ *
+ *
+ * - Sides : Valid values are 'right' (or 'r') and 'bottom'
+ * (or 'b').
+ * Either the container must have a fixed size or an anchorSize config value defined at render time in
+ * order for these to have any effect.
+ *
+ * - Mixed :
+ * Anchor values can also be mixed as needed. For example, to render the width offset from the container
+ * right edge by 50 pixels and 75% of the container's height use:
+ *
+anchor: '-50 75%'
+ *
+ *
+ *
+ *
+ */
+
+ // private
+ monitorResize:true,
+
+ // private
+ // deprecate
+ getAnchorViewSize : function(ct, target){
+ return target.dom == document.body ?
+ target.getViewSize(true) : target.getStyleSize();
+ },
+
+ // private
+ onLayout : function(ct, target){
+ Ext.layout.AnchorLayout.superclass.onLayout.call(this, ct, target);
+
+ var size = target.getViewSize(true);
+
+ var w = size.width, h = size.height;
+
+ if(w < 20 && h < 20){
+ return;
+ }
+
+ // find the container anchoring size
+ var aw, ah;
+ if(ct.anchorSize){
+ if(typeof ct.anchorSize == 'number'){
+ aw = ct.anchorSize;
+ }else{
+ aw = ct.anchorSize.width;
+ ah = ct.anchorSize.height;
+ }
+ }else{
+ aw = ct.initialConfig.width;
+ ah = ct.initialConfig.height;
+ }
+
+ var cs = ct.items.items, len = cs.length, i, c, a, cw, ch, el, vs;
+ for(i = 0; i < len; i++){
+ c = cs[i];
+ el = c.getPositionEl();
+ if(c.anchor){
+ a = c.anchorSpec;
+ if(!a){ // cache all anchor values
+ vs = c.anchor.split(' ');
+ c.anchorSpec = a = {
+ right: this.parseAnchor(vs[0], c.initialConfig.width, aw),
+ bottom: this.parseAnchor(vs[1], c.initialConfig.height, ah)
+ };
+ }
+ cw = a.right ? this.adjustWidthAnchor(a.right(w) - el.getMargins('lr'), c) : undefined;
+ ch = a.bottom ? this.adjustHeightAnchor(a.bottom(h) - el.getMargins('tb'), c) : undefined;
+
+ if(cw || ch){
+ c.setSize(cw || undefined, ch || undefined);
+ }
+ }
+ }
+ },
+
+ // private
+ parseAnchor : function(a, start, cstart){
+ if(a && a != 'none'){
+ var last;
+ if(/^(r|right|b|bottom)$/i.test(a)){ // standard anchor
+ var diff = cstart - start;
+ return function(v){
+ if(v !== last){
+ last = v;
+ return v - diff;
+ }
+ }
+ }else if(a.indexOf('%') != -1){
+ var ratio = parseFloat(a.replace('%', ''))*.01; // percentage
+ return function(v){
+ if(v !== last){
+ last = v;
+ return Math.floor(v*ratio);
+ }
+ }
+ }else{
+ a = parseInt(a, 10);
+ if(!isNaN(a)){ // simple offset adjustment
+ return function(v){
+ if(v !== last){
+ last = v;
+ return v + a;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ },
+
+ // private
+ adjustWidthAnchor : function(value, comp){
+ return value;
+ },
+
+ // private
+ adjustHeightAnchor : function(value, comp){
+ return value;
+ }
+
+ /**
+ * @property activeItem
+ * @hide
+ */
+});
+Ext.Container.LAYOUTS['anchor'] = Ext.layout.AnchorLayout;
+/**
* @class Ext.layout.ColumnLayout
* @extends Ext.layout.ContainerLayout
* This is the layout style of choice for creating structural layouts in a multi-column format where the width of
@@ -5099,7 +5439,7 @@ var p = new Ext.Panel({
layout:'column',
items: [{
title: 'Column 1',
- columnWidth: .25
+ columnWidth: .25
},{
title: 'Column 2',
columnWidth: .6
@@ -5131,14 +5471,17 @@ var p = new Ext.Panel({
Ext.layout.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, {
// private
monitorResize:true,
-
+
extraCls: 'x-column',
scrollOffset : 0,
// private
+
+ targetCls: 'x-column-layout-ct',
+
isValidParent : function(c, target){
- return (c.getPositionEl ? c.getPositionEl() : c.getEl()).dom.parentNode == this.innerCt.dom;
+ return c.getPositionEl().dom.parentNode == this.innerCt.dom;
},
// private
@@ -5146,8 +5489,6 @@ Ext.layout.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, {
var cs = ct.items.items, len = cs.length, c, i;
if(!this.innerCt){
- target.addClass('x-column-layout-ct');
-
// the innerCt prevents wrapping and shuffling while
// the container is resizing
this.innerCt = target.createChild({cls:'x-column-inner'});
@@ -5155,25 +5496,25 @@ Ext.layout.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, {
}
this.renderAll(ct, this.innerCt);
- var size = Ext.isIE && target.dom != Ext.getBody().dom ? target.getStyleSize() : target.getViewSize();
+ var size = target.getViewSize(true);
if(size.width < 1 && size.height < 1){ // display none?
return;
}
- var w = size.width - target.getPadding('lr') - this.scrollOffset,
- h = size.height - target.getPadding('tb'),
+ var w = size.width - this.scrollOffset,
+ h = size.height,
pw = w;
this.innerCt.setWidth(w);
-
+
// some columns can be percentages while others are fixed
// so we need to make 2 passes
for(i = 0; i < len; i++){
c = cs[i];
if(!c.columnWidth){
- pw -= (c.getSize().width + c.getEl().getMargins('lr'));
+ pw -= (c.getSize().width + c.getPositionEl().getMargins('lr'));
}
}
@@ -5182,11 +5523,11 @@ Ext.layout.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, {
for(i = 0; i < len; i++){
c = cs[i];
if(c.columnWidth){
- c.setSize(Math.floor(c.columnWidth*pw) - c.getEl().getMargins('lr'));
+ c.setSize(Math.floor(c.columnWidth * pw) - c.getPositionEl().getMargins('lr'));
}
}
}
-
+
/**
* @property activeItem
* @hide
@@ -5220,7 +5561,7 @@ var myBorderPanel = new Ext.Panel({
{@link Ext.layout.BorderLayout.Region#BorderLayout.Region region}: 'south', // position for region
{@link Ext.BoxComponent#height height}: 100,
{@link Ext.layout.BorderLayout.Region#split split}: true, // enable resizing
- {@link Ext.SplitBar#minSize minSize}: 75, // defaults to {@link Ext.layout.BorderLayout.Region#minHeight 50}
+ {@link Ext.SplitBar#minSize minSize}: 75, // defaults to {@link Ext.layout.BorderLayout.Region#minHeight 50}
{@link Ext.SplitBar#maxSize maxSize}: 150,
{@link Ext.layout.BorderLayout.Region#margins margins}: '0 5 5 5'
},{
@@ -5278,11 +5619,12 @@ Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {
// private
rendered : false,
+ targetCls: 'x-border-layout-ct',
+
// private
onLayout : function(ct, target){
var collapsed;
if(!this.rendered){
- target.addClass('x-border-layout-ct');
var items = ct.items.items;
collapsed = [];
for(var i = 0, len = items.length; i < len; i++) {
@@ -5294,7 +5636,7 @@ Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {
c.collapsed = false;
if(!c.rendered){
c.render(target, i);
- c.getDomPositionEl().addClass('x-border-panel');
+ c.getPositionEl().addClass('x-border-panel');
}
this[pos] = pos != 'center' && c.split ?
new Ext.layout.BorderLayout.SplitRegion(this, c.initialConfig, pos) :
@@ -5304,7 +5646,7 @@ Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {
this.rendered = true;
}
- var size = target.getViewSize();
+ var size = target.getViewSize(false);
if(size.width < 20 || size.height < 20){ // display none?
if(collapsed){
this.restoreCollapsed = collapsed;
@@ -5531,19 +5873,19 @@ Ext.layout.BorderLayout.Region.prototype = {
collapsible : false,
/**
* @cfg {Boolean} split
- *
true to create a {@link Ext.layout.BorderLayout.SplitRegion SplitRegion} and
+ *
true to create a {@link Ext.layout.BorderLayout.SplitRegion SplitRegion} and
* display a 5px wide {@link Ext.SplitBar} between this region and its neighbor, allowing the user to
* resize the regions dynamically. Defaults to false creating a
* {@link Ext.layout.BorderLayout.Region Region}.
* Notes:
- * - this configuration option is ignored if region='center'
+ * - this configuration option is ignored if region='center'
* - when split == true, it is common to specify a
* {@link Ext.SplitBar#minSize minSize} and {@link Ext.SplitBar#maxSize maxSize}
* for the {@link Ext.BoxComponent BoxComponent} representing the region. These are not native
* configs of {@link Ext.BoxComponent BoxComponent}, and are used only by this class.
* - if {@link #collapseMode} = 'mini' requires split = true to reserve space
- * for the collapse tool
- *
+ * for the collapse tool
+ *
*/
split:false,
/**
@@ -5557,8 +5899,8 @@ Ext.layout.BorderLayout.Region.prototype = {
* @cfg {Number} minWidth
* The minimum allowable width in pixels for this region (defaults to 50).
* maxWidth may also be specified.
- * Note: setting the {@link Ext.SplitBar#minSize minSize} /
- * {@link Ext.SplitBar#maxSize maxSize} supersedes any specified
+ *
Note: setting the {@link Ext.SplitBar#minSize minSize} /
+ * {@link Ext.SplitBar#maxSize maxSize} supersedes any specified
* minWidth / maxWidth.
*/
minWidth:50,
@@ -5566,8 +5908,8 @@ Ext.layout.BorderLayout.Region.prototype = {
* @cfg {Number} minHeight
* The minimum allowable height in pixels for this region (defaults to 50)
* maxHeight may also be specified.
- * Note: setting the {@link Ext.SplitBar#minSize minSize} /
- * {@link Ext.SplitBar#maxSize maxSize} supersedes any specified
+ *
Note: setting the {@link Ext.SplitBar#minSize minSize} /
+ * {@link Ext.SplitBar#maxSize maxSize} supersedes any specified
* minHeight / maxHeight.
*/
minHeight:50,
@@ -5682,7 +6024,6 @@ Ext.layout.BorderLayout.Region.prototype = {
// private
onExpandClick : function(e){
if(this.isSlid){
- this.afterSlideIn();
this.panel.expand(false);
}else{
this.panel.expand();
@@ -5701,7 +6042,9 @@ Ext.layout.BorderLayout.Region.prototype = {
this.splitEl.hide();
}
this.getCollapsedEl().show();
- this.panel.el.setStyle('z-index', 100);
+ var el = this.panel.getEl();
+ this.originalZIndex = el.getStyle('z-index');
+ el.setStyle('z-index', 100);
this.isCollapsed = true;
this.layout.layout();
},
@@ -5720,6 +6063,9 @@ Ext.layout.BorderLayout.Region.prototype = {
// private
beforeExpand : function(animate){
+ if(this.isSlid){
+ this.afterSlideIn();
+ }
var c = this.getCollapsedEl();
this.el.show();
if(this.position == 'east' || this.position == 'west'){
@@ -5739,7 +6085,7 @@ Ext.layout.BorderLayout.Region.prototype = {
this.splitEl.show();
}
this.layout.layout();
- this.panel.el.setStyle('z-index', 1);
+ this.panel.el.setStyle('z-index', this.originalZIndex);
this.state.collapsed = false;
this.panel.saveState();
},
@@ -5871,6 +6217,7 @@ Ext.layout.BorderLayout.Region.prototype = {
};
}
this.el.on(this.autoHideHd);
+ this.collapsedEl.on(this.autoHideHd);
}
},
@@ -5879,6 +6226,8 @@ Ext.layout.BorderLayout.Region.prototype = {
if(this.autoHide !== false){
this.el.un("mouseout", this.autoHideHd.mouseout);
this.el.un("mouseover", this.autoHideHd.mouseover);
+ this.collapsedEl.un("mouseout", this.autoHideHd.mouseout);
+ this.collapsedEl.un("mouseover", this.autoHideHd.mouseover);
}
},
@@ -6054,6 +6403,10 @@ Ext.layout.BorderLayout.Region.prototype = {
return [0, cm.top+cm.bottom+c.getHeight()];
break;
}
+ },
+
+ destroy : function(){
+ Ext.destroy(this.miniCollapsedEl, this.collapsedEl);
}
};
@@ -6286,11 +6639,8 @@ Ext.extend(Ext.layout.BorderLayout.SplitRegion, Ext.layout.BorderLayout.Region,
// inherit docs
destroy : function() {
- Ext.destroy(
- this.miniSplitEl,
- this.split,
- this.splitEl
- );
+ Ext.destroy(this.miniSplitEl, this.split, this.splitEl);
+ Ext.layout.BorderLayout.SplitRegion.superclass.destroy.call(this);
}
});
@@ -6404,17 +6754,17 @@ Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, {
* @type String
* @property labelStyle
*/
-
+
/**
* @cfg {Boolean} trackLabels
* True to show/hide the field label when the field is hidden. Defaults to false.
*/
trackLabels: false,
-
+
onRemove: function(c){
Ext.layout.FormLayout.superclass.onRemove.call(this, c);
- if(this.trackLabels && !this.isHide(c)){
+ if(this.trackLabels){
c.un('show', this.onFieldShow, this);
c.un('hide', this.onFieldHide, this);
}
@@ -6422,7 +6772,9 @@ Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, {
var el = c.getPositionEl(),
ct = c.getItemCt && c.getItemCt();
if(c.rendered && ct){
- el.insertAfter(ct);
+ if (el && el.dom) {
+ el.insertAfter(ct);
+ }
Ext.destroy(ct);
Ext.destroyMembers(c, 'label', 'itemCt');
if(c.customItemCt){
@@ -6430,7 +6782,7 @@ Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, {
}
}
},
-
+
// private
setContainer : function(ct){
Ext.layout.FormLayout.superclass.setContainer.call(this, ct);
@@ -6464,17 +6816,18 @@ Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, {
}
}
},
-
+
+ // private
isHide: function(c){
return c.hideLabel || this.container.hideLabels;
},
-
+
onFieldShow: function(c){
c.getItemCt().removeClass('x-hide-' + c.hideMode);
},
-
+
onFieldHide: function(c){
- c.getItemCt().addClass('x-hide-' + c.hideMode);
+ c.getItemCt().addClass('x-hide-' + c.hideMode);
},
//private
@@ -6537,11 +6890,6 @@ new Ext.Template(
}else{
c.itemCt = this.fieldTpl.append(target, args, true);
}
- if(!c.rendered){
- c.render('x-form-el-' + c.id);
- }else if(!this.isValidParent(c, target)){
- Ext.fly('x-form-el-' + c.id).appendChild(c.getPositionEl());
- }
if(!c.getItemCt){
// Non form fields don't have getItemCt, apply it here
// This will get cleaned up in onRemove
@@ -6553,7 +6901,12 @@ new Ext.Template(
});
}
c.label = c.getItemCt().child('label.x-form-item-label');
- if(this.trackLabels && !this.isHide(c)){
+ if(!c.rendered){
+ c.render('x-form-el-' + c.id);
+ }else if(!this.isValidParent(c, target)){
+ Ext.fly('x-form-el-' + c.id).appendChild(c.getPositionEl());
+ }
+ if(this.trackLabels){
if(c.hidden){
this.onFieldHide(c);
}
@@ -6591,7 +6944,7 @@ new Ext.Template(
* clearCls : StringThe CSS class to apply to the special clearing div
* rendered directly after each form field wrapper (defaults to 'x-form-clear-left')
*
- * @param field The {@link Field Ext.form.Field} being rendered.
+ * @param (Ext.form.Field} field The {@link Ext.form.Field Field} being rendered.
* @return An object hash containing the properties required to render the Field.
*/
getTemplateArgs: function(field) {
@@ -6615,7 +6968,7 @@ new Ext.Template(
}
return value;
},
-
+
adjustHeightAnchor : function(value, c){
if(c.label && !this.isHide(c) && (this.container.labelAlign == 'top')){
return value - c.label.getHeight();
@@ -6625,7 +6978,7 @@ new Ext.Template(
// private
isValidParent : function(c, target){
- return target && this.container.getEl().contains(c.getDomPositionEl());
+ return target && this.container.getEl().contains(c.getPositionEl());
}
/**
@@ -6634,7 +6987,8 @@ new Ext.Template(
*/
});
-Ext.Container.LAYOUTS['form'] = Ext.layout.FormLayout;/**
+Ext.Container.LAYOUTS['form'] = Ext.layout.FormLayout;
+/**
* @class Ext.layout.AccordionLayout
* @extends Ext.layout.FitLayout
* This is a layout that manages multiple Panels in an expandable accordion style such that only
@@ -6740,7 +7094,7 @@ Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, {
c.collapseFirst = this.collapseFirst;
}
if(!this.activeItem && !c.collapsed){
- this.activeItem = c;
+ this.setActiveItem(c, true);
}else if(this.activeItem && this.activeItem != c){
c.collapsed = true;
}
@@ -6773,7 +7127,7 @@ Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, {
ai.collapse(this.animate);
}
}
- this.activeItem = p;
+ this.setActive(p);
if(this.activeOnTop){
p.el.dom.parentNode.insertBefore(p.el.dom, p.el.dom.parentNode.firstChild);
}
@@ -6799,15 +7153,24 @@ Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, {
* @param {String/Number} item The string component id or numeric index of the item to activate
*/
setActiveItem : function(item){
+ this.setActive(item, true);
+ },
+
+ // private
+ setActive : function(item, expand){
+ var ai = this.activeItem;
item = this.container.getComponent(item);
- if(this.activeItem != item){
- if(item.rendered && item.collapsed){
+ if(ai != item){
+ if(item.rendered && item.collapsed && expand){
item.expand();
}else{
+ if(ai){
+ ai.fireEvent('deactivate', ai);
+ }
this.activeItem = item;
+ item.fireEvent('activate', item);
}
}
-
}
});
Ext.Container.LAYOUTS.accordion = Ext.layout.AccordionLayout;
@@ -6881,6 +7244,8 @@ Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, {
// private
monitorResize:false,
+
+ targetCls: 'x-table-layout-ct',
/**
* @cfg {Object} tableAttrs
@@ -6915,8 +7280,6 @@ Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, {
var cs = ct.items.items, len = cs.length, c, i;
if(!this.table){
- target.addClass('x-table-layout-ct');
-
this.table = target.createChild(
Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true);
}
@@ -6985,7 +7348,7 @@ Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, {
this.configureItem(c, position);
}else if(c && !this.isValidParent(c, target)){
var container = this.getNextCell(c);
- container.insertBefore(c.getDomPositionEl().dom, null);
+ container.insertBefore(c.getPositionEl().dom, null);
c.container = Ext.get(container);
this.configureItem(c, position);
}
@@ -6993,7 +7356,7 @@ Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, {
// private
isValidParent : function(c, target){
- return c.getDomPositionEl().up('table', 5).dom.parentNode === (target.dom || target);
+ return c.getPositionEl().up('table', 5).dom.parentNode === (target.dom || target);
}
/**
@@ -7078,439 +7441,441 @@ Ext.layout.AbsoluteLayout = Ext.extend(Ext.layout.AnchorLayout, {
*/
});
Ext.Container.LAYOUTS['absolute'] = Ext.layout.AbsoluteLayout;
-/**
- * @class Ext.layout.BoxLayout
- * @extends Ext.layout.ContainerLayout
- *
Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.
- */
-Ext.layout.BoxLayout = Ext.extend(Ext.layout.ContainerLayout, {
- /**
- * @cfg {Object} defaultMargins
- * If the individual contained items do not have a margins
- * property specified, the default margins from this property will be
- * applied to each item.
- *
This property may be specified as an object containing margins
- * to apply in the format:
-{
- top: (top margin),
- right: (right margin),
- bottom: (bottom margin),
- left: (left margin)
-}
- * This property may also be specified as a string containing
- * space-separated, numeric margin values. The order of the sides associated
- * with each value matches the way CSS processes margin values:
- *
- * - If there is only one value, it applies to all sides.
- * - If there are two values, the top and bottom borders are set to the
- * first value and the right and left are set to the second.
- * - If there are three values, the top is set to the first value, the left
- * and right are set to the second, and the bottom is set to the third.
- * - If there are four values, they apply to the top, right, bottom, and
- * left, respectively.
- *
- * Defaults to:
- * {top:0, right:0, bottom:0, left:0}
- *
- */
- defaultMargins : {left:0,top:0,right:0,bottom:0},
- /**
- * @cfg {String} padding
- * Sets the padding to be applied to all child items managed by this layout.
- * This property must be specified as a string containing
- * space-separated, numeric padding values. The order of the sides associated
- * with each value matches the way CSS processes padding values:
- *
- * - If there is only one value, it applies to all sides.
- * - If there are two values, the top and bottom borders are set to the
- * first value and the right and left are set to the second.
- * - If there are three values, the top is set to the first value, the left
- * and right are set to the second, and the bottom is set to the third.
- * - If there are four values, they apply to the top, right, bottom, and
- * left, respectively.
- *
- * Defaults to: "0"
- */
- padding : '0',
- // documented in subclasses
- pack : 'start',
-
- // private
- monitorResize : true,
- scrollOffset : 0,
- extraCls : 'x-box-item',
- ctCls : 'x-box-layout-ct',
- innerCls : 'x-box-inner',
-
- constructor : function(config){
- Ext.layout.BoxLayout.superclass.constructor.call(this, config);
- if(Ext.isString(this.defaultMargins)){
- this.defaultMargins = this.parseMargins(this.defaultMargins);
- }
- },
-
- // private
- isValidParent : function(c, target){
- return c.getEl().dom.parentNode == this.innerCt.dom;
- },
-
- // private
- onLayout : function(ct, target){
- var cs = ct.items.items, len = cs.length, c, i, last = len-1, cm;
-
- if(!this.innerCt){
- target.addClass(this.ctCls);
-
- // the innerCt prevents wrapping and shuffling while
- // the container is resizing
- this.innerCt = target.createChild({cls:this.innerCls});
- this.padding = this.parseMargins(this.padding);
- }
- this.renderAll(ct, this.innerCt);
- },
-
- // private
- renderItem : function(c){
- if(Ext.isString(c.margins)){
- c.margins = this.parseMargins(c.margins);
- }else if(!c.margins){
- c.margins = this.defaultMargins;
- }
- Ext.layout.BoxLayout.superclass.renderItem.apply(this, arguments);
- },
-
+/**
+ * @class Ext.layout.BoxLayout
+ * @extends Ext.layout.ContainerLayout
+ * Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.
+ */
+Ext.layout.BoxLayout = Ext.extend(Ext.layout.ContainerLayout, {
+ /**
+ * @cfg {Object} defaultMargins
+ * If the individual contained items do not have a margins
+ * property specified, the default margins from this property will be
+ * applied to each item.
+ *
This property may be specified as an object containing margins
+ * to apply in the format:
+{
+ top: (top margin),
+ right: (right margin),
+ bottom: (bottom margin),
+ left: (left margin)
+}
+ * This property may also be specified as a string containing
+ * space-separated, numeric margin values. The order of the sides associated
+ * with each value matches the way CSS processes margin values:
+ *
+ * - If there is only one value, it applies to all sides.
+ * - If there are two values, the top and bottom borders are set to the
+ * first value and the right and left are set to the second.
+ * - If there are three values, the top is set to the first value, the left
+ * and right are set to the second, and the bottom is set to the third.
+ * - If there are four values, they apply to the top, right, bottom, and
+ * left, respectively.
+ *
+ * Defaults to:
+ * {top:0, right:0, bottom:0, left:0}
+ *
+ */
+ defaultMargins : {left:0,top:0,right:0,bottom:0},
+ /**
+ * @cfg {String} padding
+ * Sets the padding to be applied to all child items managed by this layout.
+ * This property must be specified as a string containing
+ * space-separated, numeric padding values. The order of the sides associated
+ * with each value matches the way CSS processes padding values:
+ *
+ * - If there is only one value, it applies to all sides.
+ * - If there are two values, the top and bottom borders are set to the
+ * first value and the right and left are set to the second.
+ * - If there are three values, the top is set to the first value, the left
+ * and right are set to the second, and the bottom is set to the third.
+ * - If there are four values, they apply to the top, right, bottom, and
+ * left, respectively.
+ *
+ * Defaults to: "0"
+ */
+ padding : '0',
+ // documented in subclasses
+ pack : 'start',
+
+ // private
+ monitorResize : true,
+ scrollOffset : 0,
+ extraCls : 'x-box-item',
+ targetCls : 'x-box-layout-ct',
+ innerCls : 'x-box-inner',
+
+ constructor : function(config){
+ Ext.layout.BoxLayout.superclass.constructor.call(this, config);
+ if(Ext.isString(this.defaultMargins)){
+ this.defaultMargins = this.parseMargins(this.defaultMargins);
+ }
+ },
+
+ // private
+ isValidParent : function(c, target){
+ return c.getPositionEl().dom.parentNode == this.innerCt.dom;
+ },
+
+ // private
+ onLayout : function(ct, target){
+ var cs = ct.items.items, len = cs.length, c, i, last = len-1, cm;
+
+ if(!this.innerCt){
+ // the innerCt prevents wrapping and shuffling while
+ // the container is resizing
+ this.innerCt = target.createChild({cls:this.innerCls});
+ this.padding = this.parseMargins(this.padding);
+ }
+ this.renderAll(ct, this.innerCt);
+ },
+
+ // private
+ renderItem : function(c){
+ if(Ext.isString(c.margins)){
+ c.margins = this.parseMargins(c.margins);
+ }else if(!c.margins){
+ c.margins = this.defaultMargins;
+ }
+ Ext.layout.BoxLayout.superclass.renderItem.apply(this, arguments);
+ },
+
+ // deprecate
getTargetSize : function(target){
- return (Ext.isIE6 && Ext.isStrict && target.dom == document.body) ? target.getStyleSize() : target.getViewSize();
- },
-
- getItems: function(ct){
- var items = [];
- ct.items.each(function(c){
- if(c.isVisible()){
- items.push(c);
- }
- });
- return items;
- }
-
- /**
- * @property activeItem
- * @hide
- */
-});
-
-/**
- * @class Ext.layout.VBoxLayout
- * @extends Ext.layout.BoxLayout
- * A layout that arranges items vertically down a Container. This layout optionally divides available vertical
- * space between child items containing a numeric flex
configuration.
- * This layout may also be used to set the widths of child items by configuring it with the {@link #align} option.
- */
-Ext.layout.VBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
- /**
- * @cfg {String} align
- * Controls how the child items of the container are aligned. Acceptable configuration values for this
- * property are:
- *
- * - left : Defaultchild items are aligned horizontally
- * at the left side of the container
- * - center : child items are aligned horizontally at the
- * mid-width of the container
- * - stretch : child items are stretched horizontally to fill
- * the width of the container
- * - stretchmax : child items are stretched horizontally to
- * the size of the largest item.
- *
- */
- align : 'left', // left, center, stretch, strechmax
- /**
- * @cfg {String} pack
- * Controls how the child items of the container are packed together. Acceptable configuration values
- * for this property are:
- *
- * - start : Defaultchild items are packed together at
- * top side of container
- * - center : child items are packed together at
- * mid-height of container
- * - end : child items are packed together at bottom
- * side of container
- *
- */
- /**
- * @cfg {Number} flex
- * This configuation option is to be applied to child items of the container managed
- * by this layout. Each child item with a flex property will be flexed vertically
- * according to each item's relative flex value compared to the sum of all items with
- * a flex value specified. Any child items that have either a flex = 0 or
- * flex = undefined will not be 'flexed' (the initial size will not be changed).
- */
-
- // private
- onLayout : function(ct, target){
- Ext.layout.VBoxLayout.superclass.onLayout.call(this, ct, target);
-
-
- var cs = this.getItems(ct), cm, ch, margin,
- size = this.getTargetSize(target),
- w = size.width - target.getPadding('lr'),
- h = size.height - target.getPadding('tb') - this.scrollOffset,
- l = this.padding.left, t = this.padding.top,
- isStart = this.pack == 'start',
- isRestore = ['stretch', 'stretchmax'].indexOf(this.align) == -1,
- stretchWidth = w - (this.padding.left + this.padding.right),
- extraHeight = 0,
- maxWidth = 0,
- totalFlex = 0,
- flexHeight = 0,
- usedHeight = 0;
-
- Ext.each(cs, function(c){
- cm = c.margins;
- totalFlex += c.flex || 0;
- ch = c.getHeight();
- margin = cm.top + cm.bottom;
- extraHeight += ch + margin;
- flexHeight += margin + (c.flex ? 0 : ch);
- maxWidth = Math.max(maxWidth, c.getWidth() + cm.left + cm.right);
- });
- extraHeight = h - extraHeight - this.padding.top - this.padding.bottom;
-
- var innerCtWidth = maxWidth + this.padding.left + this.padding.right;
- switch(this.align){
- case 'stretch':
- this.innerCt.setSize(w, h);
- break;
- case 'stretchmax':
- case 'left':
- this.innerCt.setSize(innerCtWidth, h);
- break;
- case 'center':
- this.innerCt.setSize(w = Math.max(w, innerCtWidth), h);
- break;
- }
-
- var availHeight = Math.max(0, h - this.padding.top - this.padding.bottom - flexHeight),
- leftOver = availHeight,
- heights = [],
- restore = [],
- idx = 0,
- availableWidth = Math.max(0, w - this.padding.left - this.padding.right);
-
-
- Ext.each(cs, function(c){
- if(isStart && c.flex){
- ch = Math.floor(availHeight * (c.flex / totalFlex));
- leftOver -= ch;
- heights.push(ch);
- }
- });
-
- if(this.pack == 'center'){
- t += extraHeight ? extraHeight / 2 : 0;
- }else if(this.pack == 'end'){
- t += extraHeight;
- }
- Ext.each(cs, function(c){
- cm = c.margins;
- t += cm.top;
- c.setPosition(l + cm.left, t);
- if(isStart && c.flex){
- ch = Math.max(0, heights[idx++] + (leftOver-- > 0 ? 1 : 0));
- if(isRestore){
- restore.push(c.getWidth());
- }
- c.setSize(availableWidth, ch);
- }else{
- ch = c.getHeight();
- }
- t += ch + cm.bottom;
- });
-
- idx = 0;
- Ext.each(cs, function(c){
- cm = c.margins;
- if(this.align == 'stretch'){
- c.setWidth((stretchWidth - (cm.left + cm.right)).constrain(
- c.minWidth || 0, c.maxWidth || 1000000));
- }else if(this.align == 'stretchmax'){
- c.setWidth((maxWidth - (cm.left + cm.right)).constrain(
- c.minWidth || 0, c.maxWidth || 1000000));
- }else{
- if(this.align == 'center'){
- var diff = availableWidth - (c.getWidth() + cm.left + cm.right);
- if(diff > 0){
- c.setPosition(l + cm.left + (diff/2), c.y);
- }
- }
- if(isStart && c.flex){
- c.setWidth(restore[idx++]);
- }
- }
- }, this);
- }
- /**
- * @property activeItem
- * @hide
- */
-});
-
-Ext.Container.LAYOUTS.vbox = Ext.layout.VBoxLayout;
-
-/**
- * @class Ext.layout.HBoxLayout
- * @extends Ext.layout.BoxLayout
- * A layout that arranges items horizontally across a Container. This layout optionally divides available horizontal
- * space between child items containing a numeric flex
configuration.
- * This layout may also be used to set the heights of child items by configuring it with the {@link #align} option.
- */
-Ext.layout.HBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
- /**
- * @cfg {String} align
- * Controls how the child items of the container are aligned. Acceptable configuration values for this
- * property are:
- *
- * - top : Defaultchild items are aligned vertically
- * at the left side of the container
- * - middle : child items are aligned vertically at the
- * mid-height of the container
- * - stretch : child items are stretched vertically to fill
- * the height of the container
- * - stretchmax : child items are stretched vertically to
- * the size of the largest item.
- */
- align : 'top', // top, middle, stretch, strechmax
- /**
- * @cfg {String} pack
- * Controls how the child items of the container are packed together. Acceptable configuration values
- * for this property are:
- *
- * - start : Defaultchild items are packed together at
- * left side of container
- * - center : child items are packed together at
- * mid-width of container
- * - end : child items are packed together at right
- * side of container
- *
- */
- /**
- * @cfg {Number} flex
- * This configuation option is to be applied to child items of the container managed
- * by this layout. Each child item with a flex property will be flexed horizontally
- * according to each item's relative flex value compared to the sum of all items with
- * a flex value specified. Any child items that have either a flex = 0 or
- * flex = undefined will not be 'flexed' (the initial size will not be changed).
- */
-
- // private
- onLayout : function(ct, target){
- Ext.layout.HBoxLayout.superclass.onLayout.call(this, ct, target);
-
- var cs = this.getItems(ct), cm, cw, margin,
- size = this.getTargetSize(target),
- w = size.width - target.getPadding('lr') - this.scrollOffset,
- h = size.height - target.getPadding('tb'),
- l = this.padding.left, t = this.padding.top,
- isStart = this.pack == 'start',
- isRestore = ['stretch', 'stretchmax'].indexOf(this.align) == -1,
- stretchHeight = h - (this.padding.top + this.padding.bottom),
- extraWidth = 0,
- maxHeight = 0,
- totalFlex = 0,
- flexWidth = 0,
- usedWidth = 0;
-
- Ext.each(cs, function(c){
- cm = c.margins;
- totalFlex += c.flex || 0;
- cw = c.getWidth();
- margin = cm.left + cm.right;
- extraWidth += cw + margin;
- flexWidth += margin + (c.flex ? 0 : cw);
- maxHeight = Math.max(maxHeight, c.getHeight() + cm.top + cm.bottom);
- });
- extraWidth = w - extraWidth - this.padding.left - this.padding.right;
-
- var innerCtHeight = maxHeight + this.padding.top + this.padding.bottom;
- switch(this.align){
- case 'stretch':
- this.innerCt.setSize(w, h);
- break;
- case 'stretchmax':
- case 'top':
- this.innerCt.setSize(w, innerCtHeight);
- break;
- case 'middle':
- this.innerCt.setSize(w, h = Math.max(h, innerCtHeight));
- break;
- }
-
-
- var availWidth = Math.max(0, w - this.padding.left - this.padding.right - flexWidth),
- leftOver = availWidth,
- widths = [],
- restore = [],
- idx = 0,
- availableHeight = Math.max(0, h - this.padding.top - this.padding.bottom);
-
-
- Ext.each(cs, function(c){
- if(isStart && c.flex){
- cw = Math.floor(availWidth * (c.flex / totalFlex));
- leftOver -= cw;
- widths.push(cw);
- }
- });
-
- if(this.pack == 'center'){
- l += extraWidth ? extraWidth / 2 : 0;
- }else if(this.pack == 'end'){
- l += extraWidth;
- }
- Ext.each(cs, function(c){
- cm = c.margins;
- l += cm.left;
- c.setPosition(l, t + cm.top);
- if(isStart && c.flex){
- cw = Math.max(0, widths[idx++] + (leftOver-- > 0 ? 1 : 0));
- if(isRestore){
- restore.push(c.getHeight());
- }
- c.setSize(cw, availableHeight);
- }else{
- cw = c.getWidth();
- }
- l += cw + cm.right;
- });
-
- idx = 0;
- Ext.each(cs, function(c){
- var cm = c.margins;
- if(this.align == 'stretch'){
- c.setHeight((stretchHeight - (cm.top + cm.bottom)).constrain(
- c.minHeight || 0, c.maxHeight || 1000000));
- }else if(this.align == 'stretchmax'){
- c.setHeight((maxHeight - (cm.top + cm.bottom)).constrain(
- c.minHeight || 0, c.maxHeight || 1000000));
- }else{
- if(this.align == 'middle'){
- var diff = availableHeight - (c.getHeight() + cm.top + cm.bottom);
- if(diff > 0){
- c.setPosition(c.x, t + cm.top + (diff/2));
- }
- }
- if(isStart && c.flex){
- c.setHeight(restore[idx++]);
- }
- }
- }, this);
- }
-
- /**
- * @property activeItem
- * @hide
- */
-});
-
+ return (Ext.isIE6 && Ext.isStrict && target.dom == document.body) ? target.getStyleSize() : target.getViewSize(true);
+ },
+
+ getItems: function(ct){
+ var items = [];
+ ct.items.each(function(c){
+ if(c.isVisible()){
+ items.push(c);
+ }
+ });
+ return items;
+ }
+});
+
+/**
+ * @class Ext.layout.VBoxLayout
+ * @extends Ext.layout.BoxLayout
+ * A layout that arranges items vertically down a Container. This layout optionally divides available vertical
+ * space between child items containing a numeric flex
configuration.
+ * This layout may also be used to set the widths of child items by configuring it with the {@link #align} option.
+ */
+Ext.layout.VBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
+ /**
+ * @cfg {String} align
+ * Controls how the child items of the container are aligned. Acceptable configuration values for this
+ * property are:
+ *
+ * - left : Defaultchild items are aligned horizontally
+ * at the left side of the container
+ * - center : child items are aligned horizontally at the
+ * mid-width of the container
+ * - stretch : child items are stretched horizontally to fill
+ * the width of the container
+ * - stretchmax : child items are stretched horizontally to
+ * the size of the largest item.
+ *
+ */
+ align : 'left', // left, center, stretch, strechmax
+ /**
+ * @cfg {String} pack
+ * Controls how the child items of the container are packed together. Acceptable configuration values
+ * for this property are:
+ *
+ * - start : Defaultchild items are packed together at
+ * top side of container
+ * - center : child items are packed together at
+ * mid-height of container
+ * - end : child items are packed together at bottom
+ * side of container
+ *
+ */
+ /**
+ * @cfg {Number} flex
+ * This configuation option is to be applied to child items of the container managed
+ * by this layout. Each child item with a flex property will be flexed vertically
+ * according to each item's relative flex value compared to the sum of all items with
+ * a flex value specified. Any child items that have either a flex = 0 or
+ * flex = undefined will not be 'flexed' (the initial size will not be changed).
+ */
+
+ // private
+ onLayout : function(ct, target){
+ Ext.layout.VBoxLayout.superclass.onLayout.call(this, ct, target);
+
+ var cs = this.getItems(ct), cm, ch, margin, cl, diff, aw,
+ size = target.getViewSize(true),
+ w = size.width,
+ h = size.height - this.scrollOffset,
+ l = this.padding.left, t = this.padding.top,
+ isStart = this.pack == 'start',
+ stretchWidth = w - (this.padding.left + this.padding.right),
+ extraHeight = 0,
+ maxWidth = 0,
+ totalFlex = 0,
+ flexHeight = 0,
+ usedHeight = 0,
+ idx = 0,
+ heights = [],
+ restore = [],
+ c,
+ csLen = cs.length;
+
+ // Do only width calculations and apply those first, as they can affect height
+ for (i = 0 ; i < csLen; i++) {
+ c = cs[i];
+ cm = c.margins;
+ margin = cm.top + cm.bottom;
+ maxWidth = Math.max(maxWidth, c.getWidth() + cm.left + cm.right);
+ }
+
+ var innerCtWidth = maxWidth + this.padding.left + this.padding.right;
+ switch(this.align){
+ case 'stretch':
+ this.innerCt.setSize(w, h);
+ break;
+ case 'stretchmax':
+ case 'left':
+ this.innerCt.setSize(innerCtWidth, h);
+ break;
+ case 'center':
+ this.innerCt.setSize(w = Math.max(w, innerCtWidth), h);
+ break;
+ }
+
+ var availableWidth = Math.max(0, w - this.padding.left - this.padding.right);
+ // Apply widths
+ for (i = 0 ; i < csLen; i++) {
+ c = cs[i];
+ cm = c.margins;
+ if(this.align == 'stretch'){
+ c.setWidth((stretchWidth - (cm.left + cm.right)).constrain(
+ c.minWidth || 0, c.maxWidth || 1000000));
+ }else if(this.align == 'stretchmax'){
+ c.setWidth((maxWidth - (cm.left + cm.right)).constrain(
+ c.minWidth || 0, c.maxWidth || 1000000));
+ }else if(isStart && c.flex){
+ c.setWidth();
+ }
+
+ }
+
+ // Do height calculations
+ for (i = 0 ; i < csLen; i++) {
+ c = cs[i];
+ cm = c.margins;
+ totalFlex += c.flex || 0;
+ ch = c.getHeight();
+ margin = cm.top + cm.bottom;
+ extraHeight += ch + margin;
+ flexHeight += margin + (c.flex ? 0 : ch);
+ }
+ extraHeight = h - extraHeight - this.padding.top - this.padding.bottom;
+
+ var availHeight = Math.max(0, h - this.padding.top - this.padding.bottom - flexHeight),
+ leftOver = availHeight;
+ for (i = 0 ; i < csLen; i++) {
+ c = cs[i];
+ if(isStart && c.flex){
+ ch = Math.floor(availHeight * (c.flex / totalFlex));
+ leftOver -= ch;
+ heights.push(ch);
+ }
+ }
+ if(this.pack == 'center'){
+ t += extraHeight ? extraHeight / 2 : 0;
+ }else if(this.pack == 'end'){
+ t += extraHeight;
+ }
+ idx = 0;
+ // Apply heights
+ for (i = 0 ; i < csLen; i++) {
+ c = cs[i];
+ cm = c.margins;
+ t += cm.top;
+ aw = availableWidth;
+ cl = l + cm.left // default left pos
+
+// Adjust left pos for centering
+ if(this.align == 'center'){
+ if((diff = availableWidth - (c.getWidth() + cm.left + cm.right)) > 0){
+ cl += (diff/2);
+ aw -= diff;
+ }
+ }
+
+ c.setPosition(cl, t);
+ if(isStart && c.flex){
+ ch = Math.max(0, heights[idx++] + (leftOver-- > 0 ? 1 : 0));
+ c.setSize(aw, ch);
+ }else{
+ ch = c.getHeight();
+ }
+ t += ch + cm.bottom;
+ }
+ }
+});
+
+Ext.Container.LAYOUTS.vbox = Ext.layout.VBoxLayout;
+
+/**
+ * @class Ext.layout.HBoxLayout
+ * @extends Ext.layout.BoxLayout
+ * A layout that arranges items horizontally across a Container. This layout optionally divides available horizontal
+ * space between child items containing a numeric flex
configuration.
+ * This layout may also be used to set the heights of child items by configuring it with the {@link #align} option.
+ */
+Ext.layout.HBoxLayout = Ext.extend(Ext.layout.BoxLayout, {
+ /**
+ * @cfg {String} align
+ * Controls how the child items of the container are aligned. Acceptable configuration values for this
+ * property are:
+ *
+ * - top : Defaultchild items are aligned vertically
+ * at the top of the container
+ * - middle : child items are aligned vertically in the
+ * middle of the container
+ * - stretch : child items are stretched vertically to fill
+ * the height of the container
+ * - stretchmax : child items are stretched vertically to
+ * the height of the largest item.
+ */
+ align : 'top', // top, middle, stretch, strechmax
+ /**
+ * @cfg {String} pack
+ * Controls how the child items of the container are packed together. Acceptable configuration values
+ * for this property are:
+ *
+ * - start : Defaultchild items are packed together at
+ * left side of container
+ * - center : child items are packed together at
+ * mid-width of container
+ * - end : child items are packed together at right
+ * side of container
+ *
+ */
+ /**
+ * @cfg {Number} flex
+ * This configuation option is to be applied to child items of the container managed
+ * by this layout. Each child item with a flex property will be flexed horizontally
+ * according to each item's relative flex value compared to the sum of all items with
+ * a flex value specified. Any child items that have either a flex = 0 or
+ * flex = undefined will not be 'flexed' (the initial size will not be changed).
+ */
+
+ // private
+ onLayout : function(ct, target){
+ Ext.layout.HBoxLayout.superclass.onLayout.call(this, ct, target);
+
+ var cs = this.getItems(ct), cm, cw, margin, ch, diff,
+ size = target.getViewSize(true),
+ w = size.width - this.scrollOffset,
+ h = size.height,
+ l = this.padding.left, t = this.padding.top,
+ isStart = this.pack == 'start',
+ isRestore = ['stretch', 'stretchmax'].indexOf(this.align) == -1,
+ stretchHeight = h - (this.padding.top + this.padding.bottom),
+ extraWidth = 0,
+ maxHeight = 0,
+ totalFlex = 0,
+ flexWidth = 0,
+ usedWidth = 0;
+
+ Ext.each(cs, function(c){
+ cm = c.margins;
+ totalFlex += c.flex || 0;
+ cw = c.getWidth();
+ margin = cm.left + cm.right;
+ extraWidth += cw + margin;
+ flexWidth += margin + (c.flex ? 0 : cw);
+ maxHeight = Math.max(maxHeight, c.getHeight() + cm.top + cm.bottom);
+ });
+ extraWidth = w - extraWidth - this.padding.left - this.padding.right;
+
+ var innerCtHeight = maxHeight + this.padding.top + this.padding.bottom;
+ switch(this.align){
+ case 'stretch':
+ this.innerCt.setSize(w, h);
+ break;
+ case 'stretchmax':
+ case 'top':
+ this.innerCt.setSize(w, innerCtHeight);
+ break;
+ case 'middle':
+ this.innerCt.setSize(w, h = Math.max(h, innerCtHeight));
+ break;
+ }
+
+
+ var availWidth = Math.max(0, w - this.padding.left - this.padding.right - flexWidth),
+ leftOver = availWidth,
+ widths = [],
+ restore = [],
+ idx = 0,
+ availableHeight = Math.max(0, h - this.padding.top - this.padding.bottom);
+
+
+ Ext.each(cs, function(c){
+ if(isStart && c.flex){
+ cw = Math.floor(availWidth * (c.flex / totalFlex));
+ leftOver -= cw;
+ widths.push(cw);
+ }
+ });
+
+ if(this.pack == 'center'){
+ l += extraWidth ? extraWidth / 2 : 0;
+ }else if(this.pack == 'end'){
+ l += extraWidth;
+ }
+ Ext.each(cs, function(c){
+ cm = c.margins;
+ l += cm.left;
+ c.setPosition(l, t + cm.top);
+ if(isStart && c.flex){
+ cw = Math.max(0, widths[idx++] + (leftOver-- > 0 ? 1 : 0));
+ if(isRestore){
+ restore.push(c.getHeight());
+ }
+ c.setSize(cw, availableHeight);
+ }else{
+ cw = c.getWidth();
+ }
+ l += cw + cm.right;
+ });
+
+ idx = 0;
+ Ext.each(cs, function(c){
+ cm = c.margins;
+ ch = c.getHeight();
+ if(isStart && c.flex){
+ ch = restore[idx++];
+ }
+ if(this.align == 'stretch'){
+ c.setHeight((stretchHeight - (cm.top + cm.bottom)).constrain(
+ c.minHeight || 0, c.maxHeight || 1000000));
+ }else if(this.align == 'stretchmax'){
+ c.setHeight((maxHeight - (cm.top + cm.bottom)).constrain(
+ c.minHeight || 0, c.maxHeight || 1000000));
+ }else{
+ if(this.align == 'middle'){
+ diff = availableHeight - (ch + cm.top + cm.bottom);
+ ch = t + cm.top + (diff/2);
+ if(diff > 0){
+ c.setPosition(c.x, ch);
+ }
+ }
+ if(isStart && c.flex){
+ c.setHeight(ch);
+ }
+ }
+ }, this);
+ }
+});
+
Ext.Container.LAYOUTS.hbox = Ext.layout.HBoxLayout;
/**
* @class Ext.Viewport
@@ -7537,7 +7902,7 @@ new Ext.Viewport({
collapsible: true,
title: 'Navigation',
width: 200
- // the west region might typically utilize a {@link Ext.tree.TreePanel TreePanel} or a Panel with {@link Ext.layout.AccordionLayout Accordion layout}
+ // the west region might typically utilize a {@link Ext.tree.TreePanel TreePanel} or a Panel with {@link Ext.layout.AccordionLayout Accordion layout}
}, {
region: 'south',
title: 'Title for Panel',
@@ -7572,44 +7937,45 @@ new Ext.Viewport({
* @xtype viewport
*/
Ext.Viewport = Ext.extend(Ext.Container, {
- /*
- * Privatize config options which, if used, would interfere with the
- * correct operation of the Viewport as the sole manager of the
- * layout of the document body.
- */
+ /*
+ * Privatize config options which, if used, would interfere with the
+ * correct operation of the Viewport as the sole manager of the
+ * layout of the document body.
+ */
/**
* @cfg {Mixed} applyTo @hide
- */
+ */
/**
* @cfg {Boolean} allowDomMove @hide
- */
+ */
/**
* @cfg {Boolean} hideParent @hide
- */
+ */
/**
* @cfg {Mixed} renderTo @hide
- */
+ */
/**
* @cfg {Boolean} hideParent @hide
- */
+ */
/**
* @cfg {Number} height @hide
- */
+ */
/**
* @cfg {Number} width @hide
- */
+ */
/**
* @cfg {Boolean} autoHeight @hide
- */
+ */
/**
* @cfg {Boolean} autoWidth @hide
- */
+ */
/**
* @cfg {Boolean} deferHeight @hide
- */
+ */
/**
* @cfg {Boolean} monitorResize @hide
- */
+ */
+
initComponent : function() {
Ext.Viewport.superclass.initComponent.call(this);
document.getElementsByTagName('html')[0].className += ' x-viewport';
@@ -7626,10 +7992,11 @@ Ext.Viewport = Ext.extend(Ext.Container, {
},
fireResize : function(w, h){
- this.fireEvent('resize', this, w, h, w, h);
+ this.onResize(w, h, w, h);
}
});
-Ext.reg('viewport', Ext.Viewport);/**
+Ext.reg('viewport', Ext.Viewport);
+/**
* @class Ext.Panel
* @extends Ext.Container
* Panel is a container that has specific functionality and structural components that make
@@ -7984,7 +8351,7 @@ var w = new Ext.Window({
*
- event : Ext.EventObjectThe click event.
* - toolEl : Ext.ElementThe tool Element.
* - panel : Ext.PanelThe host Panel
- * - tc : Ext.PanelThe tool configuration object
+ * - tc : ObjectThe tool configuration object
*
* - stopEvent : BooleanDefaults to true. Specify as false to allow click event to propagate.
* - scope : ObjectThe scope in which to call the handler.
@@ -8069,11 +8436,7 @@ var win = new Ext.Window({
* {@link Ext.layout.BorderLayout.Region BorderLayout.Region}
* {@link Ext.layout.BorderLayout.Region#floatable floatable}
config option.
*/
- /**
- * @cfg {Boolean} autoScroll
- * true
to use overflow:'auto' on the panel's body element and show scroll bars automatically when
- * necessary, false
to clip any overflowing content (defaults to false
).
- */
+
/**
* @cfg {Mixed} floating
* This property is used to configure the underlying {@link Ext.Layer}. Acceptable values for this
@@ -8109,33 +8472,6 @@ var win = new Ext.Window({
* false
to disable the iframe shim in browsers which need one (defaults to true
).
* Note that this option only applies when {@link #floating} = true
.
*/
- /**
- * @cfg {String/Object} html
- * An HTML fragment, or a {@link Ext.DomHelper DomHelper} specification to use as the panel's body
- * content (defaults to ''). The HTML content is added by the Panel's {@link #afterRender} method,
- * and 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 {String} contentEl
- *
Optional. Specify an existing HTML element, or the id
of an existing HTML element to use as this Panel's
- * {@link #body}
content.
- *
- * - Description :
- * This config option is used to take an existing HTML element and place it in the body
- * of a new panel (it simply moves the specified DOM element into the body element of the Panel
- * after the Panel is rendered to use as the content (it is not going to be the actual panel itself).
- * - Notes :
- * The specified HTML element is appended to the Panel's {@link #body} Element by the
- * Panel's
afterRender
method 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#layout layout}
- * scheme that the Panel may use. It is just HTML. Layouts operate on child {@link Ext.Container#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 {Object/Array} keys
* A {@link Ext.KeyMap} config object (in the format expected by {@link Ext.KeyMap#addBinding}
@@ -8305,7 +8641,16 @@ new Ext.Panel({
* footer, etc.).
*/
preventBodyReset : false,
-
+
+ /**
+ * @cfg {Number/String} padding
+ * A shortcut for setting a padding style on the body element. The value can either be
+ * a number to be applied to all sides, or a normal css string describing padding.
+ * Defaults to undefined.
+ *
+ */
+ padding: undefined,
+
/** @cfg {String} resizeEvent
* The event to listen to for resizing in layouts. Defaults to 'bodyresize'.
*/
@@ -8424,19 +8769,18 @@ new Ext.Panel({
this.baseCls = 'x-plain';
}
+
+ this.toolbars = [];
// shortcuts
if(this.tbar){
this.elements += ',tbar';
- if(Ext.isObject(this.tbar)){
- this.topToolbar = this.tbar;
- }
+ this.topToolbar = this.createToolbar(this.tbar);
delete this.tbar;
+
}
if(this.bbar){
this.elements += ',bbar';
- if(Ext.isObject(this.bbar)){
- this.bottomToolbar = this.bbar;
- }
+ this.bottomToolbar = this.createToolbar(this.bbar);
delete this.bbar;
}
@@ -8453,33 +8797,61 @@ new Ext.Panel({
}
if(this.buttons){
- this.elements += ',footer';
- var btns = this.buttons;
- /**
- * This Panel's Array of buttons as created from the {@link #buttons}
- * config property. Read only.
- * @type Array
- * @property buttons
- */
- this.buttons = [];
- Ext.each(btns, function(btn){
- if(btn.render){ // button instance
- this.buttons.push(btn);
- }else if(btn.xtype){
- this.buttons.push(Ext.create(btn, 'button'));
- }else{
- this.addButton(btn);
- }
- }, this);
+ this.fbar = this.buttons;
+ delete this.buttons;
}
if(this.fbar){
- this.elements += ',footer';
+ this.createFbar(this.fbar);
}
if(this.autoLoad){
this.on('render', this.doAutoLoad, this, {delay:10});
}
},
+ // private
+ createFbar : function(fbar){
+ var min = this.minButtonWidth;
+ this.elements += ',footer';
+ this.fbar = this.createToolbar(fbar, {
+ buttonAlign: this.buttonAlign,
+ toolbarCls: 'x-panel-fbar',
+ enableOverflow: false,
+ defaults: function(c){
+ return {
+ minWidth: c.minWidth || min
+ };
+ }
+ });
+ //@compat addButton and buttons could possibly be removed
+ //@target 4.0
+ /**
+ * This Panel's Array of buttons as created from the {@link #buttons}
+ * config property. Read only.
+ * @type Array
+ * @property buttons
+ */
+ this.fbar.items.each(function(c){
+ c.minWidth = c.minWidth || this.minButtonWidth;
+ }, this);
+ this.buttons = this.fbar.items.items;
+ },
+
+ // private
+ createToolbar: function(tb, options){
+ var result;
+ // Convert array to proper toolbar config
+ if(Ext.isArray(tb)){
+ tb = {
+ items: tb
+ };
+ }
+ result = tb.events ? Ext.apply(tb, options) : this.createComponent(Ext.apply({}, tb, options), 'toolbar');
+ result.ownerCt = this;
+ result.bufferResize = false;
+ this.toolbars.push(result);
+ return result;
+ },
+
// private
createElement : function(name, pnode){
if(this[name]){
@@ -8513,23 +8885,23 @@ new Ext.Panel({
d = el.dom,
bw,
ts;
-
-
+
+
if(this.collapsible && !this.hideCollapseTool){
this.tools = this.tools ? this.tools.slice(0) : [];
this.tools[this.collapseFirst?'unshift':'push']({
id: 'toggle',
handler : this.toggleCollapse,
scope: this
- });
+ });
}
-
+
if(this.tools){
ts = this.tools;
this.elements += (this.header !== false) ? ',header' : '';
}
this.tools = {};
-
+
el.addClass(this.baseCls);
if(d.firstChild){ // existing markup
this.header = el.down('.'+this.headerCls);
@@ -8582,7 +8954,7 @@ new Ext.Panel({
* b) The last element is reported incorrectly when using a loadmask
*/
this.ft = Ext.get(this.bwrap.dom.lastChild);
- this.mc = Ext.get(this.bwrap.dom.firstChild.firstChild.firstChild);
+ this.mc = Ext.get(mc);
}else{
this.createElement('header', d);
this.createElement('bwrap', d);
@@ -8654,50 +9026,18 @@ new Ext.Panel({
if(ts){
this.addTool.apply(this, ts);
}
-
- if(this.buttons && this.buttons.length > 0){
- this.fbar = new Ext.Toolbar({
- items: this.buttons,
- toolbarCls: 'x-panel-fbar'
- });
- }
- this.toolbars = [];
if(this.fbar){
- this.fbar = Ext.create(this.fbar, 'toolbar');
- this.fbar.enableOverflow = false;
- if(this.fbar.items){
- this.fbar.items.each(function(c){
- c.minWidth = c.minWidth || this.minButtonWidth;
- }, this);
- }
- this.fbar.toolbarCls = 'x-panel-fbar';
-
- var bct = this.footer.createChild({cls: 'x-panel-btns x-panel-btns-'+this.buttonAlign});
- this.fbar.ownerCt = this;
- this.fbar.render(bct);
- bct.createChild({cls:'x-clear'});
- this.toolbars.push(this.fbar);
+ this.footer.addClass('x-panel-btns');
+ this.fbar.render(this.footer);
+ this.footer.createChild({cls:'x-clear'});
}
if(this.tbar && this.topToolbar){
- if(Ext.isArray(this.topToolbar)){
- this.topToolbar = new Ext.Toolbar(this.topToolbar);
- }else if(!this.topToolbar.events){
- this.topToolbar = Ext.create(this.topToolbar, 'toolbar');
- }
- this.topToolbar.ownerCt = this;
this.topToolbar.render(this.tbar);
- this.toolbars.push(this.topToolbar);
}
if(this.bbar && this.bottomToolbar){
- if(Ext.isArray(this.bottomToolbar)){
- this.bottomToolbar = new Ext.Toolbar(this.bottomToolbar);
- }else if(!this.bottomToolbar.events){
- this.bottomToolbar = Ext.create(this.bottomToolbar, 'toolbar');
- }
- this.bottomToolbar.ownerCt = this;
this.bottomToolbar.render(this.bbar);
- this.toolbars.push(this.bottomToolbar);
+
}
},
@@ -8731,14 +9071,12 @@ new Ext.Panel({
// private
makeFloating : function(cfg){
this.floating = true;
- this.el = new Ext.Layer(
- Ext.isObject(cfg) ? cfg : {
- shadow: Ext.isDefined(this.shadow) ? this.shadow : 'sides',
- shadowOffset: this.shadowOffset,
- constrain:false,
- shim: this.shim === false ? false : undefined
- }, this.el
- );
+ this.el = new Ext.Layer(Ext.apply({}, cfg, {
+ shadow: Ext.isDefined(this.shadow) ? this.shadow : 'sides',
+ shadowOffset: this.shadowOffset,
+ constrain:false,
+ shim: this.shim === false ? false : undefined
+ }), this.el);
},
/**
@@ -8763,27 +9101,23 @@ new Ext.Panel({
* @param {String/Object} config A valid {@link Ext.Button} config. A string will become the text for a default
* button config, an object will be treated as a button config object.
* @param {Function} handler The function to be called on button {@link Ext.Button#click}
- * @param {Object} scope The scope to use for the button handler function
+ * @param {Object} scope The scope (this
reference) in which the button handler function is executed. Defaults to the Button.
* @return {Ext.Button} The button that was added
*/
addButton : function(config, handler, scope){
- var bc = {
- handler: handler,
- scope: scope,
- minWidth: this.minButtonWidth,
- hideParent:true
- };
- if(Ext.isString(config)){
- bc.text = config;
- }else{
- Ext.apply(bc, config);
+ if(!this.fbar){
+ this.createFbar([]);
}
- var btn = new Ext.Button(bc);
- if(!this.buttons){
- this.buttons = [];
+ if(handler){
+ if(Ext.isString(config)){
+ config = {text: config};
+ }
+ config = Ext.apply({
+ handler: handler,
+ scope: scope
+ }, config)
}
- this.buttons.push(btn);
- return btn;
+ return this.fbar.add(config);
},
// private
@@ -8850,13 +9184,14 @@ new Ext.Panel({
syncHeight : function(){
var h = this.toolbarHeight,
bd = this.body,
- lsh = this.lastSize.height;
-
+ lsh = this.lastSize.height,
+ sz;
+
if(this.autoHeight || !Ext.isDefined(lsh) || lsh == 'auto'){
return;
}
-
-
+
+
if(h != this.getToolbarHeight()){
h = Math.max(0, this.adjustBodyHeight(lsh - this.getFrameHeight()));
bd.setHeight(h);
@@ -8895,7 +9230,7 @@ new Ext.Panel({
};
},
- // private
+ // private
afterRender : function(){
if(this.floating && !this.hidden){
this.el.show();
@@ -8903,35 +9238,13 @@ new Ext.Panel({
if(this.title){
this.setTitle(this.title);
}
- this.setAutoScroll();
- if(this.html){
- this.body.update(Ext.isObject(this.html) ?
- Ext.DomHelper.markup(this.html) :
- this.html);
- delete this.html;
- }
- if(this.contentEl){
- var ce = Ext.getDom(this.contentEl);
- Ext.fly(ce).removeClass(['x-hidden', 'x-hide-display']);
- this.body.dom.appendChild(ce);
- }
if(this.collapsed){
this.collapsed = false;
this.collapse(false);
}
Ext.Panel.superclass.afterRender.call(this); // do sizing calcs last
this.initEvents();
- },
-
- // private
- setAutoScroll : function(){
- if(this.rendered && this.autoScroll){
- var el = this.body || this.el;
- if(el){
- el.setOverflow('auto');
- }
- }
- },
+ },
// private
getKeyMap : function(){
@@ -8962,6 +9275,7 @@ new Ext.Panel({
this.syncHeight();
}
}
+
},
// private
@@ -9123,49 +9437,43 @@ new Ext.Panel({
onResize : function(w, h){
if(Ext.isDefined(w) || Ext.isDefined(h)){
if(!this.collapsed){
+ // First, set the the Panel's body width.
+ // If we have auto-widthed it, get the resulting full offset width so we can size the Toolbars to match
+ // The Toolbars must not buffer this resize operation because we need to know their heights.
+
if(Ext.isNumber(w)){
- w = this.adjustBodyWidth(w - this.getFrameWidth());
- if(this.tbar){
- this.tbar.setWidth(w);
- if(this.topToolbar){
- this.topToolbar.setSize(w);
- }
+ this.body.setWidth(w = this.adjustBodyWidth(w - this.getFrameWidth()));
+ } else if (w == 'auto') {
+ w = this.body.setWidth('auto').dom.offsetWidth;
+ } else {
+ w = this.body.dom.offsetWidth;
+ }
+
+ if(this.tbar){
+ this.tbar.setWidth(w);
+ if(this.topToolbar){
+ this.topToolbar.setSize(w);
}
- if(this.bbar){
- this.bbar.setWidth(w);
- if(this.bottomToolbar){
- this.bottomToolbar.setSize(w);
+ }
+ if(this.bbar){
+ this.bbar.setWidth(w);
+ if(this.bottomToolbar){
+ this.bottomToolbar.setSize(w);
+ // The bbar does not move on resize without this.
+ if (Ext.isIE) {
+ this.bbar.setStyle('position', 'static');
+ this.bbar.setStyle('position', '');
}
}
+ }
+ if(this.footer){
+ this.footer.setWidth(w);
if(this.fbar){
- var f = this.fbar,
- fWidth = 1,
- strict = Ext.isStrict;
- if(this.buttonAlign == 'left'){
- fWidth = w - f.container.getFrameWidth('lr');
- }else{
- //center/right alignment off in webkit
- if(Ext.isIE || Ext.isWebKit){
- //center alignment ok on webkit.
- //right broken in both, center on IE
- if(!(this.buttonAlign == 'center' && Ext.isWebKit) && (!strict || (!Ext.isIE8 && strict))){
- (function(){
- f.setWidth(f.getEl().child('.x-toolbar-ct').getWidth());
- }).defer(1);
- }else{
- fWidth = 'auto';
- }
- }else{
- fWidth = 'auto';
- }
- }
- f.setWidth(fWidth);
+ this.fbar.setSize(Ext.isIE ? (w - this.footer.getFrameWidth('lr')) : 'auto');
}
- this.body.setWidth(w);
- }else if(w == 'auto'){
- this.body.setWidth(w);
}
+ // At this point, the Toolbars must be layed out for getFrameHeight to find a result.
if(Ext.isNumber(h)){
h = Math.max(0, this.adjustBodyHeight(h - this.getFrameHeight()));
this.body.setHeight(h);
@@ -9183,20 +9491,20 @@ new Ext.Panel({
this.on('expand', function(){
delete this.queuedExpand;
this.onResize(this.queuedBodySize.width, this.queuedBodySize.height);
- this.doLayout();
}, this, {single:true});
}
}
this.onBodyResize(w, h);
}
this.syncShadow();
+ Ext.Panel.superclass.onResize.call(this);
},
-
+
// private
onBodyResize: function(w, h){
this.fireEvent('bodyresize', this, w, h);
},
-
+
// private
getToolbarHeight: function(){
var h = 0;
@@ -9288,6 +9596,11 @@ new Ext.Panel({
return this.body;
},
+ // private
+ getContentTarget : function(){
+ return this.body;
+ },
+
/**
* Sets the title text for the panel and optionally the {@link #iconCls icon class}.
* In order to be able to set the title, a header element must have been created
@@ -9345,38 +9658,44 @@ panel.load({
// private
beforeDestroy : function(){
+ Ext.Panel.superclass.beforeDestroy.call(this);
if(this.header){
this.header.removeAllListeners();
- if(this.headerAsText){
- Ext.Element.uncache(this.header.child('span'));
- }
- }
- Ext.Element.uncache(
- this.ft,
- this.mc,
- this.header,
- this.tbar,
- this.bbar,
- this.footer,
- this.body,
- this.bwrap
- );
+ }
if(this.tools){
for(var k in this.tools){
Ext.destroy(this.tools[k]);
}
}
- if(this.buttons){
- for(var b in this.buttons){
- Ext.destroy(this.buttons[b]);
+ if(Ext.isArray(this.buttons)){
+ while(this.buttons.length) {
+ Ext.destroy(this.buttons[0]);
}
}
if(this.rendered){
- Ext.destroy(this.toolbars);
+ Ext.destroy(
+ this.ft,
+ this.header,
+ this.footer,
+ this.toolbars,
+ this.tbar,
+ this.bbar,
+ this.body,
+ this.mc,
+ this.bwrap
+ );
+ if (this.fbar) {
+ Ext.destroy(
+ this.fbar,
+ this.fbar.el
+ );
+ }
}else{
- Ext.destroy(this.topToolbar, this.bottomToolbar);
+ Ext.destroy(
+ this.topToolbar,
+ this.bottomToolbar
+ );
}
- Ext.Panel.superclass.beforeDestroy.call(this);
},
// private
@@ -9496,6 +9815,11 @@ Ext.extend(Ext.Editor, Ext.Component, {
* The position to align to (see {@link Ext.Element#alignTo} for more details, defaults to "c-c?").
*/
alignment: "c-c?",
+ /**
+ * @cfg {Array} offsets
+ * The offsets to use when aligning (see {@link Ext.Element#alignTo} for more details. Defaults to [0, 0].
+ */
+ offsets: [0, 0],
/**
* @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
* for bottom-right shadow (defaults to "frame")
@@ -9652,9 +9976,9 @@ Ext.extend(Ext.Editor, Ext.Component, {
}
if(this.fireEvent("beforestartedit", this, this.boundEl, v) !== false){
this.startValue = v;
+ this.field.reset();
this.field.setValue(v);
- this.doAutoSize();
- this.el.alignTo(this.boundEl, this.alignment);
+ this.realign(true);
this.editing = true;
this.show();
}
@@ -9701,9 +10025,13 @@ Ext.extend(Ext.Editor, Ext.Component, {
/**
* Realigns the editor to the bound field based on the current alignment config value.
+ * @param {Boolean} autoSize (optional) True to size the field to the dimensions of the bound element.
*/
- realign : function(){
- this.el.alignTo(this.boundEl, this.alignment);
+ realign : function(autoSize){
+ if(autoSize === true){
+ this.doAutoSize();
+ }
+ this.el.alignTo(this.boundEl, this.alignment, this.offsets);
},
/**
@@ -9808,11 +10136,14 @@ Ext.extend(Ext.Editor, Ext.Component, {
},
beforeDestroy : function(){
- Ext.destroy(this.field);
- this.field = null;
+ Ext.destroyMembers(this, 'field');
+
+ delete this.parentEl;
+ delete this.boundEl;
}
});
-Ext.reg('editor', Ext.Editor);/**
+Ext.reg('editor', Ext.Editor);
+/**
* @class Ext.ColorPalette
* @extends Ext.Component
* Simple color palette class for choosing colors. The palette can be rendered to any container.
@@ -9830,23 +10161,7 @@ cp.on('select', function(palette, selColor){
* @param {Object} config The config object
* @xtype colorpalette
*/
-Ext.ColorPalette = function(config){
- Ext.ColorPalette.superclass.constructor.call(this, config);
- this.addEvents(
- /**
- * @event select
- * Fires when a color is selected
- * @param {ColorPalette} this
- * @param {String} color The 6-digit color hex code (without the # symbol)
- */
- 'select'
- );
-
- if(this.handler){
- this.on('select', this.handler, this.scope, true);
- }
-};
-Ext.extend(Ext.ColorPalette, Ext.Component, {
+Ext.ColorPalette = Ext.extend(Ext.Component, {
/**
* @cfg {String} tpl An existing XTemplate instance to be used in place of the default template for rendering the component.
*/
@@ -9861,6 +10176,11 @@ Ext.extend(Ext.ColorPalette, Ext.Component, {
* the hex codes are case-sensitive.
*/
value : null,
+ /**
+ * @cfg {String} clickEvent
+ * The DOM event that will cause a color to be selected. This can be any valid event name (dblclick, contextmenu).
+ * Defaults to 'click'.
+ */
clickEvent :'click',
// private
ctype : 'Ext.ColorPalette',
@@ -9909,18 +10229,36 @@ cp.colors = ['000000', '993300', '333300'];
* The scope (this reference) in which the {@link #handler}
* function will be called. Defaults to this ColorPalette instance.
*/
+
+ // private
+ initComponent : function(){
+ Ext.ColorPalette.superclass.initComponent.call(this);
+ this.addEvents(
+ /**
+ * @event select
+ * Fires when a color is selected
+ * @param {ColorPalette} this
+ * @param {String} color The 6-digit color hex code (without the # symbol)
+ */
+ 'select'
+ );
+
+ if(this.handler){
+ this.on('select', this.handler, this.scope, true);
+ }
+ },
// private
onRender : function(container, position){
+ this.autoEl = {
+ tag: 'div',
+ cls: this.itemCls
+ };
+ Ext.ColorPalette.superclass.onRender.call(this, container, position);
var t = this.tpl || new Ext.XTemplate(
' '
);
- var el = document.createElement('div');
- el.id = this.getId();
- el.className = this.itemCls;
- t.overwrite(el, this.colors);
- container.dom.insertBefore(el, position);
- this.el = Ext.get(el);
+ t.overwrite(this.el, this.colors);
this.mon(this.el, this.clickEvent, this.handleClick, this, {delegate: 'a'});
if(this.clickEvent != 'click'){
this.mon(this.el, 'click', Ext.emptyFn, this, {delegate: 'a', preventDefault: true});
@@ -9964,783 +10302,796 @@ cp.colors = ['000000', '993300', '333300'];
}
/**
- * @cfg {String} autoEl @hide
+ * @cfg {String} autoEl @hide
+ */
+});
+Ext.reg('colorpalette', Ext.ColorPalette);
+/**
+ * @class Ext.DatePicker
+ * @extends Ext.Component
+ *
A popup date picker. This class is used by the {@link Ext.form.DateField DateField} class
+ * to allow browsing and selection of valid dates.
+ * All the string values documented below may be overridden by including an Ext locale file in
+ * your page.
+ * @constructor
+ * Create a new DatePicker
+ * @param {Object} config The config object
+ * @xtype datepicker
+ */
+Ext.DatePicker = Ext.extend(Ext.BoxComponent, {
+ /**
+ * @cfg {String} todayText
+ * The text to display on the button that selects the current date (defaults to 'Today'
)
+ */
+ todayText : 'Today',
+ /**
+ * @cfg {String} okText
+ * The text to display on the ok button (defaults to ' OK '
to give the user extra clicking room)
+ */
+ okText : ' OK ',
+ /**
+ * @cfg {String} cancelText
+ * The text to display on the cancel button (defaults to 'Cancel'
)
+ */
+ cancelText : 'Cancel',
+ /**
+ * @cfg {Function} handler
+ * Optional. A function that will handle the select event of this picker.
+ * The handler is passed the following parameters:
+ * picker
: DatePickerThis DatePicker.
+ * date
: DateThe selected date.
+ *
+ */
+ /**
+ * @cfg {Object} scope
+ * The scope (this
reference) in which the {@link #handler}
+ * function will be called. Defaults to this DatePicker instance.
+ */
+ /**
+ * @cfg {String} todayTip
+ * A string used to format the message for displaying in a tooltip over the button that
+ * selects the current date. Defaults to '{0} (Spacebar)'
where
+ * the {0}
token is replaced by today's date.
+ */
+ todayTip : '{0} (Spacebar)',
+ /**
+ * @cfg {String} minText
+ * The error text to display if the minDate validation fails (defaults to 'This date is before the minimum date'
)
+ */
+ minText : 'This date is before the minimum date',
+ /**
+ * @cfg {String} maxText
+ * The error text to display if the maxDate validation fails (defaults to 'This date is after the maximum date'
)
+ */
+ maxText : 'This date is after the maximum date',
+ /**
+ * @cfg {String} format
+ * The default date format string which can be overriden for localization support. The format must be
+ * valid according to {@link Date#parseDate} (defaults to 'm/d/y'
).
+ */
+ format : 'm/d/y',
+ /**
+ * @cfg {String} disabledDaysText
+ * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled'
)
+ */
+ disabledDaysText : 'Disabled',
+ /**
+ * @cfg {String} disabledDatesText
+ * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled'
)
+ */
+ disabledDatesText : 'Disabled',
+ /**
+ * @cfg {Array} monthNames
+ * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
+ */
+ monthNames : Date.monthNames,
+ /**
+ * @cfg {Array} dayNames
+ * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
+ */
+ dayNames : Date.dayNames,
+ /**
+ * @cfg {String} nextText
+ * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)'
)
*/
-});
-Ext.reg('colorpalette', Ext.ColorPalette);
-/**
- * @class Ext.DatePicker
- * @extends Ext.Component
- * Simple date picker class.
- * @constructor
- * Create a new DatePicker
- * @param {Object} config The config object
- * @xtype datepicker
- */
-Ext.DatePicker = Ext.extend(Ext.BoxComponent, {
- /**
- * @cfg {String} todayText
- * The text to display on the button that selects the current date (defaults to 'Today')
- */
- todayText : 'Today',
- /**
- * @cfg {String} okText
- * The text to display on the ok button (defaults to ' OK ' to give the user extra clicking room)
- */
- okText : ' OK ',
- /**
- * @cfg {String} cancelText
- * The text to display on the cancel button (defaults to 'Cancel')
- */
- cancelText : 'Cancel',
- /**
- * @cfg {Function} handler
- * Optional. A function that will handle the select event of this picker.
- * The handler is passed the following parameters:
- * picker
: DatePickerThe Ext.DatePicker.
- * date
: DateThe selected date.
- *
- */
- /**
- * @cfg {Object} scope
- * The scope (this reference) in which the {@link #handler}
- * function will be called. Defaults to this DatePicker instance.
- */
- /**
- * @cfg {String} todayTip
- * The tooltip to display for the button that selects the current date (defaults to '{current date} (Spacebar)')
- */
- todayTip : '{0} (Spacebar)',
- /**
- * @cfg {String} minText
- * The error text to display if the minDate validation fails (defaults to 'This date is before the minimum date')
- */
- minText : 'This date is before the minimum date',
- /**
- * @cfg {String} maxText
- * The error text to display if the maxDate validation fails (defaults to 'This date is after the maximum date')
- */
- maxText : 'This date is after the maximum date',
- /**
- * @cfg {String} format
- * The default date format string which can be overriden for localization support. The format must be
- * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
- */
- format : 'm/d/y',
- /**
- * @cfg {String} disabledDaysText
- * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
- */
- disabledDaysText : 'Disabled',
- /**
- * @cfg {String} disabledDatesText
- * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
- */
- disabledDatesText : 'Disabled',
- /**
- * @cfg {Array} monthNames
- * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
- */
- monthNames : Date.monthNames,
- /**
- * @cfg {Array} dayNames
- * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
- */
- dayNames : Date.dayNames,
- /**
- * @cfg {String} nextText
- * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
- */
- nextText : 'Next Month (Control+Right)',
- /**
- * @cfg {String} prevText
- * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
- */
- prevText : 'Previous Month (Control+Left)',
- /**
- * @cfg {String} monthYearText
- * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
- */
- monthYearText : 'Choose a month (Control+Up/Down to move years)',
- /**
- * @cfg {Number} startDay
- * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
- */
- startDay : 0,
- /**
- * @cfg {Boolean} showToday
- * False to hide the footer area containing the Today button and disable the keyboard handler for spacebar
- * that selects the current date (defaults to true).
- */
- showToday : true,
- /**
- * @cfg {Date} minDate
- * Minimum allowable date (JavaScript date object, defaults to null)
- */
- /**
- * @cfg {Date} maxDate
- * Maximum allowable date (JavaScript date object, defaults to null)
- */
- /**
- * @cfg {Array} disabledDays
- * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
- */
- /**
- * @cfg {RegExp} disabledDatesRE
- * JavaScript regular expression used to disable a pattern of dates (defaults to null). The {@link #disabledDates}
- * config will generate this regex internally, but if you specify disabledDatesRE it will take precedence over the
- * disabledDates value.
- */
- /**
- * @cfg {Array} disabledDates
- * An array of 'dates' to disable, as strings. These strings will be used to build a dynamic regular
- * expression so they are very powerful. Some examples:
- *
- * - ['03/08/2003', '09/16/2003'] would disable those exact dates
- * - ['03/08', '09/16'] would disable those days for every year
- * - ['^03/08'] would only match the beginning (useful if you are using short years)
- * - ['03/../2006'] would disable every day in March 2006
- * - ['^03'] would disable every day in every March
- *
- * Note that the format of the dates included in the array should exactly match the {@link #format} config.
- * In order to support regular expressions, if you are using a date format that has '.' in it, you will have to
- * escape the dot when restricting dates. For example: ['03\\.08\\.03'].
- */
-
- // private
- initComponent : function(){
- Ext.DatePicker.superclass.initComponent.call(this);
-
- this.value = this.value ?
- this.value.clearTime(true) : new Date().clearTime();
-
- this.addEvents(
- /**
- * @event select
- * Fires when a date is selected
- * @param {DatePicker} this
- * @param {Date} date The selected date
- */
- 'select'
- );
-
- if(this.handler){
- this.on('select', this.handler, this.scope || this);
- }
-
- this.initDisabledDays();
- },
-
- // private
- initDisabledDays : function(){
- if(!this.disabledDatesRE && this.disabledDates){
- var dd = this.disabledDates,
- len = dd.length - 1,
- re = '(?:';
-
- Ext.each(dd, function(d, i){
- re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i];
- if(i != len){
- re += '|';
- }
- }, this);
- this.disabledDatesRE = new RegExp(re + ')');
- }
- },
-
- /**
- * Replaces any existing disabled dates with new values and refreshes the DatePicker.
- * @param {Array/RegExp} disabledDates An array of date strings (see the {@link #disabledDates} config
- * for details on supported values), or a JavaScript regular expression used to disable a pattern of dates.
- */
- setDisabledDates : function(dd){
- if(Ext.isArray(dd)){
- this.disabledDates = dd;
- this.disabledDatesRE = null;
- }else{
- this.disabledDatesRE = dd;
- }
- this.initDisabledDays();
- this.update(this.value, true);
- },
-
- /**
- * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.
- * @param {Array} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config
- * for details on supported values.
- */
- setDisabledDays : function(dd){
- this.disabledDays = dd;
- this.update(this.value, true);
- },
-
- /**
- * Replaces any existing {@link #minDate} with the new value and refreshes the DatePicker.
- * @param {Date} value The minimum date that can be selected
- */
- setMinDate : function(dt){
- this.minDate = dt;
- this.update(this.value, true);
- },
-
- /**
- * Replaces any existing {@link #maxDate} with the new value and refreshes the DatePicker.
- * @param {Date} value The maximum date that can be selected
- */
- setMaxDate : function(dt){
- this.maxDate = dt;
- this.update(this.value, true);
- },
-
- /**
- * Sets the value of the date field
- * @param {Date} value The date to set
- */
- setValue : function(value){
- this.value = value.clearTime(true);
- this.update(this.value);
- },
-
- /**
- * Gets the current selected value of the date field
- * @return {Date} The selected date
- */
- getValue : function(){
- return this.value;
- },
-
- // private
- focus : function(){
- this.update(this.activeDate);
- },
-
- // private
- onEnable: function(initial){
- Ext.DatePicker.superclass.onEnable.call(this);
- this.doDisabled(false);
- this.update(initial ? this.value : this.activeDate);
- if(Ext.isIE){
- this.el.repaint();
- }
-
- },
-
- // private
- onDisable : function(){
- Ext.DatePicker.superclass.onDisable.call(this);
- this.doDisabled(true);
- if(Ext.isIE && !Ext.isIE8){
- /* Really strange problem in IE6/7, when disabled, have to explicitly
- * repaint each of the nodes to get them to display correctly, simply
- * calling repaint on the main element doesn't appear to be enough.
- */
- Ext.each([].concat(this.textNodes, this.el.query('th span')), function(el){
- Ext.fly(el).repaint();
- });
- }
- },
-
- // private
- doDisabled : function(disabled){
- this.keyNav.setDisabled(disabled);
- this.prevRepeater.setDisabled(disabled);
- this.nextRepeater.setDisabled(disabled);
- if(this.showToday){
- this.todayKeyListener.setDisabled(disabled);
- this.todayBtn.setDisabled(disabled);
- }
- },
-
- // private
- onRender : function(container, position){
- var m = [
- ''];
- for(var i = 0; i < 6; i++){
- buf.push(
- '', Date.getShortMonthName(i), ' ',
- '', Date.getShortMonthName(i + 6), ' ',
- i === 0 ?
- ' ' :
- ' '
- );
- }
- buf.push(
- ' ',
- '
'
- );
- this.monthPicker.update(buf.join(''));
-
- this.mon(this.monthPicker, 'click', this.onMonthClick, this);
- this.mon(this.monthPicker, 'dblclick', this.onMonthDblClick, this);
-
- this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
- this.mpYears = this.monthPicker.select('td.x-date-mp-year');
-
- this.mpMonths.each(function(m, a, i){
- i += 1;
- if((i%2) === 0){
- m.dom.xmonth = 5 + Math.round(i * 0.5);
- }else{
- m.dom.xmonth = Math.round((i-1) * 0.5);
- }
- });
- }
- },
-
- // private
- showMonthPicker : function(){
- if(!this.disabled){
- this.createMonthPicker();
- var size = this.el.getSize();
- this.monthPicker.setSize(size);
- this.monthPicker.child('table').setSize(size);
-
- this.mpSelMonth = (this.activeDate || this.value).getMonth();
- this.updateMPMonth(this.mpSelMonth);
- this.mpSelYear = (this.activeDate || this.value).getFullYear();
- this.updateMPYear(this.mpSelYear);
-
- this.monthPicker.slideIn('t', {duration:0.2});
- }
- },
-
- // private
- updateMPYear : function(y){
- this.mpyear = y;
- var ys = this.mpYears.elements;
- for(var i = 1; i <= 10; i++){
- var td = ys[i-1], y2;
- if((i%2) === 0){
- y2 = y + Math.round(i * 0.5);
- td.firstChild.innerHTML = y2;
- td.xyear = y2;
- }else{
- y2 = y - (5-Math.round(i * 0.5));
- td.firstChild.innerHTML = y2;
- td.xyear = y2;
- }
- this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
- }
- },
-
- // private
- updateMPMonth : function(sm){
- this.mpMonths.each(function(m, a, i){
- m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
- });
- },
-
- // private
- selectMPMonth : function(m){
-
- },
-
- // private
- onMonthClick : function(e, t){
- e.stopEvent();
- var el = new Ext.Element(t), pn;
- if(el.is('button.x-date-mp-cancel')){
- this.hideMonthPicker();
- }
- else if(el.is('button.x-date-mp-ok')){
- var d = new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate());
- if(d.getMonth() != this.mpSelMonth){
- // 'fix' the JS rolling date conversion if needed
- d = new Date(this.mpSelYear, this.mpSelMonth, 1).getLastDateOfMonth();
- }
- this.update(d);
- this.hideMonthPicker();
- }
- else if((pn = el.up('td.x-date-mp-month', 2))){
- this.mpMonths.removeClass('x-date-mp-sel');
- pn.addClass('x-date-mp-sel');
- this.mpSelMonth = pn.dom.xmonth;
- }
- else if((pn = el.up('td.x-date-mp-year', 2))){
- this.mpYears.removeClass('x-date-mp-sel');
- pn.addClass('x-date-mp-sel');
- this.mpSelYear = pn.dom.xyear;
- }
- else if(el.is('a.x-date-mp-prev')){
- this.updateMPYear(this.mpyear-10);
- }
- else if(el.is('a.x-date-mp-next')){
- this.updateMPYear(this.mpyear+10);
- }
- },
-
- // private
- onMonthDblClick : function(e, t){
- e.stopEvent();
- var el = new Ext.Element(t), pn;
- if((pn = el.up('td.x-date-mp-month', 2))){
- this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
- this.hideMonthPicker();
- }
- else if((pn = el.up('td.x-date-mp-year', 2))){
- this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
- this.hideMonthPicker();
- }
- },
-
- // private
- hideMonthPicker : function(disableAnim){
- if(this.monthPicker){
- if(disableAnim === true){
- this.monthPicker.hide();
- }else{
- this.monthPicker.slideOut('t', {duration:0.2});
- }
- }
- },
-
- // private
- showPrevMonth : function(e){
- this.update(this.activeDate.add('mo', -1));
- },
-
- // private
- showNextMonth : function(e){
- this.update(this.activeDate.add('mo', 1));
- },
-
- // private
- showPrevYear : function(){
- this.update(this.activeDate.add('y', -1));
- },
-
- // private
- showNextYear : function(){
- this.update(this.activeDate.add('y', 1));
- },
-
- // private
- handleMouseWheel : function(e){
- e.stopEvent();
- if(!this.disabled){
- var delta = e.getWheelDelta();
- if(delta > 0){
- this.showPrevMonth();
- } else if(delta < 0){
- this.showNextMonth();
- }
- }
- },
-
- // private
- handleDateClick : function(e, t){
- e.stopEvent();
- if(!this.disabled && t.dateValue && !Ext.fly(t.parentNode).hasClass('x-date-disabled')){
- this.setValue(new Date(t.dateValue));
- this.fireEvent('select', this, this.value);
- }
- },
-
- // private
- selectToday : function(){
- if(this.todayBtn && !this.todayBtn.disabled){
- this.setValue(new Date().clearTime());
- this.fireEvent('select', this, this.value);
- }
- },
-
- // private
- update : function(date, forceRefresh){
- if(this.rendered){
- var vd = this.activeDate, vis = this.isVisible();
- this.activeDate = date;
- if(!forceRefresh && vd && this.el){
- var t = date.getTime();
- if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
- this.cells.removeClass('x-date-selected');
- this.cells.each(function(c){
- if(c.dom.firstChild.dateValue == t){
- c.addClass('x-date-selected');
- if(vis){
- Ext.fly(c.dom.firstChild).focus(50);
- }
- return false;
- }
- });
- return;
- }
- }
- var days = date.getDaysInMonth(),
- firstOfMonth = date.getFirstDateOfMonth(),
- startingPos = firstOfMonth.getDay()-this.startDay;
-
- if(startingPos < 0){
- startingPos += 7;
- }
- days += startingPos;
-
- var pm = date.add('mo', -1),
- prevStart = pm.getDaysInMonth()-startingPos,
- cells = this.cells.elements,
- textEls = this.textNodes,
- // convert everything to numbers so it's fast
- day = 86400000,
- d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime(),
- today = new Date().clearTime().getTime(),
- sel = date.clearTime(true).getTime(),
- min = this.minDate ? this.minDate.clearTime(true) : Number.NEGATIVE_INFINITY,
- max = this.maxDate ? this.maxDate.clearTime(true) : Number.POSITIVE_INFINITY,
- ddMatch = this.disabledDatesRE,
- ddText = this.disabledDatesText,
- ddays = this.disabledDays ? this.disabledDays.join('') : false,
- ddaysText = this.disabledDaysText,
- format = this.format;
-
- if(this.showToday){
- var td = new Date().clearTime(),
- disable = (td < min || td > max ||
- (ddMatch && format && ddMatch.test(td.dateFormat(format))) ||
- (ddays && ddays.indexOf(td.getDay()) != -1));
-
- if(!this.disabled){
- this.todayBtn.setDisabled(disable);
- this.todayKeyListener[disable ? 'disable' : 'enable']();
- }
- }
-
- var setCellClass = function(cal, cell){
- cell.title = '';
- var t = d.getTime();
- cell.firstChild.dateValue = t;
- if(t == today){
- cell.className += ' x-date-today';
- cell.title = cal.todayText;
- }
- if(t == sel){
- cell.className += ' x-date-selected';
- if(vis){
- Ext.fly(cell.firstChild).focus(50);
- }
- }
- // disabling
- if(t < min) {
- cell.className = ' x-date-disabled';
- cell.title = cal.minText;
- return;
- }
- if(t > max) {
- cell.className = ' x-date-disabled';
- cell.title = cal.maxText;
- return;
- }
- if(ddays){
- if(ddays.indexOf(d.getDay()) != -1){
- cell.title = ddaysText;
- cell.className = ' x-date-disabled';
- }
- }
- if(ddMatch && format){
- var fvalue = d.dateFormat(format);
- if(ddMatch.test(fvalue)){
- cell.title = ddText.replace('%0', fvalue);
- cell.className = ' x-date-disabled';
- }
- }
- };
-
- var i = 0;
- for(; i < startingPos; i++) {
- textEls[i].innerHTML = (++prevStart);
- d.setDate(d.getDate()+1);
- cells[i].className = 'x-date-prevday';
- setCellClass(this, cells[i]);
- }
- for(; i < days; i++){
- var intDay = i - startingPos + 1;
- textEls[i].innerHTML = (intDay);
- d.setDate(d.getDate()+1);
- cells[i].className = 'x-date-active';
- setCellClass(this, cells[i]);
- }
- var extraDays = 0;
- for(; i < 42; i++) {
- textEls[i].innerHTML = (++extraDays);
- d.setDate(d.getDate()+1);
- cells[i].className = 'x-date-nextday';
- setCellClass(this, cells[i]);
- }
-
- this.mbtn.setText(this.monthNames[date.getMonth()] + ' ' + date.getFullYear());
-
- if(!this.internalRender){
- var main = this.el.dom.firstChild,
- w = main.offsetWidth;
- this.el.setWidth(w + this.el.getBorderWidth('lr'));
- Ext.fly(main).setWidth(w);
- this.internalRender = true;
- // opera does not respect the auto grow header center column
- // then, after it gets a width opera refuses to recalculate
- // without a second pass
- if(Ext.isOpera && !this.secondPass){
- main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + 'px';
- this.secondPass = true;
- this.update.defer(10, this, [date]);
- }
- }
- }
- },
-
- // private
- beforeDestroy : function() {
- if(this.rendered){
- this.keyNav.disable();
- this.keyNav = null;
- Ext.destroy(
- this.leftClickRpt,
- this.rightClickRpt,
- this.monthPicker,
- this.eventEl,
- this.mbtn,
- this.todayBtn
- );
- }
- }
-
- /**
- * @cfg {String} autoEl @hide
- */
-});
-
-Ext.reg('datepicker', Ext.DatePicker);
+ nextText : 'Next Month (Control+Right)',
+ /**
+ * @cfg {String} prevText
+ * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)'
)
+ */
+ prevText : 'Previous Month (Control+Left)',
+ /**
+ * @cfg {String} monthYearText
+ * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)'
)
+ */
+ monthYearText : 'Choose a month (Control+Up/Down to move years)',
+ /**
+ * @cfg {Number} startDay
+ * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
+ */
+ startDay : 0,
+ /**
+ * @cfg {Boolean} showToday
+ * False to hide the footer area containing the Today button and disable the keyboard handler for spacebar
+ * that selects the current date (defaults to true
).
+ */
+ showToday : true,
+ /**
+ * @cfg {Date} minDate
+ * Minimum allowable date (JavaScript date object, defaults to null)
+ */
+ /**
+ * @cfg {Date} maxDate
+ * Maximum allowable date (JavaScript date object, defaults to null)
+ */
+ /**
+ * @cfg {Array} disabledDays
+ * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
+ */
+ /**
+ * @cfg {RegExp} disabledDatesRE
+ * JavaScript regular expression used to disable a pattern of dates (defaults to null). The {@link #disabledDates}
+ * config will generate this regex internally, but if you specify disabledDatesRE it will take precedence over the
+ * disabledDates value.
+ */
+ /**
+ * @cfg {Array} disabledDates
+ * An array of 'dates' to disable, as strings. These strings will be used to build a dynamic regular
+ * expression so they are very powerful. Some examples:
+ *
+ * - ['03/08/2003', '09/16/2003'] would disable those exact dates
+ * - ['03/08', '09/16'] would disable those days for every year
+ * - ['^03/08'] would only match the beginning (useful if you are using short years)
+ * - ['03/../2006'] would disable every day in March 2006
+ * - ['^03'] would disable every day in every March
+ *
+ * Note that the format of the dates included in the array should exactly match the {@link #format} config.
+ * In order to support regular expressions, if you are using a date format that has '.' in it, you will have to
+ * escape the dot when restricting dates. For example: ['03\\.08\\.03'].
+ */
+
+ // private
+ // Set by other components to stop the picker focus being updated when the value changes.
+ focusOnSelect: true,
+
+ // private
+ initComponent : function(){
+ Ext.DatePicker.superclass.initComponent.call(this);
+
+ this.value = this.value ?
+ this.value.clearTime(true) : new Date().clearTime();
+
+ this.addEvents(
+ /**
+ * @event select
+ * Fires when a date is selected
+ * @param {DatePicker} this DatePicker
+ * @param {Date} date The selected date
+ */
+ 'select'
+ );
+
+ if(this.handler){
+ this.on('select', this.handler, this.scope || this);
+ }
+
+ this.initDisabledDays();
+ },
+
+ // private
+ initDisabledDays : function(){
+ if(!this.disabledDatesRE && this.disabledDates){
+ var dd = this.disabledDates,
+ len = dd.length - 1,
+ re = '(?:';
+
+ Ext.each(dd, function(d, i){
+ re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i];
+ if(i != len){
+ re += '|';
+ }
+ }, this);
+ this.disabledDatesRE = new RegExp(re + ')');
+ }
+ },
+
+ /**
+ * Replaces any existing disabled dates with new values and refreshes the DatePicker.
+ * @param {Array/RegExp} disabledDates An array of date strings (see the {@link #disabledDates} config
+ * for details on supported values), or a JavaScript regular expression used to disable a pattern of dates.
+ */
+ setDisabledDates : function(dd){
+ if(Ext.isArray(dd)){
+ this.disabledDates = dd;
+ this.disabledDatesRE = null;
+ }else{
+ this.disabledDatesRE = dd;
+ }
+ this.initDisabledDays();
+ this.update(this.value, true);
+ },
+
+ /**
+ * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.
+ * @param {Array} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config
+ * for details on supported values.
+ */
+ setDisabledDays : function(dd){
+ this.disabledDays = dd;
+ this.update(this.value, true);
+ },
+
+ /**
+ * Replaces any existing {@link #minDate} with the new value and refreshes the DatePicker.
+ * @param {Date} value The minimum date that can be selected
+ */
+ setMinDate : function(dt){
+ this.minDate = dt;
+ this.update(this.value, true);
+ },
+
+ /**
+ * Replaces any existing {@link #maxDate} with the new value and refreshes the DatePicker.
+ * @param {Date} value The maximum date that can be selected
+ */
+ setMaxDate : function(dt){
+ this.maxDate = dt;
+ this.update(this.value, true);
+ },
+
+ /**
+ * Sets the value of the date field
+ * @param {Date} value The date to set
+ */
+ setValue : function(value){
+ this.value = value.clearTime(true);
+ this.update(this.value);
+ },
+
+ /**
+ * Gets the current selected value of the date field
+ * @return {Date} The selected date
+ */
+ getValue : function(){
+ return this.value;
+ },
+
+ // private
+ focus : function(){
+ this.update(this.activeDate);
+ },
+
+ // private
+ onEnable: function(initial){
+ Ext.DatePicker.superclass.onEnable.call(this);
+ this.doDisabled(false);
+ this.update(initial ? this.value : this.activeDate);
+ if(Ext.isIE){
+ this.el.repaint();
+ }
+
+ },
+
+ // private
+ onDisable : function(){
+ Ext.DatePicker.superclass.onDisable.call(this);
+ this.doDisabled(true);
+ if(Ext.isIE && !Ext.isIE8){
+ /* Really strange problem in IE6/7, when disabled, have to explicitly
+ * repaint each of the nodes to get them to display correctly, simply
+ * calling repaint on the main element doesn't appear to be enough.
+ */
+ Ext.each([].concat(this.textNodes, this.el.query('th span')), function(el){
+ Ext.fly(el).repaint();
+ });
+ }
+ },
+
+ // private
+ doDisabled : function(disabled){
+ this.keyNav.setDisabled(disabled);
+ this.prevRepeater.setDisabled(disabled);
+ this.nextRepeater.setDisabled(disabled);
+ if(this.showToday){
+ this.todayKeyListener.setDisabled(disabled);
+ this.todayBtn.setDisabled(disabled);
+ }
+ },
+
+ // private
+ onRender : function(container, position){
+ var m = [
+ '',
+ ' ',
+ ''],
+ dn = this.dayNames,
+ i;
+ for(i = 0; i < 7; i++){
+ var d = this.startDay+i;
+ if(d > 6){
+ d = d-7;
+ }
+ m.push('', dn[d].substr(0,1), ' ');
+ }
+ m[m.length] = ' ';
+ for(i = 0; i < 42; i++) {
+ if(i % 7 === 0 && i !== 0){
+ m[m.length] = ' ';
+ }
+ m[m.length] = ' ';
+ }
+ m.push('
',
+ this.showToday ? ' ' : '',
+ '
');
+
+ var el = document.createElement('div');
+ el.className = 'x-date-picker';
+ el.innerHTML = m.join('');
+
+ container.dom.insertBefore(el, position);
+
+ this.el = Ext.get(el);
+ this.eventEl = Ext.get(el.firstChild);
+
+ this.prevRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-left a'), {
+ handler: this.showPrevMonth,
+ scope: this,
+ preventDefault:true,
+ stopDefault:true
+ });
+
+ this.nextRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-right a'), {
+ handler: this.showNextMonth,
+ scope: this,
+ preventDefault:true,
+ stopDefault:true
+ });
+
+ this.monthPicker = this.el.down('div.x-date-mp');
+ this.monthPicker.enableDisplayMode('block');
+
+ this.keyNav = new Ext.KeyNav(this.eventEl, {
+ 'left' : function(e){
+ if(e.ctrlKey){
+ this.showPrevMonth();
+ }else{
+ this.update(this.activeDate.add('d', -1));
+ }
+ },
+
+ 'right' : function(e){
+ if(e.ctrlKey){
+ this.showNextMonth();
+ }else{
+ this.update(this.activeDate.add('d', 1));
+ }
+ },
+
+ 'up' : function(e){
+ if(e.ctrlKey){
+ this.showNextYear();
+ }else{
+ this.update(this.activeDate.add('d', -7));
+ }
+ },
+
+ 'down' : function(e){
+ if(e.ctrlKey){
+ this.showPrevYear();
+ }else{
+ this.update(this.activeDate.add('d', 7));
+ }
+ },
+
+ 'pageUp' : function(e){
+ this.showNextMonth();
+ },
+
+ 'pageDown' : function(e){
+ this.showPrevMonth();
+ },
+
+ 'enter' : function(e){
+ e.stopPropagation();
+ return true;
+ },
+
+ scope : this
+ });
+
+ this.el.unselectable();
+
+ this.cells = this.el.select('table.x-date-inner tbody td');
+ this.textNodes = this.el.query('table.x-date-inner tbody span');
+
+ this.mbtn = new Ext.Button({
+ text: ' ',
+ tooltip: this.monthYearText,
+ renderTo: this.el.child('td.x-date-middle', true)
+ });
+ this.mbtn.el.child('em').addClass('x-btn-arrow');
+
+ if(this.showToday){
+ this.todayKeyListener = this.eventEl.addKeyListener(Ext.EventObject.SPACE, this.selectToday, this);
+ var today = (new Date()).dateFormat(this.format);
+ this.todayBtn = new Ext.Button({
+ renderTo: this.el.child('td.x-date-bottom', true),
+ text: String.format(this.todayText, today),
+ tooltip: String.format(this.todayTip, today),
+ handler: this.selectToday,
+ scope: this
+ });
+ }
+ this.mon(this.eventEl, 'mousewheel', this.handleMouseWheel, this);
+ this.mon(this.eventEl, 'click', this.handleDateClick, this, {delegate: 'a.x-date-date'});
+ this.mon(this.mbtn, 'click', this.showMonthPicker, this);
+ this.onEnable(true);
+ },
+
+ // private
+ createMonthPicker : function(){
+ if(!this.monthPicker.dom.firstChild){
+ var buf = [''];
+ for(var i = 0; i < 6; i++){
+ buf.push(
+ '', Date.getShortMonthName(i), ' ',
+ '', Date.getShortMonthName(i + 6), ' ',
+ i === 0 ?
+ ' ' :
+ ' '
+ );
+ }
+ buf.push(
+ ' ',
+ '
'
+ );
+ this.monthPicker.update(buf.join(''));
+
+ this.mon(this.monthPicker, 'click', this.onMonthClick, this);
+ this.mon(this.monthPicker, 'dblclick', this.onMonthDblClick, this);
+
+ this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
+ this.mpYears = this.monthPicker.select('td.x-date-mp-year');
+
+ this.mpMonths.each(function(m, a, i){
+ i += 1;
+ if((i%2) === 0){
+ m.dom.xmonth = 5 + Math.round(i * 0.5);
+ }else{
+ m.dom.xmonth = Math.round((i-1) * 0.5);
+ }
+ });
+ }
+ },
+
+ // private
+ showMonthPicker : function(){
+ if(!this.disabled){
+ this.createMonthPicker();
+ var size = this.el.getSize();
+ this.monthPicker.setSize(size);
+ this.monthPicker.child('table').setSize(size);
+
+ this.mpSelMonth = (this.activeDate || this.value).getMonth();
+ this.updateMPMonth(this.mpSelMonth);
+ this.mpSelYear = (this.activeDate || this.value).getFullYear();
+ this.updateMPYear(this.mpSelYear);
+
+ this.monthPicker.slideIn('t', {duration:0.2});
+ }
+ },
+
+ // private
+ updateMPYear : function(y){
+ this.mpyear = y;
+ var ys = this.mpYears.elements;
+ for(var i = 1; i <= 10; i++){
+ var td = ys[i-1], y2;
+ if((i%2) === 0){
+ y2 = y + Math.round(i * 0.5);
+ td.firstChild.innerHTML = y2;
+ td.xyear = y2;
+ }else{
+ y2 = y - (5-Math.round(i * 0.5));
+ td.firstChild.innerHTML = y2;
+ td.xyear = y2;
+ }
+ this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
+ }
+ },
+
+ // private
+ updateMPMonth : function(sm){
+ this.mpMonths.each(function(m, a, i){
+ m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
+ });
+ },
+
+ // private
+ selectMPMonth : function(m){
+
+ },
+
+ // private
+ onMonthClick : function(e, t){
+ e.stopEvent();
+ var el = new Ext.Element(t), pn;
+ if(el.is('button.x-date-mp-cancel')){
+ this.hideMonthPicker();
+ }
+ else if(el.is('button.x-date-mp-ok')){
+ var d = new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate());
+ if(d.getMonth() != this.mpSelMonth){
+ // 'fix' the JS rolling date conversion if needed
+ d = new Date(this.mpSelYear, this.mpSelMonth, 1).getLastDateOfMonth();
+ }
+ this.update(d);
+ this.hideMonthPicker();
+ }
+ else if((pn = el.up('td.x-date-mp-month', 2))){
+ this.mpMonths.removeClass('x-date-mp-sel');
+ pn.addClass('x-date-mp-sel');
+ this.mpSelMonth = pn.dom.xmonth;
+ }
+ else if((pn = el.up('td.x-date-mp-year', 2))){
+ this.mpYears.removeClass('x-date-mp-sel');
+ pn.addClass('x-date-mp-sel');
+ this.mpSelYear = pn.dom.xyear;
+ }
+ else if(el.is('a.x-date-mp-prev')){
+ this.updateMPYear(this.mpyear-10);
+ }
+ else if(el.is('a.x-date-mp-next')){
+ this.updateMPYear(this.mpyear+10);
+ }
+ },
+
+ // private
+ onMonthDblClick : function(e, t){
+ e.stopEvent();
+ var el = new Ext.Element(t), pn;
+ if((pn = el.up('td.x-date-mp-month', 2))){
+ this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
+ this.hideMonthPicker();
+ }
+ else if((pn = el.up('td.x-date-mp-year', 2))){
+ this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
+ this.hideMonthPicker();
+ }
+ },
+
+ // private
+ hideMonthPicker : function(disableAnim){
+ if(this.monthPicker){
+ if(disableAnim === true){
+ this.monthPicker.hide();
+ }else{
+ this.monthPicker.slideOut('t', {duration:0.2});
+ }
+ }
+ },
+
+ // private
+ showPrevMonth : function(e){
+ this.update(this.activeDate.add('mo', -1));
+ },
+
+ // private
+ showNextMonth : function(e){
+ this.update(this.activeDate.add('mo', 1));
+ },
+
+ // private
+ showPrevYear : function(){
+ this.update(this.activeDate.add('y', -1));
+ },
+
+ // private
+ showNextYear : function(){
+ this.update(this.activeDate.add('y', 1));
+ },
+
+ // private
+ handleMouseWheel : function(e){
+ e.stopEvent();
+ if(!this.disabled){
+ var delta = e.getWheelDelta();
+ if(delta > 0){
+ this.showPrevMonth();
+ } else if(delta < 0){
+ this.showNextMonth();
+ }
+ }
+ },
+
+ // private
+ handleDateClick : function(e, t){
+ e.stopEvent();
+ if(!this.disabled && t.dateValue && !Ext.fly(t.parentNode).hasClass('x-date-disabled')){
+ this.cancelFocus = this.focusOnSelect === false;
+ this.setValue(new Date(t.dateValue));
+ delete this.cancelFocus;
+ this.fireEvent('select', this, this.value);
+ }
+ },
+
+ // private
+ selectToday : function(){
+ if(this.todayBtn && !this.todayBtn.disabled){
+ this.setValue(new Date().clearTime());
+ this.fireEvent('select', this, this.value);
+ }
+ },
+
+ // private
+ update : function(date, forceRefresh){
+ if(this.rendered){
+ var vd = this.activeDate, vis = this.isVisible();
+ this.activeDate = date;
+ if(!forceRefresh && vd && this.el){
+ var t = date.getTime();
+ if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
+ this.cells.removeClass('x-date-selected');
+ this.cells.each(function(c){
+ if(c.dom.firstChild.dateValue == t){
+ c.addClass('x-date-selected');
+ if(vis && !this.cancelFocus){
+ Ext.fly(c.dom.firstChild).focus(50);
+ }
+ return false;
+ }
+ }, this);
+ return;
+ }
+ }
+ var days = date.getDaysInMonth(),
+ firstOfMonth = date.getFirstDateOfMonth(),
+ startingPos = firstOfMonth.getDay()-this.startDay;
+
+ if(startingPos < 0){
+ startingPos += 7;
+ }
+ days += startingPos;
+
+ var pm = date.add('mo', -1),
+ prevStart = pm.getDaysInMonth()-startingPos,
+ cells = this.cells.elements,
+ textEls = this.textNodes,
+ // convert everything to numbers so it's fast
+ day = 86400000,
+ d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime(),
+ today = new Date().clearTime().getTime(),
+ sel = date.clearTime(true).getTime(),
+ min = this.minDate ? this.minDate.clearTime(true) : Number.NEGATIVE_INFINITY,
+ max = this.maxDate ? this.maxDate.clearTime(true) : Number.POSITIVE_INFINITY,
+ ddMatch = this.disabledDatesRE,
+ ddText = this.disabledDatesText,
+ ddays = this.disabledDays ? this.disabledDays.join('') : false,
+ ddaysText = this.disabledDaysText,
+ format = this.format;
+
+ if(this.showToday){
+ var td = new Date().clearTime(),
+ disable = (td < min || td > max ||
+ (ddMatch && format && ddMatch.test(td.dateFormat(format))) ||
+ (ddays && ddays.indexOf(td.getDay()) != -1));
+
+ if(!this.disabled){
+ this.todayBtn.setDisabled(disable);
+ this.todayKeyListener[disable ? 'disable' : 'enable']();
+ }
+ }
+
+ var setCellClass = function(cal, cell){
+ cell.title = '';
+ var t = d.getTime();
+ cell.firstChild.dateValue = t;
+ if(t == today){
+ cell.className += ' x-date-today';
+ cell.title = cal.todayText;
+ }
+ if(t == sel){
+ cell.className += ' x-date-selected';
+ if(vis){
+ Ext.fly(cell.firstChild).focus(50);
+ }
+ }
+ // disabling
+ if(t < min) {
+ cell.className = ' x-date-disabled';
+ cell.title = cal.minText;
+ return;
+ }
+ if(t > max) {
+ cell.className = ' x-date-disabled';
+ cell.title = cal.maxText;
+ return;
+ }
+ if(ddays){
+ if(ddays.indexOf(d.getDay()) != -1){
+ cell.title = ddaysText;
+ cell.className = ' x-date-disabled';
+ }
+ }
+ if(ddMatch && format){
+ var fvalue = d.dateFormat(format);
+ if(ddMatch.test(fvalue)){
+ cell.title = ddText.replace('%0', fvalue);
+ cell.className = ' x-date-disabled';
+ }
+ }
+ };
+
+ var i = 0;
+ for(; i < startingPos; i++) {
+ textEls[i].innerHTML = (++prevStart);
+ d.setDate(d.getDate()+1);
+ cells[i].className = 'x-date-prevday';
+ setCellClass(this, cells[i]);
+ }
+ for(; i < days; i++){
+ var intDay = i - startingPos + 1;
+ textEls[i].innerHTML = (intDay);
+ d.setDate(d.getDate()+1);
+ cells[i].className = 'x-date-active';
+ setCellClass(this, cells[i]);
+ }
+ var extraDays = 0;
+ for(; i < 42; i++) {
+ textEls[i].innerHTML = (++extraDays);
+ d.setDate(d.getDate()+1);
+ cells[i].className = 'x-date-nextday';
+ setCellClass(this, cells[i]);
+ }
+
+ this.mbtn.setText(this.monthNames[date.getMonth()] + ' ' + date.getFullYear());
+
+ if(!this.internalRender){
+ var main = this.el.dom.firstChild,
+ w = main.offsetWidth;
+ this.el.setWidth(w + this.el.getBorderWidth('lr'));
+ Ext.fly(main).setWidth(w);
+ this.internalRender = true;
+ // opera does not respect the auto grow header center column
+ // then, after it gets a width opera refuses to recalculate
+ // without a second pass
+ if(Ext.isOpera && !this.secondPass){
+ main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + 'px';
+ this.secondPass = true;
+ this.update.defer(10, this, [date]);
+ }
+ }
+ }
+ },
+
+ // private
+ beforeDestroy : function() {
+ if(this.rendered){
+ Ext.destroy(
+ this.keyNav,
+ this.monthPicker,
+ this.eventEl,
+ this.mbtn,
+ this.nextRepeater,
+ this.prevRepeater,
+ this.cells.el,
+ this.todayBtn
+ );
+ delete this.textNodes;
+ delete this.cells.elements;
+ }
+ }
+
+ /**
+ * @cfg {String} autoEl @hide
+ */
+});
+
+Ext.reg('datepicker', Ext.DatePicker);
/**
* @class Ext.LoadMask
* A simple utility class for generically masking elements while loading data. If the {@link #store}
@@ -10762,16 +11113,22 @@ Ext.LoadMask = function(el, config){
this.el = Ext.get(el);
Ext.apply(this, config);
if(this.store){
- this.store.on('beforeload', this.onBeforeLoad, this);
- this.store.on('load', this.onLoad, this);
- this.store.on('exception', this.onLoad, this);
+ this.store.on({
+ scope: this,
+ beforeload: this.onBeforeLoad,
+ load: this.onLoad,
+ exception: this.onLoad
+ });
this.removeMask = Ext.value(this.removeMask, false);
}else{
var um = this.el.getUpdater();
um.showLoadIndicator = false; // disable the default indicator
- um.on('beforeupdate', this.onBeforeLoad, this);
- um.on('update', this.onLoad, this);
- um.on('failure', this.onLoad, this);
+ um.on({
+ scope: this,
+ beforeupdate: this.onBeforeLoad,
+ update: this.onLoad,
+ failure: this.onLoad
+ });
this.removeMask = Ext.value(this.removeMask, true);
}
};
@@ -11015,12 +11372,13 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, {
autoStart: 300
});
this.tracker.initEl(this.thumb);
- this.on('beforedestroy', this.tracker.destroy, this.tracker);
},
// private override
onMouseDown : function(e){
- if(this.disabled) {return;}
+ if(this.disabled){
+ return;
+ }
if(this.clickToChange && e.target != this.thumb.dom){
var local = this.innerEl.translatePoints(e.getXY());
this.onClickChange(local);
@@ -11065,11 +11423,12 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, {
// private
doSnap : function(value){
- if(!this.increment || this.increment == 1 || !value) {
+ if(!(this.increment && value)){
return value;
}
- var newValue = value, inc = this.increment;
- var m = value % inc;
+ var newValue = value,
+ inc = this.increment,
+ m = value % inc;
if(m != 0){
newValue -= m;
if(m * 2 > inc){
@@ -11097,8 +11456,8 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, {
// private
getRatio : function(){
- var w = this.innerEl.getWidth();
- var v = this.maxValue - this.minValue;
+ var w = this.innerEl.getWidth(),
+ v = this.maxValue - this.minValue;
return v == 0 ? w : (w/v);
},
@@ -11131,12 +11490,12 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, {
// private
translateValue : function(v){
var ratio = this.getRatio();
- return (v * ratio)-(this.minValue * ratio)-this.halfThumb;
+ return (v * ratio) - (this.minValue * ratio) - this.halfThumb;
},
reverseValue : function(pos){
var ratio = this.getRatio();
- return (pos+this.halfThumb+(this.minValue * ratio))/ratio;
+ return (pos + this.halfThumb + (this.minValue * ratio)) / ratio;
},
// private
@@ -11212,7 +11571,7 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, {
this.thumb.removeClass(this.disabledClass);
if(Ext.isIE){
this.innerEl.removeClass(this.disabledClass).dom.disabled = false;
- if (this.thumbHolder){
+ if(this.thumbHolder){
this.thumbHolder.hide();
}
this.thumb.show();
@@ -11238,6 +11597,12 @@ Ext.Slider = Ext.extend(Ext.BoxComponent, {
*/
getValue : function(){
return this.value;
+ },
+
+ // private
+ beforeDestroy : function(){
+ Ext.destroyMembers(this, 'endEl', 'innerEl', 'thumb', 'halfThumb', 'focusEl', 'tracker', 'thumbHolder');
+ Ext.Slider.superclass.beforeDestroy.call(this);
}
});
Ext.reg('slider', Ext.Slider);
@@ -11250,8 +11615,8 @@ Ext.Slider.Vertical = {
},
getRatio : function(){
- var h = this.innerEl.getHeight();
- var v = this.maxValue - this.minValue;
+ var h = this.innerEl.getHeight(),
+ v = this.maxValue - this.minValue;
return h/v;
},
@@ -11264,15 +11629,15 @@ Ext.Slider.Vertical = {
},
onDrag: function(e){
- var pos = this.innerEl.translatePoints(this.tracker.getXY());
- var bottom = this.innerEl.getHeight()-pos.top;
+ var pos = this.innerEl.translatePoints(this.tracker.getXY()),
+ bottom = this.innerEl.getHeight()-pos.top;
this.setValue(this.minValue + Ext.util.Format.round(bottom/this.getRatio(), this.decimalPrecision), false);
this.fireEvent('drag', this, e);
},
onClickChange : function(local){
if(local.left > this.clickRange[0] && local.left < this.clickRange[1]){
- var bottom = this.innerEl.getHeight()-local.top;
+ var bottom = this.innerEl.getHeight() - local.top;
this.setValue(this.minValue + Ext.util.Format.round(bottom/this.getRatio(), this.decimalPrecision), undefined, true);
}
}
@@ -11557,6 +11922,16 @@ myAction.on('complete', function(){
this.hide();
}
return this;
+ },
+
+ onDestroy: function(){
+ if(this.rendered){
+ if(this.textEl.isComposite){
+ this.textEl.clear();
+ }
+ Ext.destroyMembers(this, 'textEl', 'progressBar', 'textTopEl');
+ }
+ Ext.ProgressBar.superclass.onDestroy.call(this);
}
});
Ext.reg('progress', Ext.ProgressBar);
\ No newline at end of file