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