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 * <p>A base class which provides methods common to Panel classes across the Sencha product range.</p>
19 * <p>Please refer to sub class's documentation</p>
21 Ext.define('Ext.panel.AbstractPanel', {
23 /* Begin Definitions */
25 extend: 'Ext.container.Container',
27 requires: ['Ext.util.MixedCollection', 'Ext.core.Element', 'Ext.toolbar.Toolbar'],
32 * @cfg {String} baseCls
33 * The base CSS class to apply to this panel's element (defaults to <code>'x-panel'</code>).
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.
41 * Defaults to <code>undefined</code>.
45 * @cfg {Boolean} bodyBorder
46 * A shortcut to add or remove the border on the body of a panel. This only applies to a panel which has the {@link #frame} configuration set to `true`.
47 * Defaults to <code>undefined</code>.
51 * @cfg {String/Object/Function} bodyStyle
52 * Custom CSS styles to be applied to the panel's body element, which can be supplied as a valid CSS style string,
53 * an object containing style property name/value pairs or a function that returns such a string or object.
54 * For example, these two formats are interpreted to be equivalent:<pre><code>
55 bodyStyle: 'background:#ffc; padding:10px;'
65 * @cfg {String/Array} bodyCls
66 * A CSS class, space-delimited string of classes, or array of classes to be applied to the panel's body element.
67 * The following examples are all valid:<pre><code>
70 bodyCls: ['foo', 'bar']
76 componentLayout: 'dock',
79 * @cfg {Object} defaultDockWeights
80 * This object holds the default weights applied to dockedItems that have no weight. These start with a
81 * weight of 1, to allow negative weights to insert before top items and are odd numbers
82 * so that even weights can be used to get between different dock orders.
84 * To make default docking order match border layout, do this:
86 Ext.panel.AbstractPanel.prototype.defaultDockWeights = { top: 1, bottom: 3, left: 5, right: 7 };</code></pre>
87 * Changing these defaults as above or individually on this object will effect all Panels.
88 * To change the defaults on a single panel, you should replace the entire object:
90 initComponent: function () {
91 // NOTE: Don't change members of defaultDockWeights since the object is shared.
92 this.defaultDockWeights = { top: 1, bottom: 3, left: 5, right: 7 };
97 * To change only one of the default values, you do this:
99 initComponent: function () {
100 // NOTE: Don't change members of defaultDockWeights since the object is shared.
101 this.defaultDockWeights = Ext.applyIf({ top: 10 }, this.defaultDockWeights);
106 defaultDockWeights: { top: 1, left: 3, right: 5, bottom: 7 },
108 renderTpl: ['<div class="{baseCls}-body<tpl if="bodyCls"> {bodyCls}</tpl> {baseCls}-body-{ui}<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl></tpl>"<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>></div>'],
110 // TODO: Move code examples into product-specific files. The code snippet below is Touch only.
112 * @cfg {Object/Array} dockedItems
113 * A component or series of components to be added as docked items to this panel.
114 * The docked items can be docked to either the top, right, left or bottom of a panel.
115 * This is typically used for things like toolbars or tab bars:
117 var panel = new Ext.panel.Panel({
123 text: 'Docked to the top'
131 initComponent : function() {
137 * Fires after the Panel has been resized.
138 * @param {Ext.panel.Panel} p the Panel which has been resized.
139 * @param {Number} width The Panel body's new width.
140 * @param {Number} height The Panel body's new height.
149 Ext.applyIf(me.renderSelectors, {
150 body: '.' + me.baseCls + '-body'
156 if (me.frame && me.border && me.bodyBorder === undefined) {
157 me.bodyBorder = false;
159 if (me.frame && me.border && (me.bodyBorder === false || me.bodyBorder === 0)) {
160 me.manageBodyBorders = true;
167 initItems : function() {
169 items = me.dockedItems;
172 me.dockedItems = Ext.create('Ext.util.MixedCollection', false, me.getComponentId);
179 * Finds a docked component by id, itemId or position. Also see {@link #getDockedItems}
180 * @param {String/Number} comp The id, itemId or position of the docked component (see {@link #getComponent} for details)
181 * @return {Ext.Component} The docked component (if found)
183 getDockedComponent: function(comp) {
184 if (Ext.isObject(comp)) {
185 comp = comp.getItemId();
187 return this.dockedItems.get(comp);
191 * Attempts a default component lookup (see {@link Ext.container.Container#getComponent}). If the component is not found in the normal
192 * items, the dockedItems are searched and the matched component (if any) returned (see {@loink #getDockedComponent}). Note that docked
193 * items will only be matched by component id or itemId -- if you pass a numeric index only non-docked child components will be searched.
194 * @param {String/Number} comp The component id, itemId or position to find
195 * @return {Ext.Component} The component (if found)
197 getComponent: function(comp) {
198 var component = this.callParent(arguments);
199 if (component === undefined && !Ext.isNumber(comp)) {
200 // If the arg is a numeric index skip docked items
201 component = this.getDockedComponent(comp);
207 * Parses the {@link bodyStyle} config if available to create a style string that will be applied to the body element.
208 * This also includes {@link bodyPadding} and {@link bodyBorder} if available.
209 * @return {String} A CSS style string with body styles, padding and border.
212 initBodyStyles: function() {
214 bodyStyle = me.bodyStyle,
216 Element = Ext.core.Element,
219 if (Ext.isFunction(bodyStyle)) {
220 bodyStyle = bodyStyle();
222 if (Ext.isString(bodyStyle)) {
223 styles = bodyStyle.split(';');
225 for (prop in bodyStyle) {
226 if (bodyStyle.hasOwnProperty(prop)) {
227 styles.push(prop + ':' + bodyStyle[prop]);
232 if (me.bodyPadding !== undefined) {
233 styles.push('padding: ' + Element.unitizeBox((me.bodyPadding === true) ? 5 : me.bodyPadding));
235 if (me.frame && me.bodyBorder) {
236 if (!Ext.isNumber(me.bodyBorder)) {
239 styles.push('border-width: ' + Element.unitizeBox(me.bodyBorder));
242 return styles.length ? styles.join(';') : undefined;
246 * Parse the {@link bodyCls} config if available to create a comma-delimited string of
247 * CSS classes to be applied to the body element.
248 * @return {String} The CSS class(es)
251 initBodyCls: function() {
254 bodyCls = me.bodyCls;
257 Ext.each(bodyCls, function(v) {
262 return cls.length > 0 ? cls : undefined;
266 * Initialized the renderData to be used when rendering the renderTpl.
267 * @return {Object} Object with keys and values that are going to be applied to the renderTpl
270 initRenderData: function() {
271 return Ext.applyIf(this.callParent(), {
272 bodyStyle: this.initBodyStyles(),
273 bodyCls: this.initBodyCls()
278 * Adds docked item(s) to the panel.
279 * @param {Object/Array} component The Component or array of components to add. The components
280 * must include a 'dock' parameter on each component to indicate where it should be docked ('top', 'right',
282 * @param {Number} pos (optional) The index at which the Component will be added
284 addDocked : function(items, pos) {
289 items = me.prepareItems(items);
290 length = items.length;
292 for (; i < length; i++) {
294 item.dock = item.dock || 'top';
296 // Allow older browsers to target docked items to style without borders
297 if (me.border === false) {
298 // item.cls = item.cls || '' + ' ' + me.baseCls + '-noborder-docked-' + item.dock;
301 if (pos !== undefined) {
302 me.dockedItems.insert(pos + i, item);
305 me.dockedItems.add(item);
308 me.onDockedAdd(item);
311 // Set flag which means that beforeLayout will not veto the layout due to the size not changing
312 me.componentLayout.childrenChanged = true;
313 if (me.rendered && !me.suspendLayout) {
314 me.doComponentLayout();
319 // Placeholder empty functions
320 onDockedAdd : Ext.emptyFn,
321 onDockedRemove : Ext.emptyFn,
324 * Inserts docked item(s) to the panel at the indicated position.
325 * @param {Number} pos The index at which the Component will be inserted
326 * @param {Object/Array} component. The Component or array of components to add. The components
327 * must include a 'dock' paramater on each component to indicate where it should be docked ('top', 'right',
330 insertDocked : function(pos, items) {
331 this.addDocked(items, pos);
335 * Removes the docked item from the panel.
336 * @param {Ext.Component} item. The Component to remove.
337 * @param {Boolean} autoDestroy (optional) Destroy the component after removal.
339 removeDocked : function(item, autoDestroy) {
344 if (!me.dockedItems.contains(item)) {
348 layout = me.componentLayout;
349 hasLayout = layout && me.rendered;
352 layout.onRemove(item);
355 me.dockedItems.remove(item);
357 me.onDockedRemove(item);
359 if (autoDestroy === true || (autoDestroy !== false && me.autoDestroy)) {
363 if (hasLayout && !autoDestroy) {
364 layout.afterRemove(item);
368 // Set flag which means that beforeLayout will not veto the layout due to the size not changing
369 me.componentLayout.childrenChanged = true;
370 if (!me.destroying && !me.suspendLayout) {
371 me.doComponentLayout();
378 * Retrieve an array of all currently docked Components.
379 * @param {String} cqSelector A {@link Ext.ComponentQuery ComponentQuery} selector string to filter the returned items.
380 * @return {Array} An array of components.
382 getDockedItems : function(cqSelector) {
384 defaultWeight = me.defaultDockWeights,
387 if (me.dockedItems && me.dockedItems.items.length) {
388 // Allow filtering of returned docked items by CQ selector.
390 dockedItems = Ext.ComponentQuery.query(cqSelector, me.dockedItems.items);
392 dockedItems = me.dockedItems.items.slice();
395 Ext.Array.sort(dockedItems, function(a, b) {
396 // Docked items are ordered by their visual representation by default (t,l,r,b)
397 var aw = a.weight || defaultWeight[a.dock],
398 bw = b.weight || defaultWeight[b.dock];
399 if (Ext.isNumber(aw) && Ext.isNumber(bw)) {
411 addUIClsToElement: function(cls, force) {
413 result = me.callParent(arguments),
414 classes = [Ext.baseCSSPrefix + cls, me.baseCls + '-body-' + cls, me.baseCls + '-body-' + me.ui + '-' + cls],
417 if (!force && me.rendered) {
419 me.body.addCls(me.bodyCls);
421 me.body.addCls(classes);
425 array = me.bodyCls.split(' ');
427 for (i = 0; i < classes.length; i++) {
428 if (!Ext.Array.contains(array, classes[i])) {
429 array.push(classes[i]);
433 me.bodyCls = array.join(' ');
435 me.bodyCls = classes.join(' ');
443 removeUIClsFromElement: function(cls, force) {
445 result = me.callParent(arguments),
446 classes = [Ext.baseCSSPrefix + cls, me.baseCls + '-body-' + cls, me.baseCls + '-body-' + me.ui + '-' + cls],
449 if (!force && me.rendered) {
451 me.body.removeCls(me.bodyCls);
453 me.body.removeCls(classes);
457 array = me.bodyCls.split(' ');
459 for (i = 0; i < classes.length; i++) {
460 Ext.Array.remove(array, classes[i]);
463 me.bodyCls = array.join(' ');
471 addUIToElement: function(force) {
473 cls = me.baseCls + '-body-' + me.ui,
476 me.callParent(arguments);
478 if (!force && me.rendered) {
480 me.body.addCls(me.bodyCls);
486 array = me.bodyCls.split(' ');
488 if (!Ext.Array.contains(array, cls)) {
492 me.bodyCls = array.join(' ');
500 removeUIFromElement: function() {
502 cls = me.baseCls + '-body-' + me.ui,
505 me.callParent(arguments);
509 me.body.removeCls(me.bodyCls);
511 me.body.removeCls(cls);
515 array = me.bodyCls.split(' ');
516 Ext.Array.remove(array, cls);
517 me.bodyCls = array.join(' ');
525 getTargetEl : function() {
529 getRefItems: function(deep) {
530 var items = this.callParent(arguments),
531 // deep fetches all docked items, and their descendants using '*' selector and then '* *'
532 dockedItems = this.getDockedItems(deep ? '*,* *' : undefined),
533 ln = dockedItems.length,
537 // Find the index where we go from top/left docked items to right/bottom docked items
538 for (; i < ln; i++) {
539 item = dockedItems[i];
540 if (item.dock === 'right' || item.dock === 'bottom') {
545 // Return docked items in the top/left position before our container items, and
546 // return right/bottom positioned items after our container items.
547 // See AbstractDock.renderItems() for more information.
548 return Ext.Array.splice(dockedItems, 0, i).concat(items).concat(dockedItems);
551 beforeDestroy: function(){
552 var docked = this.dockedItems,
556 while ((c = docked.first())) {
557 this.removeDocked(c, true);
563 setBorder: function(border) {
565 me.border = (border !== undefined) ? border : true;
567 me.doComponentLayout();