PageRenderTime 29ms CodeModel.GetById 18ms app.highlight 6ms RepoModel.GetById 0ms app.codeStats 0ms

/ext-4.0.7/docs/source/Container2.html

https://bitbucket.org/srogerf/javascript
HTML | 916 lines | 813 code | 103 blank | 0 comment | 0 complexity | 0713f695e50d4f7f9819a43f9f33f8d3 MD5 | raw file
  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="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7  <script type="text/javascript" src="../resources/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 */
 27Ext.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    applyDefaults: function(config){
203        /*
204         * Ensure header.Container defaults don't get applied to a RowNumberer 
205         * if an xtype is supplied. This isn't an ideal solution however it's 
206         * much more likely that a RowNumberer with no options will be created, 
207         * wanting to use the defaults specified on the class as opposed to 
208         * those setup on the Container.
209         */
210        if (config &amp;&amp; !config.isComponent &amp;&amp; config.xtype == 'rownumberer') {
211            return config;
212        }
213        return this.callParent([config]);
214    },
215
216    applyColumnsState: function(columns) {
217        if (!columns || !columns.length) {
218            return;
219        }
220
221        var me = this,
222            i = 0,
223            index,
224            col;
225
226        Ext.each(columns, function (columnState) {
227            col = me.down('gridcolumn[headerId=' + columnState.id + ']');
228            if (col) {
229                index = me.items.indexOf(col);
230                if (i !== index) {
231                    me.moveHeader(index, i);
232                }
233
234                if (col.applyColumnState) {
235                    col.applyColumnState(columnState);
236                }
237                ++i;
238            }
239        });
240    },
241
242    getColumnsState: function () {
243        var me = this,
244            columns = [],
245            state;
246
247        me.items.each(function (col) {
248            state = col.getColumnState &amp;&amp; col.getColumnState();
249            if (state) {
250                columns.push(state);
251            }
252        });
253
254        return columns;
255    },
256
257    // Invalidate column cache on add
258    // We cannot refresh the View on every add because this method is called
259    // when the HeaderDropZone moves Headers around, that will also refresh the view
260    onAdd: function(c) {
261        var me = this;
262        if (!c.headerId) {
263            c.headerId = c.initialConfig.id || ('h' + (++me.headerCounter));
264        }
265        //&lt;debug warn&gt;
266        if (Ext.global.console &amp;&amp; Ext.global.console.warn) {
267            if (!me._usedIDs) me._usedIDs = {};
268            if (me._usedIDs[c.headerId]) {
269                Ext.global.console.warn(this.$className, 'attempted to reuse an existing id', c.headerId);
270            }
271            me._usedIDs[c.headerId] = true;
272        }
273        //&lt;/debug&gt;
274        me.callParent(arguments);
275        me.purgeCache();
276    },
277
278    // Invalidate column cache on remove
279    // We cannot refresh the View on every remove because this method is called
280    // when the HeaderDropZone moves Headers around, that will also refresh the view
281    onRemove: function(c) {
282        var me = this;
283        me.callParent(arguments);
284        me.purgeCache();
285    },
286
287    afterRender: function() {
288        this.callParent();
289        var store   = this.up('[store]').store,
290            sorters = store.sorters,
291            first   = sorters.first(),
292            hd;
293
294        if (first) {
295            hd = this.down('gridcolumn[dataIndex=' + first.property  +']');
296            if (hd) {
297                hd.setSortState(first.direction, false, true);
298            }
299        }
300    },
301
302    afterLayout: function() {
303        if (!this.isHeader) {
304            var me = this,
305                topHeaders = me.query('&gt;gridcolumn:not([hidden])'),
306                viewEl,
307                firstHeaderEl,
308                lastHeaderEl;
309
310            me.callParent(arguments);
311
312            if (topHeaders.length) {
313                firstHeaderEl = topHeaders[0].el;
314                if (firstHeaderEl !== me.pastFirstHeaderEl) {
315                    if (me.pastFirstHeaderEl) {
316                        me.pastFirstHeaderEl.removeCls(me.firstHeaderCls);
317                    }
318                    firstHeaderEl.addCls(me.firstHeaderCls);
319                    me.pastFirstHeaderEl = firstHeaderEl;
320                }
321
322                lastHeaderEl = topHeaders[topHeaders.length - 1].el;
323                if (lastHeaderEl !== me.pastLastHeaderEl) {
324                    if (me.pastLastHeaderEl) {
325                        me.pastLastHeaderEl.removeCls(me.lastHeaderCls);
326                    }
327                    lastHeaderEl.addCls(me.lastHeaderCls);
328                    me.pastLastHeaderEl = lastHeaderEl;
329                }
330            }
331        }
332
333    },
334
335    onHeaderShow: function(header, preventLayout) {
336        // Pass up to the GridSection
337        var me = this,
338            gridSection = me.ownerCt,
339            menu = me.getMenu(),
340            topItems, topItemsVisible,
341            colCheckItem,
342            itemToEnable,
343            len, i;
344
345        if (menu) {
346
347            colCheckItem = menu.down('menucheckitem[headerId=' + header.id + ']');
348            if (colCheckItem) {
349                colCheckItem.setChecked(true, true);
350            }
351
352            // There's more than one header visible, and we've disabled some checked items... re-enable them
353            topItems = menu.query('#columnItem&gt;menucheckitem[checked]');
354            topItemsVisible = topItems.length;
355            if ((me.getVisibleGridColumns().length &gt; 1) &amp;&amp; me.disabledMenuItems &amp;&amp; me.disabledMenuItems.length) {
356                if (topItemsVisible == 1) {
357                    Ext.Array.remove(me.disabledMenuItems, topItems[0]);
358                }
359                for (i = 0, len = me.disabledMenuItems.length; i &lt; len; i++) {
360                    itemToEnable = me.disabledMenuItems[i];
361                    if (!itemToEnable.isDestroyed) {
362                        itemToEnable[itemToEnable.menu ? 'enableCheckChange' : 'enable']();
363                    }
364                }
365                if (topItemsVisible == 1) {
366                    me.disabledMenuItems = topItems;
367                } else {
368                    me.disabledMenuItems = [];
369                }
370            }
371        }
372
373        // Only update the grid UI when we are notified about base level Header shows;
374        // Group header shows just cause a layout of the HeaderContainer
375        if (!header.isGroupHeader) {
376            if (me.view) {
377                me.view.onHeaderShow(me, header, true);
378            }
379            if (gridSection) {
380                gridSection.onHeaderShow(me, header);
381            }
382        }
383        me.fireEvent('columnshow', me, header);
384
385        // The header's own hide suppresses cascading layouts, so lay the headers out now
386        if (preventLayout !== true) {
387            me.doLayout();
388        }
389    },
390
391    doComponentLayout: function(){
392        var me = this;
393        if (me.view &amp;&amp; me.view.saveScrollState) {
394            me.view.saveScrollState();
395        }
396        me.callParent(arguments);
397        if (me.view &amp;&amp; me.view.restoreScrollState) {
398            me.view.restoreScrollState();
399        }
400    },
401
402    onHeaderHide: function(header, suppressLayout) {
403        // Pass up to the GridSection
404        var me = this,
405            gridSection = me.ownerCt,
406            menu = me.getMenu(),
407            colCheckItem;
408
409        if (menu) {
410
411            // If the header was hidden programmatically, sync the Menu state
412            colCheckItem = menu.down('menucheckitem[headerId=' + header.id + ']');
413            if (colCheckItem) {
414                colCheckItem.setChecked(false, true);
415            }
416            me.setDisabledItems();
417        }
418
419        // Only update the UI when we are notified about base level Header hides;
420        if (!header.isGroupHeader) {
421            if (me.view) {
422                me.view.onHeaderHide(me, header, true);
423            }
424            if (gridSection) {
425                gridSection.onHeaderHide(me, header);
426            }
427
428            // The header's own hide suppresses cascading layouts, so lay the headers out now
429            if (!suppressLayout) {
430                me.doLayout();
431            }
432        }
433        me.fireEvent('columnhide', me, header);
434    },
435
436    setDisabledItems: function(){
437        var me = this,
438            menu = me.getMenu(),
439            i = 0,
440            len,
441            itemsToDisable,
442            itemToDisable;
443
444        // Find what to disable. If only one top level item remaining checked, we have to disable stuff.
445        itemsToDisable = menu.query('#columnItem&gt;menucheckitem[checked]');
446        if ((itemsToDisable.length === 1)) {
447            if (!me.disabledMenuItems) {
448                me.disabledMenuItems = [];
449            }
450
451            // If down to only one column visible, also disable any descendant checkitems
452            if ((me.getVisibleGridColumns().length === 1) &amp;&amp; itemsToDisable[0].menu) {
453                itemsToDisable = itemsToDisable.concat(itemsToDisable[0].menu.query('menucheckitem[checked]'));
454            }
455
456            len = itemsToDisable.length;
457            // Disable any further unchecking at any level.
458            for (i = 0; i &lt; len; i++) {
459                itemToDisable = itemsToDisable[i];
460                if (!Ext.Array.contains(me.disabledMenuItems, itemToDisable)) {
461
462                    // If we only want to disable check change: it might be a disabled item, so enable it prior to
463                    // setting its correct disablement level.
464                    itemToDisable.disabled = false;
465                    itemToDisable[itemToDisable.menu ? 'disableCheckChange' : 'disable']();
466                    me.disabledMenuItems.push(itemToDisable);
467                }
468            }
469        }
470    },
471
472<span id='Ext-grid-header-Container-method-tempLock'>    /**
473</span>     * Temporarily lock the headerCt. This makes it so that clicking on headers
474     * don't trigger actions like sorting or opening of the header menu. This is
475     * done because extraneous events may be fired on the headers after interacting
476     * with a drag drop operation.
477     * @private
478     */
479    tempLock: function() {
480        this.ddLock = true;
481        Ext.Function.defer(function() {
482            this.ddLock = false;
483        }, 200, this);
484    },
485
486    onHeaderResize: function(header, w, suppressFocus) {
487        this.tempLock();
488        if (this.view &amp;&amp; this.view.rendered) {
489            this.view.onHeaderResize(header, w, suppressFocus);
490        }
491    },
492
493    onHeaderClick: function(header, e, t) {
494        this.fireEvent(&quot;headerclick&quot;, this, header, e, t);
495    },
496
497    onHeaderTriggerClick: function(header, e, t) {
498        // generate and cache menu, provide ability to cancel/etc
499        if (this.fireEvent(&quot;headertriggerclick&quot;, this, header, e, t) !== false) {
500            this.showMenuBy(t, header);
501        }
502    },
503
504    showMenuBy: function(t, header) {
505        var menu = this.getMenu(),
506            ascItem  = menu.down('#ascItem'),
507            descItem = menu.down('#descItem'),
508            sortableMth;
509
510        menu.activeHeader = menu.ownerCt = header;
511        menu.setFloatParent(header);
512        // TODO: remove coupling to Header's titleContainer el
513        header.titleContainer.addCls(this.headerOpenCls);
514
515        // enable or disable asc &amp; desc menu items based on header being sortable
516        sortableMth = header.sortable ? 'enable' : 'disable';
517        if (ascItem) {
518            ascItem[sortableMth]();
519        }
520        if (descItem) {
521            descItem[sortableMth]();
522        }
523        menu.showBy(t);
524    },
525
526    // remove the trigger open class when the menu is hidden
527    onMenuDeactivate: function() {
528        var menu = this.getMenu();
529        // TODO: remove coupling to Header's titleContainer el
530        menu.activeHeader.titleContainer.removeCls(this.headerOpenCls);
531    },
532
533    moveHeader: function(fromIdx, toIdx) {
534
535        // An automatically expiring lock
536        this.tempLock();
537        this.onHeaderMoved(this.move(fromIdx, toIdx), fromIdx, toIdx);
538    },
539
540    purgeCache: function() {
541        var me = this;
542        // Delete column cache - column order has changed.
543        delete me.gridDataColumns;
544        delete me.hideableColumns;
545
546        // Menu changes when columns are moved. It will be recreated.
547        if (me.menu) {
548            me.menu.destroy();
549            delete me.menu;
550        }
551    },
552
553    onHeaderMoved: function(header, fromIdx, toIdx) {
554        var me = this,
555            gridSection = me.ownerCt;
556
557        if (gridSection &amp;&amp; gridSection.onHeaderMove) {
558            gridSection.onHeaderMove(me, header, fromIdx, toIdx);
559        }
560        me.fireEvent(&quot;columnmove&quot;, me, header, fromIdx, toIdx);
561    },
562
563<span id='Ext-grid-header-Container-method-getMenu'>    /**
564</span>     * Gets the menu (and will create it if it doesn't already exist)
565     * @private
566     */
567    getMenu: function() {
568        var me = this;
569
570        if (!me.menu) {
571            me.menu = Ext.create('Ext.menu.Menu', {
572                hideOnParentHide: false,  // Persists when owning ColumnHeader is hidden
573                items: me.getMenuItems(),
574                listeners: {
575                    deactivate: me.onMenuDeactivate,
576                    scope: me
577                }
578            });
579            me.setDisabledItems();
580            me.fireEvent('menucreate', me, me.menu);
581        }
582        return me.menu;
583    },
584
585<span id='Ext-grid-header-Container-method-getMenuItems'>    /**
586</span>     * Returns an array of menu items to be placed into the shared menu
587     * across all headers in this header container.
588     * @returns {Array} menuItems
589     */
590    getMenuItems: function() {
591        var me = this,
592            menuItems = [],
593            hideableColumns = me.enableColumnHide ? me.getColumnMenu(me) : null;
594
595        if (me.sortable) {
596            menuItems = [{
597                itemId: 'ascItem',
598                text: me.sortAscText,
599                cls: Ext.baseCSSPrefix + 'hmenu-sort-asc',
600                handler: me.onSortAscClick,
601                scope: me
602            },{
603                itemId: 'descItem',
604                text: me.sortDescText,
605                cls: Ext.baseCSSPrefix + 'hmenu-sort-desc',
606                handler: me.onSortDescClick,
607                scope: me
608            }];
609        }
610        if (hideableColumns &amp;&amp; hideableColumns.length) {
611            menuItems.push('-', {
612                itemId: 'columnItem',
613                text: me.columnsText,
614                cls: Ext.baseCSSPrefix + 'cols-icon',
615                menu: hideableColumns
616            });
617        }
618        return menuItems;
619    },
620
621    // sort asc when clicking on item in menu
622    onSortAscClick: function() {
623        var menu = this.getMenu(),
624            activeHeader = menu.activeHeader;
625
626        activeHeader.setSortState('ASC');
627    },
628
629    // sort desc when clicking on item in menu
630    onSortDescClick: function() {
631        var menu = this.getMenu(),
632            activeHeader = menu.activeHeader;
633
634        activeHeader.setSortState('DESC');
635    },
636
637<span id='Ext-grid-header-Container-method-getColumnMenu'>    /**
638</span>     * Returns an array of menu CheckItems corresponding to all immediate children of the passed Container which have been configured as hideable.
639     */
640    getColumnMenu: function(headerContainer) {
641        var menuItems = [],
642            i = 0,
643            item,
644            items = headerContainer.query('&gt;gridcolumn[hideable]'),
645            itemsLn = items.length,
646            menuItem;
647
648        for (; i &lt; itemsLn; i++) {
649            item = items[i];
650            menuItem = Ext.create('Ext.menu.CheckItem', {
651                text: item.text,
652                checked: !item.hidden,
653                hideOnClick: false,
654                headerId: item.id,
655                menu: item.isGroupHeader ? this.getColumnMenu(item) : undefined,
656                checkHandler: this.onColumnCheckChange,
657                scope: this
658            });
659            if (itemsLn === 1) {
660                menuItem.disabled = true;
661            }
662            menuItems.push(menuItem);
663
664            // If the header is ever destroyed - for instance by dragging out the last remaining sub header,
665            // then the associated menu item must also be destroyed.
666            item.on({
667                destroy: Ext.Function.bind(menuItem.destroy, menuItem)
668            });
669        }
670        return menuItems;
671    },
672
673    onColumnCheckChange: function(checkItem, checked) {
674        var header = Ext.getCmp(checkItem.headerId);
675        header[checked ? 'show' : 'hide']();
676    },
677
678<span id='Ext-grid-header-Container-method-getColumnsForTpl'>    /**
679</span>     * Get the columns used for generating a template via TableChunker.
680     * Returns an array of all columns and their
681     *  - dataIndex
682     *  - align
683     *  - width
684     *  - id
685     *  - columnId - used to create an identifying CSS class
686     *  - cls The tdCls configuration from the Column object
687     *  @private
688     */
689    getColumnsForTpl: function(flushCache) {
690        var cols    = [],
691            headers   = this.getGridColumns(flushCache),
692            headersLn = headers.length,
693            i = 0,
694            header,
695            width;
696
697        for (; i &lt; headersLn; i++) {
698            header = headers[i];
699
700            if (header.hidden || header.up('headercontainer[hidden=true]')) {
701                width = 0;
702            } else {
703                width = header.getDesiredWidth();
704                // IE6 and IE7 bug.
705                // Setting the width of the first TD does not work - ends up with a 1 pixel discrepancy.
706                // We need to increment the passed with in this case.
707                if ((i === 0) &amp;&amp; (Ext.isIE6 || Ext.isIE7)) {
708                    width += 1;
709                }
710            }
711            cols.push({
712                dataIndex: header.dataIndex,
713                align: header.align,
714                width: width,
715                id: header.id,
716                cls: header.tdCls,
717                columnId: header.getItemId()
718            });
719        }
720        return cols;
721    },
722
723<span id='Ext-grid-header-Container-method-getColumnCount'>    /**
724</span>     * Returns the number of &lt;b&gt;grid columns&lt;/b&gt; descended from this HeaderContainer.
725     * Group Columns are HeaderContainers. All grid columns are returned, including hidden ones.
726     */
727    getColumnCount: function() {
728        return this.getGridColumns().length;
729    },
730
731<span id='Ext-grid-header-Container-method-getFullWidth'>    /**
732</span>     * Gets the full width of all columns that are visible.
733     */
734    getFullWidth: function(flushCache) {
735        var fullWidth = 0,
736            headers     = this.getVisibleGridColumns(flushCache),
737            headersLn   = headers.length,
738            i         = 0;
739
740        for (; i &lt; headersLn; i++) {
741            if (!isNaN(headers[i].width)) {
742                // use headers getDesiredWidth if its there
743                if (headers[i].getDesiredWidth) {
744                    fullWidth += headers[i].getDesiredWidth();
745                // if injected a diff cmp use getWidth
746                } else {
747                    fullWidth += headers[i].getWidth();
748                }
749            }
750        }
751        return fullWidth;
752    },
753
754    // invoked internally by a header when not using triStateSorting
755    clearOtherSortStates: function(activeHeader) {
756        var headers   = this.getGridColumns(),
757            headersLn = headers.length,
758            i         = 0,
759            oldSortState;
760
761        for (; i &lt; headersLn; i++) {
762            if (headers[i] !== activeHeader) {
763                oldSortState = headers[i].sortState;
764                // unset the sortstate and dont recurse
765                headers[i].setSortState(null, true);
766                //if (!silent &amp;&amp; oldSortState !== null) {
767                //    this.fireEvent('sortchange', this, headers[i], null);
768                //}
769            }
770        }
771    },
772
773<span id='Ext-grid-header-Container-method-getVisibleGridColumns'>    /**
774</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
775     * level, and does not return &lt;i&gt;grouped&lt;/i&gt; headers which contain sub headers.
776     * @param {Boolean} refreshCache If omitted, the cached set of columns will be returned. Pass true to refresh the cache.
777     * @returns {Array}
778     */
779    getVisibleGridColumns: function(refreshCache) {
780        return Ext.ComponentQuery.query(':not([hidden])', this.getGridColumns(refreshCache));
781    },
782
783<span id='Ext-grid-header-Container-method-getGridColumns'>    /**
784</span>     * Returns an array of all columns which map to Store fields. This goes down to the lowest column header
785     * level, and does not return &lt;i&gt;grouped&lt;/i&gt; headers which contain sub headers.
786     * @param {Boolean} refreshCache If omitted, the cached set of columns will be returned. Pass true to refresh the cache.
787     * @returns {Array}
788     */
789    getGridColumns: function(refreshCache) {
790        var me = this,
791            result = refreshCache ? null : me.gridDataColumns;
792
793        // Not already got the column cache, so collect the base columns
794        if (!result) {
795            me.gridDataColumns = result = [];
796            me.cascade(function(c) {
797                if ((c !== me) &amp;&amp; !c.isGroupHeader) {
798                    result.push(c);
799                }
800            });
801        }
802
803        return result;
804    },
805
806<span id='Ext-grid-header-Container-method-getHideableColumns'>    /**
807</span>     * @private
808     * For use by column headers in determining whether there are any hideable columns when deciding whether or not
809     * the header menu should be disabled.
810     */
811    getHideableColumns: function(refreshCache) {
812        var me = this,
813            result = refreshCache ? null : me.hideableColumns;
814
815        if (!result) {
816            result = me.hideableColumns = me.query('[hideable]');
817        }
818        return result;
819    },
820
821<span id='Ext-grid-header-Container-method-getHeaderIndex'>    /**
822</span>     * Get the index of a leaf level header regardless of what the nesting
823     * structure is.
824     */
825    getHeaderIndex: function(header) {
826        var columns = this.getGridColumns();
827        return Ext.Array.indexOf(columns, header);
828    },
829
830<span id='Ext-grid-header-Container-method-getHeaderAtIndex'>    /**
831</span>     * Get a leaf level header by index regardless of what the nesting
832     * structure is.
833     */
834    getHeaderAtIndex: function(index) {
835        var columns = this.getGridColumns();
836        return columns[index];
837    },
838
839<span id='Ext-grid-header-Container-method-prepareData'>    /**
840</span>     * Maps the record data to base it on the header id's.
841     * This correlates to the markup/template generated by
842     * TableChunker.
843     */
844    prepareData: function(data, rowIdx, record, view, panel) {
845        var obj       = {},
846            headers   = this.gridDataColumns || this.getGridColumns(),
847            headersLn = headers.length,
848            colIdx    = 0,
849            header,
850            headerId,
851            renderer,
852            value,
853            metaData,
854            store = panel.store;
855
856        for (; colIdx &lt; headersLn; colIdx++) {
857            metaData = {
858                tdCls: '',
859                style: ''
860            };
861            header = headers[colIdx];
862            headerId = header.id;
863            renderer = header.renderer;
864            value = data[header.dataIndex];
865
866            // When specifying a renderer as a string, it always resolves
867            // to Ext.util.Format
868            if (typeof renderer === &quot;string&quot;) {
869                header.renderer = renderer = Ext.util.Format[renderer];
870            }
871
872            if (typeof renderer === &quot;function&quot;) {
873                value = renderer.call(
874                    header.scope || this.ownerCt,
875                    value,
876                    // metadata per cell passing an obj by reference so that
877                    // it can be manipulated inside the renderer
878                    metaData,
879                    record,
880                    rowIdx,
881                    colIdx,
882                    store,
883                    view
884                );
885            }
886
887            // &lt;debug&gt;
888            if (metaData.css) {
889                // This warning attribute is used by the compat layer
890                obj.cssWarning = true;
891                metaData.tdCls = metaData.css;
892                delete metaData.css;
893            }
894            // &lt;/debug&gt;
895
896            obj[headerId+'-modified'] = record.isModified(header.dataIndex) ? Ext.baseCSSPrefix + 'grid-dirty-cell' : '';
897            obj[headerId+'-tdCls'] = metaData.tdCls;
898            obj[headerId+'-tdAttr'] = metaData.tdAttr;
899            obj[headerId+'-style'] = metaData.style;
900            if (value === undefined || value === null || value === '') {
901                value = '&amp;#160;';
902            }
903            obj[headerId] = value;
904        }
905        return obj;
906    },
907
908    expandToFit: function(header) {
909        if (this.view) {
910            this.view.expandToFit(header);
911        }
912    }
913});
914</pre>
915</body>
916</html>