-<!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-grid.header.Container'>/**
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title>The source code</title>
+ <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
+ <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
+ <style type="text/css">
+ .highlight { display: block; background-color: #ddd; }
+ </style>
+ <script type="text/javascript">
+ function highlight() {
+ document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
+ }
+ </script>
+</head>
+<body onload="prettyPrint(); highlight();">
+ <pre class="prettyprint lang-js"><span id='Ext-grid-header-Container'>/**
</span> * @class Ext.grid.header.Container
* @extends Ext.container.Container
- * @private
*
* Container which holds headers and is docked at the top or bottom of a TablePanel.
* The HeaderContainer drives resizing/moving/hiding of columns within the TableView.
* As headers are hidden, moved or resized the headercontainer is responsible for
* triggering changes within the view.
- *
- * @xtype headercontainer
*/
Ext.define('Ext.grid.header.Container', {
extend: 'Ext.container.Container',
baseCls: Ext.baseCSSPrefix + 'grid-header-ct',
dock: 'top',
-<span id='Ext-grid.header.Container-cfg-weight'> /**
+<span id='Ext-grid-header-Container-cfg-weight'> /**
</span> * @cfg {Number} weight
* HeaderContainer overrides the default weight of 0 for all docked items to 100.
* This is so that it has more priority over things like toolbars.
*/
weight: 100,
defaultType: 'gridcolumn',
-<span id='Ext-grid.header.Container-cfg-defaultWidth'> /**
+<span id='Ext-grid-header-Container-cfg-defaultWidth'> /**
</span> * @cfg {Number} defaultWidth
* Width of the header if no width or flex is specified. Defaults to 100.
*/
dragging: false,
-<span id='Ext-grid.header.Container-property-isGroupHeader'> /**
+<span id='Ext-grid-header-Container-property-isGroupHeader'> /**
</span> * <code>true</code> if this HeaderContainer is in fact a group header which contains sub headers.
* @type Boolean
* @property isGroupHeader
*/
-<span id='Ext-grid.header.Container-cfg-sortable'> /**
+<span id='Ext-grid-header-Container-cfg-sortable'> /**
</span> * @cfg {Boolean} sortable
* Provides the default sortable state for all Headers within this HeaderContainer.
* Also turns on or off the menus in the HeaderContainer. Note that the menu is
* items for every header.
*/
sortable: true,
-
+
initComponent: function() {
var me = this;
-
+
me.headerCounter = 0;
me.plugins = me.plugins || [];
me.reorderer = Ext.create('Ext.grid.plugin.HeaderReorderer');
if (!me.enableColumnResize) {
me.resizer.disable();
- }
+ }
if (!me.enableColumnMove) {
me.reorderer.disable();
}
});
me.callParent();
me.addEvents(
-<span id='Ext-grid.header.Container-event-columnresize'> /**
+<span id='Ext-grid-header-Container-event-columnresize'> /**
</span> * @event columnresize
* @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
* @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
*/
'columnresize',
-<span id='Ext-grid.header.Container-event-headerclick'> /**
+<span id='Ext-grid-header-Container-event-headerclick'> /**
</span> * @event headerclick
* @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
* @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
*/
'headerclick',
-<span id='Ext-grid.header.Container-event-headertriggerclick'> /**
+<span id='Ext-grid-header-Container-event-headertriggerclick'> /**
</span> * @event headertriggerclick
* @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
* @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
*/
'headertriggerclick',
-<span id='Ext-grid.header.Container-event-columnmove'> /**
+<span id='Ext-grid-header-Container-event-columnmove'> /**
</span> * @event columnmove
* @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
* @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
* @param {Number} toIdx
*/
'columnmove',
-<span id='Ext-grid.header.Container-event-columnhide'> /**
+<span id='Ext-grid-header-Container-event-columnhide'> /**
</span> * @event columnhide
* @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
* @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
*/
'columnhide',
-<span id='Ext-grid.header.Container-event-columnshow'> /**
+<span id='Ext-grid-header-Container-event-columnshow'> /**
</span> * @event columnshow
* @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
* @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
*/
'columnshow',
-<span id='Ext-grid.header.Container-event-sortchange'> /**
+<span id='Ext-grid-header-Container-event-sortchange'> /**
</span> * @event sortchange
* @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
* @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
* @param {String} direction
*/
'sortchange',
-<span id='Ext-grid.header.Container-event-menucreate'> /**
+<span id='Ext-grid-header-Container-event-menucreate'> /**
</span> * @event menucreate
* Fired immediately after the column header menu is created.
* @param {Ext.grid.header.Container} ct This instance
Ext.destroy(this.resizer, this.reorderer);
this.callParent();
},
+
+ applyDefaults: function(config){
+ /*
+ * Ensure header.Container defaults don't get applied to a RowNumberer
+ * if an xtype is supplied. This isn't an ideal solution however it's
+ * much more likely that a RowNumberer with no options will be created,
+ * wanting to use the defaults specified on the class as opposed to
+ * those setup on the Container.
+ */
+ if (config && !config.isComponent && config.xtype == 'rownumberer') {
+ return config;
+ }
+ return this.callParent([config]);
+ },
+
+ applyColumnsState: function(columns) {
+ if (!columns || !columns.length) {
+ return;
+ }
+
+ var me = this,
+ i = 0,
+ index,
+ col;
+
+ Ext.each(columns, function (columnState) {
+ col = me.down('gridcolumn[headerId=' + columnState.id + ']');
+ if (col) {
+ index = me.items.indexOf(col);
+ if (i !== index) {
+ me.moveHeader(index, i);
+ }
+
+ if (col.applyColumnState) {
+ col.applyColumnState(columnState);
+ }
+ ++i;
+ }
+ });
+ },
+
+ getColumnsState: function () {
+ var me = this,
+ columns = [],
+ state;
+
+ me.items.each(function (col) {
+ state = col.getColumnState && col.getColumnState();
+ if (state) {
+ columns.push(state);
+ }
+ });
+
+ return columns;
+ },
// Invalidate column cache on add
// We cannot refresh the View on every add because this method is called
onAdd: function(c) {
var me = this;
if (!c.headerId) {
- c.headerId = 'h' + (++me.headerCounter);
+ c.headerId = c.initialConfig.id || ('h' + (++me.headerCounter));
+ }
+ //<debug warn>
+ if (Ext.global.console && Ext.global.console.warn) {
+ if (!me._usedIDs) me._usedIDs = {};
+ if (me._usedIDs[c.headerId]) {
+ Ext.global.console.warn(this.$className, 'attempted to reuse an existing id', c.headerId);
+ }
+ me._usedIDs[c.headerId] = true;
}
+ //</debug>
me.callParent(arguments);
me.purgeCache();
},
if (!this.isHeader) {
var me = this,
topHeaders = me.query('>gridcolumn:not([hidden])'),
- viewEl;
+ viewEl,
+ firstHeaderEl,
+ lastHeaderEl;
me.callParent(arguments);
if (topHeaders.length) {
- topHeaders[0].el.radioCls(me.firstHeaderCls);
- topHeaders[topHeaders.length - 1].el.radioCls(me.lastHeaderCls);
+ firstHeaderEl = topHeaders[0].el;
+ if (firstHeaderEl !== me.pastFirstHeaderEl) {
+ if (me.pastFirstHeaderEl) {
+ me.pastFirstHeaderEl.removeCls(me.firstHeaderCls);
+ }
+ firstHeaderEl.addCls(me.firstHeaderCls);
+ me.pastFirstHeaderEl = firstHeaderEl;
+ }
+
+ lastHeaderEl = topHeaders[topHeaders.length - 1].el;
+ if (lastHeaderEl !== me.pastLastHeaderEl) {
+ if (me.pastLastHeaderEl) {
+ me.pastLastHeaderEl.removeCls(me.lastHeaderCls);
+ }
+ lastHeaderEl.addCls(me.lastHeaderCls);
+ me.pastLastHeaderEl = lastHeaderEl;
+ }
}
}
+
},
- onHeaderShow: function(header) {
+ onHeaderShow: function(header, preventLayout) {
// Pass up to the GridSection
var me = this,
gridSection = me.ownerCt,
me.fireEvent('columnshow', me, header);
// The header's own hide suppresses cascading layouts, so lay the headers out now
- me.doLayout();
+ if (preventLayout !== true) {
+ me.doLayout();
+ }
+ },
+
+ doComponentLayout: function(){
+ var me = this;
+ if (me.view && me.view.saveScrollState) {
+ me.view.saveScrollState();
+ }
+ me.callParent(arguments);
+ if (me.view && me.view.restoreScrollState) {
+ me.view.restoreScrollState();
+ }
},
onHeaderHide: function(header, suppressLayout) {
for (i = 0; i < len; i++) {
itemToDisable = itemsToDisable[i];
if (!Ext.Array.contains(me.disabledMenuItems, itemToDisable)) {
+
+ // If we only want to disable check change: it might be a disabled item, so enable it prior to
+ // setting its correct disablement level.
+ itemToDisable.disabled = false;
itemToDisable[itemToDisable.menu ? 'disableCheckChange' : 'disable']();
me.disabledMenuItems.push(itemToDisable);
}
}
},
-<span id='Ext-grid.header.Container-method-tempLock'> /**
+<span id='Ext-grid-header-Container-method-tempLock'> /**
</span> * Temporarily lock the headerCt. This makes it so that clicking on headers
* don't trigger actions like sorting or opening of the header menu. This is
* done because extraneous events may be fired on the headers after interacting
if (this.view && this.view.rendered) {
this.view.onHeaderResize(header, w, suppressFocus);
}
- this.fireEvent('columnresize', this, header, w);
},
onHeaderClick: function(header, e, t) {
var me = this;
// Delete column cache - column order has changed.
delete me.gridDataColumns;
+ delete me.hideableColumns;
// Menu changes when columns are moved. It will be recreated.
if (me.menu) {
var me = this,
gridSection = me.ownerCt;
- if (gridSection) {
+ if (gridSection && gridSection.onHeaderMove) {
gridSection.onHeaderMove(me, header, fromIdx, toIdx);
}
me.fireEvent("columnmove", me, header, fromIdx, toIdx);
},
-<span id='Ext-grid.header.Container-method-getMenu'> /**
+<span id='Ext-grid-header-Container-method-getMenu'> /**
</span> * Gets the menu (and will create it if it doesn't already exist)
* @private
*/
if (!me.menu) {
me.menu = Ext.create('Ext.menu.Menu', {
+ hideOnParentHide: false, // Persists when owning ColumnHeader is hidden
items: me.getMenuItems(),
listeners: {
deactivate: me.onMenuDeactivate,
return me.menu;
},
-<span id='Ext-grid.header.Container-method-getMenuItems'> /**
+<span id='Ext-grid-header-Container-method-getMenuItems'> /**
</span> * Returns an array of menu items to be placed into the shared menu
* across all headers in this header container.
* @returns {Array} menuItems
*/
getMenuItems: function() {
var me = this,
- menuItems = [{
- itemId: 'columnItem',
- text: me.columnsText,
- cls: Ext.baseCSSPrefix + 'cols-icon',
- menu: me.getColumnMenu(me)
- }];
+ menuItems = [],
+ hideableColumns = me.enableColumnHide ? me.getColumnMenu(me) : null;
if (me.sortable) {
- menuItems.unshift({
+ menuItems = [{
itemId: 'ascItem',
text: me.sortAscText,
- cls: 'xg-hmenu-sort-asc',
+ cls: Ext.baseCSSPrefix + 'hmenu-sort-asc',
handler: me.onSortAscClick,
scope: me
},{
itemId: 'descItem',
text: me.sortDescText,
- cls: 'xg-hmenu-sort-desc',
+ cls: Ext.baseCSSPrefix + 'hmenu-sort-desc',
handler: me.onSortDescClick,
scope: me
- },'-');
+ }];
+ }
+ if (hideableColumns && hideableColumns.length) {
+ menuItems.push('-', {
+ itemId: 'columnItem',
+ text: me.columnsText,
+ cls: Ext.baseCSSPrefix + 'cols-icon',
+ menu: hideableColumns
+ });
}
return menuItems;
},
activeHeader.setSortState('DESC');
},
-<span id='Ext-grid.header.Container-method-getColumnMenu'> /**
+<span id='Ext-grid-header-Container-method-getColumnMenu'> /**
</span> * Returns an array of menu CheckItems corresponding to all immediate children of the passed Container which have been configured as hideable.
*/
getColumnMenu: function(headerContainer) {
header[checked ? 'show' : 'hide']();
},
-<span id='Ext-grid.header.Container-method-getColumnsForTpl'> /**
+<span id='Ext-grid-header-Container-method-getColumnsForTpl'> /**
</span> * Get the columns used for generating a template via TableChunker.
* Returns an array of all columns and their
* - dataIndex
headers = this.getGridColumns(flushCache),
headersLn = headers.length,
i = 0,
- header;
+ header,
+ width;
for (; i < headersLn; i++) {
header = headers[i];
+
+ if (header.hidden || header.up('headercontainer[hidden=true]')) {
+ width = 0;
+ } else {
+ width = header.getDesiredWidth();
+ // IE6 and IE7 bug.
+ // Setting the width of the first TD does not work - ends up with a 1 pixel discrepancy.
+ // We need to increment the passed with in this case.
+ if ((i === 0) && (Ext.isIE6 || Ext.isIE7)) {
+ width += 1;
+ }
+ }
cols.push({
dataIndex: header.dataIndex,
align: header.align,
- width: header.hidden ? 0 : header.getDesiredWidth(),
+ width: width,
id: header.id,
cls: header.tdCls,
columnId: header.getItemId()
return cols;
},
-<span id='Ext-grid.header.Container-method-getColumnCount'> /**
+<span id='Ext-grid-header-Container-method-getColumnCount'> /**
</span> * Returns the number of <b>grid columns</b> descended from this HeaderContainer.
* Group Columns are HeaderContainers. All grid columns are returned, including hidden ones.
*/
return this.getGridColumns().length;
},
-<span id='Ext-grid.header.Container-method-getFullWidth'> /**
+<span id='Ext-grid-header-Container-method-getFullWidth'> /**
</span> * Gets the full width of all columns that are visible.
*/
getFullWidth: function(flushCache) {
}
},
-<span id='Ext-grid.header.Container-method-getVisibleGridColumns'> /**
-</span> * Returns an array of the <b>visible<b> columns in the grid. This goes down to the lowest column header
+<span id='Ext-grid-header-Container-method-getVisibleGridColumns'> /**
+</span> * Returns an array of the <b>visible</b> columns in the grid. This goes down to the lowest column header
* level, and does not return <i>grouped</i> headers which contain sub headers.
* @param {Boolean} refreshCache If omitted, the cached set of columns will be returned. Pass true to refresh the cache.
* @returns {Array}
return Ext.ComponentQuery.query(':not([hidden])', this.getGridColumns(refreshCache));
},
-<span id='Ext-grid.header.Container-method-getGridColumns'> /**
+<span id='Ext-grid-header-Container-method-getGridColumns'> /**
</span> * Returns an array of all columns which map to Store fields. This goes down to the lowest column header
* level, and does not return <i>grouped</i> headers which contain sub headers.
* @param {Boolean} refreshCache If omitted, the cached set of columns will be returned. Pass true to refresh the cache.
return result;
},
-<span id='Ext-grid.header.Container-method-getHeaderIndex'> /**
+<span id='Ext-grid-header-Container-method-getHideableColumns'> /**
+</span> * @private
+ * For use by column headers in determining whether there are any hideable columns when deciding whether or not
+ * the header menu should be disabled.
+ */
+ getHideableColumns: function(refreshCache) {
+ var me = this,
+ result = refreshCache ? null : me.hideableColumns;
+
+ if (!result) {
+ result = me.hideableColumns = me.query('[hideable]');
+ }
+ return result;
+ },
+
+<span id='Ext-grid-header-Container-method-getHeaderIndex'> /**
</span> * Get the index of a leaf level header regardless of what the nesting
* structure is.
*/
return Ext.Array.indexOf(columns, header);
},
-<span id='Ext-grid.header.Container-method-getHeaderAtIndex'> /**
+<span id='Ext-grid-header-Container-method-getHeaderAtIndex'> /**
</span> * Get a leaf level header by index regardless of what the nesting
* structure is.
*/
return columns[index];
},
-<span id='Ext-grid.header.Container-method-prepareData'> /**
+<span id='Ext-grid-header-Container-method-prepareData'> /**
</span> * Maps the record data to base it on the header id's.
* This correlates to the markup/template generated by
* TableChunker.
*/
- prepareData: function(data, rowIdx, record, view) {
+ prepareData: function(data, rowIdx, record, view, panel) {
var obj = {},
- headers = this.getGridColumns(),
+ headers = this.gridDataColumns || this.getGridColumns(),
headersLn = headers.length,
colIdx = 0,
- header, value,
+ header,
+ headerId,
+ renderer,
+ value,
metaData,
- g = this.up('tablepanel'),
- store = g.store;
+ store = panel.store;
for (; colIdx < headersLn; colIdx++) {
metaData = {
style: ''
};
header = headers[colIdx];
+ headerId = header.id;
+ renderer = header.renderer;
value = data[header.dataIndex];
// When specifying a renderer as a string, it always resolves
// to Ext.util.Format
- if (Ext.isString(header.renderer)) {
- header.renderer = Ext.util.Format[header.renderer];
+ if (typeof renderer === "string") {
+ header.renderer = renderer = Ext.util.Format[renderer];
}
- if (Ext.isFunction(header.renderer)) {
- value = header.renderer.call(
+ if (typeof renderer === "function") {
+ value = renderer.call(
header.scope || this.ownerCt,
value,
// metadata per cell passing an obj by reference so that
delete metaData.css;
}
// </debug>
- obj[header.id+'-modified'] = record.isModified(header.dataIndex) ? Ext.baseCSSPrefix + 'grid-dirty-cell' : Ext.baseCSSPrefix + 'grid-clean-cell';
- obj[header.id+'-tdCls'] = metaData.tdCls;
- obj[header.id+'-tdAttr'] = metaData.tdAttr;
- obj[header.id+'-style'] = metaData.style;
+
+ obj[headerId+'-modified'] = record.isModified(header.dataIndex) ? Ext.baseCSSPrefix + 'grid-dirty-cell' : '';
+ obj[headerId+'-tdCls'] = metaData.tdCls;
+ obj[headerId+'-tdAttr'] = metaData.tdAttr;
+ obj[headerId+'-style'] = metaData.style;
if (value === undefined || value === null || value === '') {
value = '&#160;';
}
- obj[header.id] = value;
+ obj[headerId] = value;
}
return obj;
},
}
}
});
-</pre></pre></body></html>
\ No newline at end of file
+</pre>
+</body>
+</html>