Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / docs / source / Container2.html
1 <!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'>/**
2 </span> * @class Ext.grid.header.Container
3  * @extends Ext.container.Container
4  * @private
5  *
6  * Container which holds headers and is docked at the top or bottom of a TablePanel.
7  * The HeaderContainer drives resizing/moving/hiding of columns within the TableView.
8  * As headers are hidden, moved or resized the headercontainer is responsible for
9  * triggering changes within the view.
10  *
11  * @xtype headercontainer
12  */
13 Ext.define('Ext.grid.header.Container', {
14     extend: 'Ext.container.Container',
15     uses: [
16         'Ext.grid.ColumnLayout',
17         'Ext.grid.column.Column',
18         'Ext.menu.Menu',
19         'Ext.menu.CheckItem',
20         'Ext.menu.Separator',
21         'Ext.grid.plugin.HeaderResizer',
22         'Ext.grid.plugin.HeaderReorderer'
23     ],
24     border: true,
25
26     alias: 'widget.headercontainer',
27
28     baseCls: Ext.baseCSSPrefix + 'grid-header-ct',
29     dock: 'top',
30
31 <span id='Ext-grid.header.Container-cfg-weight'>    /**
32 </span>     * @cfg {Number} weight
33      * HeaderContainer overrides the default weight of 0 for all docked items to 100.
34      * This is so that it has more priority over things like toolbars.
35      */
36     weight: 100,
37     defaultType: 'gridcolumn',
38 <span id='Ext-grid.header.Container-cfg-defaultWidth'>    /**
39 </span>     * @cfg {Number} defaultWidth
40      * Width of the header if no width or flex is specified. Defaults to 100.
41      */
42     defaultWidth: 100,
43
44
45     sortAscText: 'Sort Ascending',
46     sortDescText: 'Sort Descending',
47     sortClearText: 'Clear Sort',
48     columnsText: 'Columns',
49
50     lastHeaderCls: Ext.baseCSSPrefix + 'column-header-last',
51     firstHeaderCls: Ext.baseCSSPrefix + 'column-header-first',
52     headerOpenCls: Ext.baseCSSPrefix + 'column-header-open',
53
54     // private; will probably be removed by 4.0
55     triStateSort: false,
56
57     ddLock: false,
58
59     dragging: false,
60
61 <span id='Ext-grid.header.Container-property-isGroupHeader'>    /**
62 </span>     * &lt;code&gt;true&lt;/code&gt; if this HeaderContainer is in fact a group header which contains sub headers.
63      * @type Boolean
64      * @property isGroupHeader
65      */
66
67 <span id='Ext-grid.header.Container-cfg-sortable'>    /**
68 </span>     * @cfg {Boolean} sortable
69      * Provides the default sortable state for all Headers within this HeaderContainer.
70      * Also turns on or off the menus in the HeaderContainer. Note that the menu is
71      * shared across every header and therefore turning it off will remove the menu
72      * items for every header.
73      */
74     sortable: true,
75     
76     initComponent: function() {
77         var me = this;
78         
79         me.headerCounter = 0;
80         me.plugins = me.plugins || [];
81
82         // TODO: Pass in configurations to turn on/off dynamic
83         //       resizing and disable resizing all together
84
85         // Only set up a Resizer and Reorderer for the topmost HeaderContainer.
86         // Nested Group Headers are themselves HeaderContainers
87         if (!me.isHeader) {
88             me.resizer   = Ext.create('Ext.grid.plugin.HeaderResizer');
89             me.reorderer = Ext.create('Ext.grid.plugin.HeaderReorderer');
90             if (!me.enableColumnResize) {
91                 me.resizer.disable();
92             } 
93             if (!me.enableColumnMove) {
94                 me.reorderer.disable();
95             }
96             me.plugins.push(me.reorderer, me.resizer);
97         }
98
99         // Base headers do not need a box layout
100         if (me.isHeader &amp;&amp; !me.items) {
101             me.layout = 'auto';
102         }
103         // HeaderContainer and Group header needs a gridcolumn layout.
104         else {
105             me.layout = {
106                 type: 'gridcolumn',
107                 availableSpaceOffset: me.availableSpaceOffset,
108                 align: 'stretchmax',
109                 resetStretch: true
110             };
111         }
112         me.defaults = me.defaults || {};
113         Ext.applyIf(me.defaults, {
114             width: me.defaultWidth,
115             triStateSort: me.triStateSort,
116             sortable: me.sortable
117         });
118         me.callParent();
119         me.addEvents(
120 <span id='Ext-grid.header.Container-event-columnresize'>            /**
121 </span>             * @event columnresize
122              * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
123              * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
124              * @param {Number} width
125              */
126             'columnresize',
127
128 <span id='Ext-grid.header.Container-event-headerclick'>            /**
129 </span>             * @event headerclick
130              * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
131              * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
132              * @param {Ext.EventObject} e
133              * @param {HTMLElement} t
134              */
135             'headerclick',
136
137 <span id='Ext-grid.header.Container-event-headertriggerclick'>            /**
138 </span>             * @event headertriggerclick
139              * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
140              * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
141              * @param {Ext.EventObject} e
142              * @param {HTMLElement} t
143              */
144             'headertriggerclick',
145
146 <span id='Ext-grid.header.Container-event-columnmove'>            /**
147 </span>             * @event columnmove
148              * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
149              * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
150              * @param {Number} fromIdx
151              * @param {Number} toIdx
152              */
153             'columnmove',
154 <span id='Ext-grid.header.Container-event-columnhide'>            /**
155 </span>             * @event columnhide
156              * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
157              * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
158              */
159             'columnhide',
160 <span id='Ext-grid.header.Container-event-columnshow'>            /**
161 </span>             * @event columnshow
162              * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
163              * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
164              */
165             'columnshow',
166 <span id='Ext-grid.header.Container-event-sortchange'>            /**
167 </span>             * @event sortchange
168              * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.
169              * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition
170              * @param {String} direction
171              */
172             'sortchange',
173 <span id='Ext-grid.header.Container-event-menucreate'>            /**
174 </span>             * @event menucreate
175              * Fired immediately after the column header menu is created.
176              * @param {Ext.grid.header.Container} ct This instance
177              * @param {Ext.menu.Menu} menu The Menu that was created
178              */
179             'menucreate'
180         );
181     },
182
183     onDestroy: function() {
184         Ext.destroy(this.resizer, this.reorderer);
185         this.callParent();
186     },
187
188     // Invalidate column cache on add
189     // We cannot refresh the View on every add because this method is called
190     // when the HeaderDropZone moves Headers around, that will also refresh the view
191     onAdd: function(c) {
192         var me = this;
193         if (!c.headerId) {
194             c.headerId = 'h' + (++me.headerCounter);
195         }
196         me.callParent(arguments);
197         me.purgeCache();
198     },
199
200     // Invalidate column cache on remove
201     // We cannot refresh the View on every remove because this method is called
202     // when the HeaderDropZone moves Headers around, that will also refresh the view
203     onRemove: function(c) {
204         var me = this;
205         me.callParent(arguments);
206         me.purgeCache();
207     },
208
209     afterRender: function() {
210         this.callParent();
211         var store   = this.up('[store]').store,
212             sorters = store.sorters,
213             first   = sorters.first(),
214             hd;
215
216         if (first) {
217             hd = this.down('gridcolumn[dataIndex=' + first.property  +']');
218             if (hd) {
219                 hd.setSortState(first.direction, false, true);
220             }
221         }
222     },
223
224     afterLayout: function() {
225         if (!this.isHeader) {
226             var me = this,
227                 topHeaders = me.query('&gt;gridcolumn:not([hidden])'),
228                 viewEl;
229
230             me.callParent(arguments);
231
232             if (topHeaders.length) {
233                 topHeaders[0].el.radioCls(me.firstHeaderCls);
234                 topHeaders[topHeaders.length - 1].el.radioCls(me.lastHeaderCls);
235             }
236         }
237     },
238
239     onHeaderShow: function(header) {
240         // Pass up to the GridSection
241         var me = this,
242             gridSection = me.ownerCt,
243             menu = me.getMenu(),
244             topItems, topItemsVisible,
245             colCheckItem,
246             itemToEnable,
247             len, i;
248
249         if (menu) {
250
251             colCheckItem = menu.down('menucheckitem[headerId=' + header.id + ']');
252             if (colCheckItem) {
253                 colCheckItem.setChecked(true, true);
254             }
255
256             // There's more than one header visible, and we've disabled some checked items... re-enable them
257             topItems = menu.query('#columnItem&gt;menucheckitem[checked]');
258             topItemsVisible = topItems.length;
259             if ((me.getVisibleGridColumns().length &gt; 1) &amp;&amp; me.disabledMenuItems &amp;&amp; me.disabledMenuItems.length) {
260                 if (topItemsVisible == 1) {
261                     Ext.Array.remove(me.disabledMenuItems, topItems[0]);
262                 }
263                 for (i = 0, len = me.disabledMenuItems.length; i &lt; len; i++) {
264                     itemToEnable = me.disabledMenuItems[i];
265                     if (!itemToEnable.isDestroyed) {
266                         itemToEnable[itemToEnable.menu ? 'enableCheckChange' : 'enable']();
267                     }
268                 }
269                 if (topItemsVisible == 1) {
270                     me.disabledMenuItems = topItems;
271                 } else {
272                     me.disabledMenuItems = [];
273                 }
274             }
275         }
276
277         // Only update the grid UI when we are notified about base level Header shows;
278         // Group header shows just cause a layout of the HeaderContainer
279         if (!header.isGroupHeader) {
280             if (me.view) {
281                 me.view.onHeaderShow(me, header, true);
282             }
283             if (gridSection) {
284                 gridSection.onHeaderShow(me, header);
285             }
286         }
287         me.fireEvent('columnshow', me, header);
288
289         // The header's own hide suppresses cascading layouts, so lay the headers out now
290         me.doLayout();
291     },
292
293     onHeaderHide: function(header, suppressLayout) {
294         // Pass up to the GridSection
295         var me = this,
296             gridSection = me.ownerCt,
297             menu = me.getMenu(),
298             colCheckItem;
299
300         if (menu) {
301
302             // If the header was hidden programmatically, sync the Menu state
303             colCheckItem = menu.down('menucheckitem[headerId=' + header.id + ']');
304             if (colCheckItem) {
305                 colCheckItem.setChecked(false, true);
306             }
307             me.setDisabledItems();
308         }
309
310         // Only update the UI when we are notified about base level Header hides;
311         if (!header.isGroupHeader) {
312             if (me.view) {
313                 me.view.onHeaderHide(me, header, true);
314             }
315             if (gridSection) {
316                 gridSection.onHeaderHide(me, header);
317             }
318
319             // The header's own hide suppresses cascading layouts, so lay the headers out now
320             if (!suppressLayout) {
321                 me.doLayout();
322             }
323         }
324         me.fireEvent('columnhide', me, header);
325     },
326
327     setDisabledItems: function(){
328         var me = this,
329             menu = me.getMenu(),
330             i = 0,
331             len,
332             itemsToDisable,
333             itemToDisable;
334
335         // Find what to disable. If only one top level item remaining checked, we have to disable stuff.
336         itemsToDisable = menu.query('#columnItem&gt;menucheckitem[checked]');
337         if ((itemsToDisable.length === 1)) {
338             if (!me.disabledMenuItems) {
339                 me.disabledMenuItems = [];
340             }
341
342             // If down to only one column visible, also disable any descendant checkitems
343             if ((me.getVisibleGridColumns().length === 1) &amp;&amp; itemsToDisable[0].menu) {
344                 itemsToDisable = itemsToDisable.concat(itemsToDisable[0].menu.query('menucheckitem[checked]'));
345             }
346
347             len = itemsToDisable.length;
348             // Disable any further unchecking at any level.
349             for (i = 0; i &lt; len; i++) {
350                 itemToDisable = itemsToDisable[i];
351                 if (!Ext.Array.contains(me.disabledMenuItems, itemToDisable)) {
352                     itemToDisable[itemToDisable.menu ? 'disableCheckChange' : 'disable']();
353                     me.disabledMenuItems.push(itemToDisable);
354                 }
355             }
356         }
357     },
358
359 <span id='Ext-grid.header.Container-method-tempLock'>    /**
360 </span>     * Temporarily lock the headerCt. This makes it so that clicking on headers
361      * don't trigger actions like sorting or opening of the header menu. This is
362      * done because extraneous events may be fired on the headers after interacting
363      * with a drag drop operation.
364      * @private
365      */
366     tempLock: function() {
367         this.ddLock = true;
368         Ext.Function.defer(function() {
369             this.ddLock = false;
370         }, 200, this);
371     },
372
373     onHeaderResize: function(header, w, suppressFocus) {
374         this.tempLock();
375         if (this.view &amp;&amp; this.view.rendered) {
376             this.view.onHeaderResize(header, w, suppressFocus);
377         }
378         this.fireEvent('columnresize', this, header, w);
379     },
380
381     onHeaderClick: function(header, e, t) {
382         this.fireEvent(&quot;headerclick&quot;, this, header, e, t);
383     },
384
385     onHeaderTriggerClick: function(header, e, t) {
386         // generate and cache menu, provide ability to cancel/etc
387         if (this.fireEvent(&quot;headertriggerclick&quot;, this, header, e, t) !== false) {
388             this.showMenuBy(t, header);
389         }
390     },
391
392     showMenuBy: function(t, header) {
393         var menu = this.getMenu(),
394             ascItem  = menu.down('#ascItem'),
395             descItem = menu.down('#descItem'),
396             sortableMth;
397
398         menu.activeHeader = menu.ownerCt = header;
399         menu.setFloatParent(header);
400         // TODO: remove coupling to Header's titleContainer el
401         header.titleContainer.addCls(this.headerOpenCls);
402
403         // enable or disable asc &amp; desc menu items based on header being sortable
404         sortableMth = header.sortable ? 'enable' : 'disable';
405         if (ascItem) {
406             ascItem[sortableMth]();
407         }
408         if (descItem) {
409             descItem[sortableMth]();
410         }
411         menu.showBy(t);
412     },
413
414     // remove the trigger open class when the menu is hidden
415     onMenuDeactivate: function() {
416         var menu = this.getMenu();
417         // TODO: remove coupling to Header's titleContainer el
418         menu.activeHeader.titleContainer.removeCls(this.headerOpenCls);
419     },
420
421     moveHeader: function(fromIdx, toIdx) {
422
423         // An automatically expiring lock
424         this.tempLock();
425         this.onHeaderMoved(this.move(fromIdx, toIdx), fromIdx, toIdx);
426     },
427
428     purgeCache: function() {
429         var me = this;
430         // Delete column cache - column order has changed.
431         delete me.gridDataColumns;
432
433         // Menu changes when columns are moved. It will be recreated.
434         if (me.menu) {
435             me.menu.destroy();
436             delete me.menu;
437         }
438     },
439
440     onHeaderMoved: function(header, fromIdx, toIdx) {
441         var me = this,
442             gridSection = me.ownerCt;
443
444         if (gridSection) {
445             gridSection.onHeaderMove(me, header, fromIdx, toIdx);
446         }
447         me.fireEvent(&quot;columnmove&quot;, me, header, fromIdx, toIdx);
448     },
449
450 <span id='Ext-grid.header.Container-method-getMenu'>    /**
451 </span>     * Gets the menu (and will create it if it doesn't already exist)
452      * @private
453      */
454     getMenu: function() {
455         var me = this;
456
457         if (!me.menu) {
458             me.menu = Ext.create('Ext.menu.Menu', {
459                 items: me.getMenuItems(),
460                 listeners: {
461                     deactivate: me.onMenuDeactivate,
462                     scope: me
463                 }
464             });
465             me.setDisabledItems();
466             me.fireEvent('menucreate', me, me.menu);
467         }
468         return me.menu;
469     },
470
471 <span id='Ext-grid.header.Container-method-getMenuItems'>    /**
472 </span>     * Returns an array of menu items to be placed into the shared menu
473      * across all headers in this header container.
474      * @returns {Array} menuItems
475      */
476     getMenuItems: function() {
477         var me = this,
478             menuItems = [{
479                 itemId: 'columnItem',
480                 text: me.columnsText,
481                 cls: Ext.baseCSSPrefix + 'cols-icon',
482                 menu: me.getColumnMenu(me)
483             }];
484
485         if (me.sortable) {
486             menuItems.unshift({
487                 itemId: 'ascItem',
488                 text: me.sortAscText,
489                 cls: 'xg-hmenu-sort-asc',
490                 handler: me.onSortAscClick,
491                 scope: me
492             },{
493                 itemId: 'descItem',
494                 text: me.sortDescText,
495                 cls: 'xg-hmenu-sort-desc',
496                 handler: me.onSortDescClick,
497                 scope: me
498             },'-');
499         }
500         return menuItems;
501     },
502
503     // sort asc when clicking on item in menu
504     onSortAscClick: function() {
505         var menu = this.getMenu(),
506             activeHeader = menu.activeHeader;
507
508         activeHeader.setSortState('ASC');
509     },
510
511     // sort desc when clicking on item in menu
512     onSortDescClick: function() {
513         var menu = this.getMenu(),
514             activeHeader = menu.activeHeader;
515
516         activeHeader.setSortState('DESC');
517     },
518
519 <span id='Ext-grid.header.Container-method-getColumnMenu'>    /**
520 </span>     * Returns an array of menu CheckItems corresponding to all immediate children of the passed Container which have been configured as hideable.
521      */
522     getColumnMenu: function(headerContainer) {
523         var menuItems = [],
524             i = 0,
525             item,
526             items = headerContainer.query('&gt;gridcolumn[hideable]'),
527             itemsLn = items.length,
528             menuItem;
529
530         for (; i &lt; itemsLn; i++) {
531             item = items[i];
532             menuItem = Ext.create('Ext.menu.CheckItem', {
533                 text: item.text,
534                 checked: !item.hidden,
535                 hideOnClick: false,
536                 headerId: item.id,
537                 menu: item.isGroupHeader ? this.getColumnMenu(item) : undefined,
538                 checkHandler: this.onColumnCheckChange,
539                 scope: this
540             });
541             if (itemsLn === 1) {
542                 menuItem.disabled = true;
543             }
544             menuItems.push(menuItem);
545
546             // If the header is ever destroyed - for instance by dragging out the last remaining sub header,
547             // then the associated menu item must also be destroyed.
548             item.on({
549                 destroy: Ext.Function.bind(menuItem.destroy, menuItem)
550             });
551         }
552         return menuItems;
553     },
554
555     onColumnCheckChange: function(checkItem, checked) {
556         var header = Ext.getCmp(checkItem.headerId);
557         header[checked ? 'show' : 'hide']();
558     },
559
560 <span id='Ext-grid.header.Container-method-getColumnsForTpl'>    /**
561 </span>     * Get the columns used for generating a template via TableChunker.
562      * Returns an array of all columns and their
563      *  - dataIndex
564      *  - align
565      *  - width
566      *  - id
567      *  - columnId - used to create an identifying CSS class
568      *  - cls The tdCls configuration from the Column object
569      *  @private
570      */
571     getColumnsForTpl: function(flushCache) {
572         var cols    = [],
573             headers   = this.getGridColumns(flushCache),
574             headersLn = headers.length,
575             i = 0,
576             header;
577
578         for (; i &lt; headersLn; i++) {
579             header = headers[i];
580             cols.push({
581                 dataIndex: header.dataIndex,
582                 align: header.align,
583                 width: header.hidden ? 0 : header.getDesiredWidth(),
584                 id: header.id,
585                 cls: header.tdCls,
586                 columnId: header.getItemId()
587             });
588         }
589         return cols;
590     },
591
592 <span id='Ext-grid.header.Container-method-getColumnCount'>    /**
593 </span>     * Returns the number of &lt;b&gt;grid columns&lt;/b&gt; descended from this HeaderContainer.
594      * Group Columns are HeaderContainers. All grid columns are returned, including hidden ones.
595      */
596     getColumnCount: function() {
597         return this.getGridColumns().length;
598     },
599
600 <span id='Ext-grid.header.Container-method-getFullWidth'>    /**
601 </span>     * Gets the full width of all columns that are visible.
602      */
603     getFullWidth: function(flushCache) {
604         var fullWidth = 0,
605             headers     = this.getVisibleGridColumns(flushCache),
606             headersLn   = headers.length,
607             i         = 0;
608
609         for (; i &lt; headersLn; i++) {
610             if (!isNaN(headers[i].width)) {
611                 // use headers getDesiredWidth if its there
612                 if (headers[i].getDesiredWidth) {
613                     fullWidth += headers[i].getDesiredWidth();
614                 // if injected a diff cmp use getWidth
615                 } else {
616                     fullWidth += headers[i].getWidth();
617                 }
618             }
619         }
620         return fullWidth;
621     },
622
623     // invoked internally by a header when not using triStateSorting
624     clearOtherSortStates: function(activeHeader) {
625         var headers   = this.getGridColumns(),
626             headersLn = headers.length,
627             i         = 0,
628             oldSortState;
629
630         for (; i &lt; headersLn; i++) {
631             if (headers[i] !== activeHeader) {
632                 oldSortState = headers[i].sortState;
633                 // unset the sortstate and dont recurse
634                 headers[i].setSortState(null, true);
635                 //if (!silent &amp;&amp; oldSortState !== null) {
636                 //    this.fireEvent('sortchange', this, headers[i], null);
637                 //}
638             }
639         }
640     },
641
642 <span id='Ext-grid.header.Container-method-getVisibleGridColumns'>    /**
643 </span>     * Returns an array of the &lt;b&gt;visible&lt;b&gt; columns in the grid. This goes down to the lowest column header
644      * level, and does not return &lt;i&gt;grouped&lt;/i&gt; headers which contain sub headers.
645      * @param {Boolean} refreshCache If omitted, the cached set of columns will be returned. Pass true to refresh the cache.
646      * @returns {Array}
647      */
648     getVisibleGridColumns: function(refreshCache) {
649         return Ext.ComponentQuery.query(':not([hidden])', this.getGridColumns(refreshCache));
650     },
651
652 <span id='Ext-grid.header.Container-method-getGridColumns'>    /**
653 </span>     * Returns an array of all columns which map to Store fields. This goes down to the lowest column header
654      * level, and does not return &lt;i&gt;grouped&lt;/i&gt; headers which contain sub headers.
655      * @param {Boolean} refreshCache If omitted, the cached set of columns will be returned. Pass true to refresh the cache.
656      * @returns {Array}
657      */
658     getGridColumns: function(refreshCache) {
659         var me = this,
660             result = refreshCache ? null : me.gridDataColumns;
661
662         // Not already got the column cache, so collect the base columns
663         if (!result) {
664             me.gridDataColumns = result = [];
665             me.cascade(function(c) {
666                 if ((c !== me) &amp;&amp; !c.isGroupHeader) {
667                     result.push(c);
668                 }
669             });
670         }
671
672         return result;
673     },
674
675 <span id='Ext-grid.header.Container-method-getHeaderIndex'>    /**
676 </span>     * Get the index of a leaf level header regardless of what the nesting
677      * structure is.
678      */
679     getHeaderIndex: function(header) {
680         var columns = this.getGridColumns();
681         return Ext.Array.indexOf(columns, header);
682     },
683
684 <span id='Ext-grid.header.Container-method-getHeaderAtIndex'>    /**
685 </span>     * Get a leaf level header by index regardless of what the nesting
686      * structure is.
687      */
688     getHeaderAtIndex: function(index) {
689         var columns = this.getGridColumns();
690         return columns[index];
691     },
692
693 <span id='Ext-grid.header.Container-method-prepareData'>    /**
694 </span>     * Maps the record data to base it on the header id's.
695      * This correlates to the markup/template generated by
696      * TableChunker.
697      */
698     prepareData: function(data, rowIdx, record, view) {
699         var obj       = {},
700             headers   = this.getGridColumns(),
701             headersLn = headers.length,
702             colIdx    = 0,
703             header, value,
704             metaData,
705             g = this.up('tablepanel'),
706             store = g.store;
707
708         for (; colIdx &lt; headersLn; colIdx++) {
709             metaData = {
710                 tdCls: '',
711                 style: ''
712             };
713             header = headers[colIdx];
714             value = data[header.dataIndex];
715
716             // When specifying a renderer as a string, it always resolves
717             // to Ext.util.Format
718             if (Ext.isString(header.renderer)) {
719                 header.renderer = Ext.util.Format[header.renderer];
720             }
721
722             if (Ext.isFunction(header.renderer)) {
723                 value = header.renderer.call(
724                     header.scope || this.ownerCt,
725                     value,
726                     // metadata per cell passing an obj by reference so that
727                     // it can be manipulated inside the renderer
728                     metaData,
729                     record,
730                     rowIdx,
731                     colIdx,
732                     store,
733                     view
734                 );
735             }
736
737             // &lt;debug&gt;
738             if (metaData.css) {
739                 // This warning attribute is used by the compat layer
740                 obj.cssWarning = true;
741                 metaData.tdCls = metaData.css;
742                 delete metaData.css;
743             }
744             // &lt;/debug&gt;
745             obj[header.id+'-modified'] = record.isModified(header.dataIndex) ? Ext.baseCSSPrefix + 'grid-dirty-cell' : Ext.baseCSSPrefix + 'grid-clean-cell';
746             obj[header.id+'-tdCls'] = metaData.tdCls;
747             obj[header.id+'-tdAttr'] = metaData.tdAttr;
748             obj[header.id+'-style'] = metaData.style;
749             if (value === undefined || value === null || value === '') {
750                 value = '&amp;#160;';
751             }
752             obj[header.id] = value;
753         }
754         return obj;
755     },
756
757     expandToFit: function(header) {
758         if (this.view) {
759             this.view.expandToFit(header);
760         }
761     }
762 });
763 </pre></pre></body></html>