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