3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.panel.AbstractPanel
17 * @extends Ext.container.Container
18 * A base class which provides methods common to Panel classes across the Sencha product range.
21 Ext.define('Ext.panel.AbstractPanel', {
23 /* Begin Definitions */
25 extend: 'Ext.container.Container',
27 requires: ['Ext.util.MixedCollection', 'Ext.Element', 'Ext.toolbar.Toolbar'],
32 * @cfg {String} [baseCls='x-panel']
33 * The base CSS class to apply to this panel's element.
35 baseCls : Ext.baseCSSPrefix + 'panel',
38 * @cfg {Number/String} bodyPadding
39 * A shortcut for setting a padding style on the body element. The value can either be
40 * a number to be applied to all sides, or a normal css string describing padding.
44 * @cfg {Boolean} bodyBorder
45 * A shortcut to add or remove the border on the body of a panel. This only applies to a panel
46 * which has the {@link #frame} configuration set to `true`.
50 * @cfg {String/Object/Function} bodyStyle
51 * Custom CSS styles to be applied to the panel's body element, which can be supplied as a valid CSS style string,
52 * an object containing style property name/value pairs or a function that returns such a string or object.
53 * For example, these two formats are interpreted to be equivalent:<pre><code>
54 bodyStyle: 'background:#ffc; padding:10px;'
64 * @cfg {String/String[]} bodyCls
65 * A CSS class, space-delimited string of classes, or array of classes to be applied to the panel's body element.
66 * The following examples are all valid:<pre><code>
69 bodyCls: ['foo', 'bar']
75 componentLayout: 'dock',
78 * @cfg {Object} defaultDockWeights
79 * This object holds the default weights applied to dockedItems that have no weight. These start with a
80 * weight of 1, to allow negative weights to insert before top items and are odd numbers
81 * so that even weights can be used to get between different dock orders.
83 * To make default docking order match border layout, do this:
85 Ext.panel.AbstractPanel.prototype.defaultDockWeights = { top: 1, bottom: 3, left: 5, right: 7 };</code></pre>
86 * Changing these defaults as above or individually on this object will effect all Panels.
87 * To change the defaults on a single panel, you should replace the entire object:
89 initComponent: function () {
90 // NOTE: Don't change members of defaultDockWeights since the object is shared.
91 this.defaultDockWeights = { top: 1, bottom: 3, left: 5, right: 7 };
96 * To change only one of the default values, you do this:
98 initComponent: function () {
99 // NOTE: Don't change members of defaultDockWeights since the object is shared.
100 this.defaultDockWeights = Ext.applyIf({ top: 10 }, this.defaultDockWeights);
105 defaultDockWeights: { top: 1, left: 3, right: 5, bottom: 7 },
108 '<div id="{id}-body" class="{baseCls}-body<tpl if="bodyCls"> {bodyCls}</tpl>',
109 ' {baseCls}-body-{ui}<tpl if="uiCls">',
110 '<tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl>',
111 '</tpl>"<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>>',
115 // TODO: Move code examples into product-specific files. The code snippet below is Touch only.
117 * @cfg {Object/Object[]} dockedItems
118 * A component or series of components to be added as docked items to this panel.
119 * The docked items can be docked to either the top, right, left or bottom of a panel.
120 * This is typically used for things like toolbars or tab bars:
122 var panel = new Ext.panel.Panel({
128 text: 'Docked to the top'
136 initComponent : function() {
142 * Fires after the Panel has been resized.
143 * @param {Ext.panel.Panel} p the Panel which has been resized.
144 * @param {Number} width The Panel body's new width.
145 * @param {Number} height The Panel body's new height.
154 me.addChildEls('body');
159 if (me.frame && me.border && me.bodyBorder === undefined) {
160 me.bodyBorder = false;
162 if (me.frame && me.border && (me.bodyBorder === false || me.bodyBorder === 0)) {
163 me.manageBodyBorders = true;
170 initItems : function() {
172 items = me.dockedItems;
175 me.dockedItems = Ext.create('Ext.util.MixedCollection', false, me.getComponentId);
182 * Finds a docked component by id, itemId or position. Also see {@link #getDockedItems}
183 * @param {String/Number} comp The id, itemId or position of the docked component (see {@link #getComponent} for details)
184 * @return {Ext.Component} The docked component (if found)
186 getDockedComponent: function(comp) {
187 if (Ext.isObject(comp)) {
188 comp = comp.getItemId();
190 return this.dockedItems.get(comp);
194 * Attempts a default component lookup (see {@link Ext.container.Container#getComponent}). If the component is not found in the normal
195 * items, the dockedItems are searched and the matched component (if any) returned (see {@link #getDockedComponent}). Note that docked
196 * items will only be matched by component id or itemId -- if you pass a numeric index only non-docked child components will be searched.
197 * @param {String/Number} comp The component id, itemId or position to find
198 * @return {Ext.Component} The component (if found)
200 getComponent: function(comp) {
201 var component = this.callParent(arguments);
202 if (component === undefined && !Ext.isNumber(comp)) {
203 // If the arg is a numeric index skip docked items
204 component = this.getDockedComponent(comp);
210 * Parses the {@link bodyStyle} config if available to create a style string that will be applied to the body element.
211 * This also includes {@link bodyPadding} and {@link bodyBorder} if available.
212 * @return {String} A CSS style string with body styles, padding and border.
215 initBodyStyles: function() {
217 bodyStyle = me.bodyStyle,
219 Element = Ext.Element,
222 if (Ext.isFunction(bodyStyle)) {
223 bodyStyle = bodyStyle();
225 if (Ext.isString(bodyStyle)) {
226 styles = bodyStyle.split(';');
228 for (prop in bodyStyle) {
229 if (bodyStyle.hasOwnProperty(prop)) {
230 styles.push(prop + ':' + bodyStyle[prop]);
235 if (me.bodyPadding !== undefined) {
236 styles.push('padding: ' + Element.unitizeBox((me.bodyPadding === true) ? 5 : me.bodyPadding));
238 if (me.frame && me.bodyBorder) {
239 if (!Ext.isNumber(me.bodyBorder)) {
242 styles.push('border-width: ' + Element.unitizeBox(me.bodyBorder));
245 return styles.length ? styles.join(';') : undefined;
249 * Parse the {@link bodyCls} config if available to create a comma-delimited string of
250 * CSS classes to be applied to the body element.
251 * @return {String} The CSS class(es)
254 initBodyCls: function() {
257 bodyCls = me.bodyCls;
260 Ext.each(bodyCls, function(v) {
265 return cls.length > 0 ? cls : undefined;
269 * Initialized the renderData to be used when rendering the renderTpl.
270 * @return {Object} Object with keys and values that are going to be applied to the renderTpl
273 initRenderData: function() {
274 return Ext.applyIf(this.callParent(), {
275 bodyStyle: this.initBodyStyles(),
276 bodyCls: this.initBodyCls()
281 * Adds docked item(s) to the panel.
282 * @param {Object/Object[]} component The Component or array of components to add. The components
283 * must include a 'dock' parameter on each component to indicate where it should be docked ('top', 'right',
285 * @param {Number} pos (optional) The index at which the Component will be added
287 addDocked : function(items, pos) {
292 items = me.prepareItems(items);
293 length = items.length;
295 for (; i < length; i++) {
297 item.dock = item.dock || 'top';
299 // Allow older browsers to target docked items to style without borders
300 if (me.border === false) {
301 // item.cls = item.cls || '' + ' ' + me.baseCls + '-noborder-docked-' + item.dock;
304 if (pos !== undefined) {
305 me.dockedItems.insert(pos + i, item);
308 me.dockedItems.add(item);
311 me.onDockedAdd(item);
314 // Set flag which means that beforeLayout will not veto the layout due to the size not changing
315 me.componentLayout.childrenChanged = true;
316 if (me.rendered && !me.suspendLayout) {
317 me.doComponentLayout();
322 // Placeholder empty functions
323 onDockedAdd : Ext.emptyFn,
324 onDockedRemove : Ext.emptyFn,
327 * Inserts docked item(s) to the panel at the indicated position.
328 * @param {Number} pos The index at which the Component will be inserted
329 * @param {Object/Object[]} component. The Component or array of components to add. The components
330 * must include a 'dock' paramater on each component to indicate where it should be docked ('top', 'right',
333 insertDocked : function(pos, items) {
334 this.addDocked(items, pos);
338 * Removes the docked item from the panel.
339 * @param {Ext.Component} item. The Component to remove.
340 * @param {Boolean} autoDestroy (optional) Destroy the component after removal.
342 removeDocked : function(item, autoDestroy) {
347 if (!me.dockedItems.contains(item)) {
351 layout = me.componentLayout;
352 hasLayout = layout && me.rendered;
355 layout.onRemove(item);
358 me.dockedItems.remove(item);
360 me.onDockedRemove(item);
362 if (autoDestroy === true || (autoDestroy !== false && me.autoDestroy)) {
364 } else if (hasLayout) {
365 // not destroying, make any layout related removals
366 layout.afterRemove(item);
370 // Set flag which means that beforeLayout will not veto the layout due to the size not changing
371 me.componentLayout.childrenChanged = true;
372 if (!me.destroying && !me.suspendLayout) {
373 me.doComponentLayout();
380 * Retrieve an array of all currently docked Components.
381 * @param {String} cqSelector A {@link Ext.ComponentQuery ComponentQuery} selector string to filter the returned items.
382 * @return {Ext.Component[]} An array of components.
384 getDockedItems : function(cqSelector) {
386 defaultWeight = me.defaultDockWeights,
389 if (me.dockedItems && me.dockedItems.items.length) {
390 // Allow filtering of returned docked items by CQ selector.
392 dockedItems = Ext.ComponentQuery.query(cqSelector, me.dockedItems.items);
394 dockedItems = me.dockedItems.items.slice();
397 Ext.Array.sort(dockedItems, function(a, b) {
398 // Docked items are ordered by their visual representation by default (t,l,r,b)
399 var aw = a.weight || defaultWeight[a.dock],
400 bw = b.weight || defaultWeight[b.dock];
401 if (Ext.isNumber(aw) && Ext.isNumber(bw)) {
413 addUIClsToElement: function(cls, force) {
415 result = me.callParent(arguments),
416 classes = [Ext.baseCSSPrefix + cls, me.baseCls + '-body-' + cls, me.baseCls + '-body-' + me.ui + '-' + cls],
419 if (!force && me.rendered) {
421 me.body.addCls(me.bodyCls);
423 me.body.addCls(classes);
427 array = me.bodyCls.split(' ');
429 for (i = 0; i < classes.length; i++) {
430 if (!Ext.Array.contains(array, classes[i])) {
431 array.push(classes[i]);
435 me.bodyCls = array.join(' ');
437 me.bodyCls = classes.join(' ');
445 removeUIClsFromElement: function(cls, force) {
447 result = me.callParent(arguments),
448 classes = [Ext.baseCSSPrefix + cls, me.baseCls + '-body-' + cls, me.baseCls + '-body-' + me.ui + '-' + cls],
451 if (!force && me.rendered) {
453 me.body.removeCls(me.bodyCls);
455 me.body.removeCls(classes);
459 array = me.bodyCls.split(' ');
461 for (i = 0; i < classes.length; i++) {
462 Ext.Array.remove(array, classes[i]);
465 me.bodyCls = array.join(' ');
473 addUIToElement: function(force) {
475 cls = me.baseCls + '-body-' + me.ui,
478 me.callParent(arguments);
480 if (!force && me.rendered) {
482 me.body.addCls(me.bodyCls);
488 array = me.bodyCls.split(' ');
490 if (!Ext.Array.contains(array, cls)) {
494 me.bodyCls = array.join(' ');
502 removeUIFromElement: function() {
504 cls = me.baseCls + '-body-' + me.ui,
507 me.callParent(arguments);
511 me.body.removeCls(me.bodyCls);
513 me.body.removeCls(cls);
517 array = me.bodyCls.split(' ');
518 Ext.Array.remove(array, cls);
519 me.bodyCls = array.join(' ');
527 getTargetEl : function() {
531 getRefItems: function(deep) {
532 var items = this.callParent(arguments),
533 // deep fetches all docked items, and their descendants using '*' selector and then '* *'
534 dockedItems = this.getDockedItems(deep ? '*,* *' : undefined),
535 ln = dockedItems.length,
539 // Find the index where we go from top/left docked items to right/bottom docked items
540 for (; i < ln; i++) {
541 item = dockedItems[i];
542 if (item.dock === 'right' || item.dock === 'bottom') {
547 // Return docked items in the top/left position before our container items, and
548 // return right/bottom positioned items after our container items.
549 // See AbstractDock.renderItems() for more information.
550 return Ext.Array.splice(dockedItems, 0, i).concat(items).concat(dockedItems);
553 beforeDestroy: function(){
554 var docked = this.dockedItems,
558 while ((c = docked.first())) {
559 this.removeDocked(c, true);
565 setBorder: function(border) {
567 me.border = (border !== undefined) ? border : true;
569 me.doComponentLayout();