| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999 | <!DOCTYPE html><html><head>  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  <title>The source code</title>  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>  <style type="text/css">    .highlight { display: block; background-color: #ddd; }  </style>  <script type="text/javascript">    function highlight() {      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";    }  </script></head><body onload="prettyPrint(); highlight();">  <pre class="prettyprint lang-js"><span id='Ext-grid-header-Container'>/**</span> * Container which holds headers and is docked at the top or bottom of a TablePanel. * The HeaderContainer drives resizing/moving/hiding of columns within the TableView. * As headers are hidden, moved or resized the headercontainer is responsible for * triggering changes within the view. */Ext.define('Ext.grid.header.Container', {    extend: 'Ext.container.Container',    requires: [        'Ext.grid.ColumnLayout',        'Ext.grid.plugin.HeaderResizer',        'Ext.grid.plugin.HeaderReorderer'    ],    uses: [        'Ext.grid.column.Column',        'Ext.menu.Menu',        'Ext.menu.CheckItem',        'Ext.menu.Separator'    ],    border: true,    alias: 'widget.headercontainer',    baseCls: Ext.baseCSSPrefix + 'grid-header-ct',    dock: 'top',<span id='Ext-grid-header-Container-cfg-weight'>    /**</span>     * @cfg {Number} weight     * HeaderContainer overrides the default weight of 0 for all docked items to 100.     * This is so that it has more priority over things like toolbars.     */    weight: 100,    defaultType: 'gridcolumn',        detachOnRemove: false,<span id='Ext-grid-header-Container-cfg-defaultWidth'>    /**</span>     * @cfg {Number} defaultWidth     * Width of the header if no width or flex is specified.     */    defaultWidth: 100,    <span id='Ext-grid-header-Container-cfg-sealed'>    /**</span>     * @cfg {Boolean} [sealed=false]     * Specify as `true` to constrain column dragging so that a column cannot be dragged into or out of this column.     *     * **Note that this config is only valid for column headers which contain child column headers, eg:**     *     {     *         sealed: true     *         text: 'ExtJS',     *         columns: [{     *             text: '3.0.4',     *             dataIndex: 'ext304'     *         }, {     *             text: '4.1.0',     *             dataIndex: 'ext410'     *         }     *     }     *     */    //<locale>    sortAscText: 'Sort Ascending',    //</locale>    //<locale>    sortDescText: 'Sort Descending',    //</locale>    //<locale>    sortClearText: 'Clear Sort',    //</locale>    //<locale>    columnsText: 'Columns',    //</locale>    headerOpenCls: Ext.baseCSSPrefix + 'column-header-open',    // private; will probably be removed by 4.0    triStateSort: false,    ddLock: false,    dragging: false,<span id='Ext-grid-header-Container-property-isGroupHeader'>    /**</span>     * @property {Boolean} isGroupHeader     * True if this HeaderContainer is in fact a group header which contains sub headers.     */<span id='Ext-grid-header-Container-cfg-sortable'>    /**</span>     * @cfg {Boolean} sortable     * Provides the default sortable state for all Headers within this HeaderContainer.     * Also turns on or off the menus in the HeaderContainer. Note that the menu is     * shared across every header and therefore turning it off will remove the menu     * items for every header.     */    sortable: true,    initComponent: function() {        var me = this;        me.headerCounter = 0;        me.plugins = me.plugins || [];        // TODO: Pass in configurations to turn on/off dynamic        //       resizing and disable resizing all together        // Only set up a Resizer and Reorderer for the topmost HeaderContainer.        // Nested Group Headers are themselves HeaderContainers        if (!me.isHeader) {            if (me.enableColumnResize) {                me.resizer = new Ext.grid.plugin.HeaderResizer();                me.plugins.push(me.resizer);            }            if (me.enableColumnMove) {                me.reorderer = new Ext.grid.plugin.HeaderReorderer();                me.plugins.push(me.reorderer);            }        }        // Base headers do not need a box layout        if (me.isHeader && !me.items) {            me.layout = me.layout || 'auto';        }        // HeaderContainer and Group header needs a gridcolumn layout.        else {            me.layout = Ext.apply({                type: 'gridcolumn',                align: 'stretchmax'            }, me.initialConfig.layout);        }        me.defaults = me.defaults || {};        Ext.applyIf(me.defaults, {            triStateSort: me.triStateSort,            sortable: me.sortable        });                me.menuTask = new Ext.util.DelayedTask(me.updateMenuDisabledState, me);        me.callParent();        me.addEvents(<span id='Ext-grid-header-Container-event-columnresize'>            /**</span>             * @event columnresize             * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.             * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition             * @param {Number} width             */            'columnresize',<span id='Ext-grid-header-Container-event-headerclick'>            /**</span>             * @event headerclick             * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.             * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition             * @param {Ext.EventObject} e             * @param {HTMLElement} t             */            'headerclick',<span id='Ext-grid-header-Container-event-headertriggerclick'>            /**</span>             * @event headertriggerclick             * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.             * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition             * @param {Ext.EventObject} e             * @param {HTMLElement} t             */            'headertriggerclick',<span id='Ext-grid-header-Container-event-columnmove'>            /**</span>             * @event columnmove             * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.             * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition             * @param {Number} fromIdx             * @param {Number} toIdx             */            'columnmove',<span id='Ext-grid-header-Container-event-columnhide'>            /**</span>             * @event columnhide             * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.             * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition             */            'columnhide',<span id='Ext-grid-header-Container-event-columnshow'>            /**</span>             * @event columnshow             * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.             * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition             */            'columnshow',<span id='Ext-grid-header-Container-event-sortchange'>            /**</span>             * @event sortchange             * @param {Ext.grid.header.Container} ct The grid's header Container which encapsulates all column headers.             * @param {Ext.grid.column.Column} column The Column header Component which provides the column definition             * @param {String} direction             */            'sortchange',<span id='Ext-grid-header-Container-event-menucreate'>            /**</span>             * @event menucreate             * Fired immediately after the column header menu is created.             * @param {Ext.grid.header.Container} ct This instance             * @param {Ext.menu.Menu} menu The Menu that was created             */            'menucreate'        );    },    onDestroy: function() {        var me = this;                me.menuTask.cancel();        Ext.destroy(me.resizer, me.reorderer);        me.callParent();    },    applyColumnsState: function(columns) {        if (!columns || !columns.length) {            return;        }        var me     = this,            items  = me.items.items,            count  = items.length,            i      = 0,            length = columns.length,            c, col, columnState, index;        for (c = 0; c < length; c++) {            columnState = columns[c];            for (index = count; index--; ) {                col = items[index];                if (col.getStateId && col.getStateId() == columnState.id) {                    // If a column in the new grid matches up with a saved state...                    // Ensure that the column is restored to the state order.                    // i is incremented upon every column match, so all persistent                    // columns are ordered before any new columns.                    if (i !== index) {                        me.moveHeader(index, i);                    }                    if (col.applyColumnState) {                        col.applyColumnState(columnState);                    }                    ++i;                    break;                }            }        }    },    getColumnsState: function () {        var me = this,            columns = [],            state;        me.items.each(function (col) {            state = col.getColumnState && col.getColumnState();            if (state) {                columns.push(state);            }        });        return columns;    },    // Invalidate column cache on add    // We cannot refresh the View on every add because this method is called    // when the HeaderDropZone moves Headers around, that will also refresh the view    onAdd: function(c) {        var me = this,            headerCt = me.isHeader ? me.getOwnerHeaderCt() : me;        if (!c.headerId) {            c.headerId = c.initialConfig.id || Ext.id(null, 'header-');        }        if (!c.stateId) {            // This was the headerId generated in 4.0, so to preserve saved state, we now            // assign a default stateId in that same manner. The stateId's of a column are            // not global at the stateProvider, but are local to the grid state data. The            // headerId should still follow our standard naming convention.            c.stateId = c.initialConfig.id || ('h' + (++me.headerCounter));        }        //<debug warn>        if (Ext.global.console && Ext.global.console.warn) {            if (!me._usedIDs) {                me._usedIDs = {};            }            if (me._usedIDs[c.headerId]) {                Ext.global.console.warn(this.$className, 'attempted to reuse an existing id', c.headerId);            }            me._usedIDs[c.headerId] = true;        }        //</debug>        me.callParent(arguments);        // Upon add of any column we need to purge the *HeaderContainer's* cache of leaf view columns.        if (headerCt) {            headerCt.purgeCache();        }    },    // Invalidate column cache on remove    // We cannot refresh the View on every remove because this method is called    // when the HeaderDropZone moves Headers around, that will also refresh the view    onRemove: function(c) {        var me = this,            headerCt = me.isHeader ? me.getOwnerHeaderCt() : me;        me.callParent(arguments);                //<debug warn>        if (!me._usedIDs) {            me._usedIDs = {};        }        delete me._usedIDs[c.headerId];        //</debug>        // Upon removal of any column we need to purge the *HeaderContainer's* cache of leaf view columns.        if (headerCt) {            me.purgeCache();        }    },    // @private    applyDefaults: function(config) {        var ret;         /*         * Ensure header.Container defaults don't get applied to a RowNumberer          * if an xtype is supplied. This isn't an ideal solution however it's          * much more likely that a RowNumberer with no options will be created,          * wanting to use the defaults specified on the class as opposed to          * those setup on the Container.         */        if (config && !config.isComponent && config.xtype == 'rownumberer') {            ret = config;        } else {            ret = this.callParent(arguments);                        // Apply default width unless it's a group header (in which case it must be left to shrinkwrap), or it's flexed            if (!config.isGroupHeader && !('width' in ret) && !ret.flex) {                ret.width = this.defaultWidth;            }        }        return ret;    },    afterRender: function() {        this.callParent();        this.setSortState();            },        setSortState: function(){        var store   = this.up('[store]').store,            // grab the first sorter, since there may also be groupers            // in this collection            first = store.getFirstSorter(),            hd;        if (first) {            hd = this.down('gridcolumn[dataIndex=' + first.property  +']');            if (hd) {                hd.setSortState(first.direction, false, true);            }        } else {            this.clearOtherSortStates(null);        }    },        getHeaderMenu: function(){        var menu = this.getMenu(),            item;                    if (menu) {            item = menu.child('#columnItem');            if (item) {                return item.menu;            }        }           return null;     },        onHeaderVisibilityChange: function(header, visible){        var me = this,            menu = me.getHeaderMenu(),            item;                if (menu) {            // If the header was hidden programmatically, sync the Menu state            item = me.getMenuItemForHeader(menu, header);            if (item) {                item.setChecked(visible, true);            }            // delay this since the headers may fire a number of times if we're hiding/showing groups            me.menuTask.delay(50);        }    },    <span id='Ext-grid-header-Container-method-getLeafMenuItems'>    /**</span>     * @private     * Gets all "leaf" menu nodes and returns the checked count for those leaves.     * Only includes columns that are hideable via the menu     */    getLeafMenuItems: function() {        var me = this,            columns = me.getGridColumns(),            items = [],            i = 0,            count = 0,            len = columns.length,            menu = me.getMenu(),            item;        for (; i < len; ++i) {            item = columns[i];            if (item.hideable) {                item = me.getMenuItemForHeader(menu, item);                if (item) {                    items.push(item);                    if (item.checked) {                        ++count;                    }                }            } else if (!item.hidden && !item.menuDisabled) {                ++count;            }        }        return {            items: items,            checkedCount: count            };    },        updateMenuDisabledState: function(){        var me = this,            result = me.getLeafMenuItems(),            total = result.checkedCount,            items = result.items,            len = items.length,            i = 0,            rootItem = me.getMenu().child('#columnItem');                    if (total <= 1) {            // only one column visible, prevent hiding of the remaining item            me.disableMenuItems(rootItem, Ext.ComponentQuery.query('[checked=true]', items)[0]);        } else {            // at least 2 visible, set the state appropriately            for (; i < len; ++i) {                me.setMenuItemState(total, rootItem, items[i]);            }        }    },        disableMenuItems: function(rootItem, item){        while (item && item != rootItem) {            item.disableCheckChange();            item = item.parentMenu.ownerItem;        }    },        setMenuItemState: function(total, rootItem, item){        var parentMenu,            checkedChildren;                    while (item && item != rootItem) {            parentMenu = item.parentMenu;            checkedChildren = item.parentMenu.query('[checked=true]:not([menu])').length;            item.enableCheckChange();            item = parentMenu.ownerItem;            if (checkedChildren === total) {                // contains all the checked children, jump out the item and all parents                break;            }        }                // while we're not at the top, disable from the current item up        this.disableMenuItems(rootItem, item);    },        getMenuItemForHeader: function(menu, header){        return header ? menu.down('menucheckitem[headerId=' + header.id + ']') : null;    },    onHeaderShow: function(header) {        // Pass up to the GridSection        var me = this,            gridSection = me.ownerCt;        me.onHeaderVisibilityChange(header, true);        // Only update the grid UI when we are notified about base level Header shows;        // Group header shows just cause a layout of the HeaderContainer        if (!header.isGroupHeader) {            if (gridSection) {                gridSection.onHeaderShow(me, header);            }        }        me.fireEvent('columnshow', me, header);    },    onHeaderHide: function(header) {        // Pass up to the GridSection        var me = this,            gridSection = me.ownerCt;        me.onHeaderVisibilityChange(header, false);        // Only update the UI when we are notified about base level Header hides;        if (!header.isGroupHeader) {            if (gridSection) {                gridSection.onHeaderHide(me, header);            }        }        me.fireEvent('columnhide', me, header);    },<span id='Ext-grid-header-Container-method-tempLock'>    /**</span>     * Temporarily lock the headerCt. This makes it so that clicking on headers     * don't trigger actions like sorting or opening of the header menu. This is     * done because extraneous events may be fired on the headers after interacting     * with a drag drop operation.     * @private     */    tempLock: function() {        this.ddLock = true;        Ext.Function.defer(function() {            this.ddLock = false;        }, 200, this);    },    onHeaderResize: function(header, w, suppressFocus) {        var me = this,            view = me.view,            gridSection = me.ownerCt;        // Do not react to header sizing during initial Panel layout when there is no view content to size.        if (view && view.table.dom) {            me.tempLock();            if (gridSection) {                gridSection.onHeaderResize(me, header, w);            }        }        me.fireEvent('columnresize', this, header, w);    },    onHeaderClick: function(header, e, t) {        header.fireEvent('headerclick', this, header, e, t);        this.fireEvent("headerclick", this, header, e, t);    },    onHeaderTriggerClick: function(header, e, t) {        // generate and cache menu, provide ability to cancel/etc        var me = this;        if (header.fireEvent('headertriggerclick', me, header, e, t) !== false && me.fireEvent("headertriggerclick", me, header, e, t) !== false) {            me.showMenuBy(t, header);        }    },    showMenuBy: function(t, header) {        var menu = this.getMenu(),            ascItem  = menu.down('#ascItem'),            descItem = menu.down('#descItem'),            sortableMth;        menu.activeHeader = menu.ownerCt = header;        menu.setFloatParent(header);        // TODO: remove coupling to Header's titleContainer el        header.titleEl.addCls(this.headerOpenCls);        // enable or disable asc & desc menu items based on header being sortable        sortableMth = header.sortable ? 'enable' : 'disable';        if (ascItem) {            ascItem[sortableMth]();        }        if (descItem) {            descItem[sortableMth]();        }        menu.showBy(t);    },    // remove the trigger open class when the menu is hidden    onMenuDeactivate: function() {        var menu = this.getMenu();        // TODO: remove coupling to Header's titleContainer el        menu.activeHeader.titleEl.removeCls(this.headerOpenCls);    },    moveHeader: function(fromIdx, toIdx) {        // An automatically expiring lock        this.tempLock();        this.onHeaderMoved(this.move(fromIdx, toIdx), 1, fromIdx, toIdx);    },    purgeCache: function() {        var me = this;        // Delete column cache - column order has changed.        delete me.gridDataColumns;        delete me.hideableColumns;        // Menu changes when columns are moved. It will be recreated.        if (me.menu) {            // Must hide before destroy so that trigger el is deactivated            me.menu.hide();            me.menu.destroy();            delete me.menu;        }    },    onHeaderMoved: function(header, colsToMove, fromIdx, toIdx) {        var me = this,            gridSection = me.ownerCt;        if (gridSection && gridSection.onHeaderMove) {            gridSection.onHeaderMove(me, header, colsToMove, fromIdx, toIdx);        }        me.fireEvent("columnmove", me, header, fromIdx, toIdx);    },<span id='Ext-grid-header-Container-method-getMenu'>    /**</span>     * Gets the menu (and will create it if it doesn't already exist)     * @private     */    getMenu: function() {        var me = this;        if (!me.menu) {            me.menu = new Ext.menu.Menu({                hideOnParentHide: false,  // Persists when owning ColumnHeader is hidden                items: me.getMenuItems(),                listeners: {                    deactivate: me.onMenuDeactivate,                    scope: me                }            });            me.updateMenuDisabledState();            me.fireEvent('menucreate', me, me.menu);        }        return me.menu;    },<span id='Ext-grid-header-Container-method-getMenuItems'>    /**</span>     * Returns an array of menu items to be placed into the shared menu     * across all headers in this header container.     * @returns {Array} menuItems     */    getMenuItems: function() {        var me = this,            menuItems = [],            hideableColumns = me.enableColumnHide ? me.getColumnMenu(me) : null;        if (me.sortable) {            menuItems = [{                itemId: 'ascItem',                text: me.sortAscText,                cls: Ext.baseCSSPrefix + 'hmenu-sort-asc',                handler: me.onSortAscClick,                scope: me            },{                itemId: 'descItem',                text: me.sortDescText,                cls: Ext.baseCSSPrefix + 'hmenu-sort-desc',                handler: me.onSortDescClick,                scope: me            }];        }        if (hideableColumns && hideableColumns.length) {            menuItems.push('-', {                itemId: 'columnItem',                text: me.columnsText,                cls: Ext.baseCSSPrefix + 'cols-icon',                menu: hideableColumns            });        }        return menuItems;    },    // sort asc when clicking on item in menu    onSortAscClick: function() {        var menu = this.getMenu(),            activeHeader = menu.activeHeader;        activeHeader.setSortState('ASC');    },    // sort desc when clicking on item in menu    onSortDescClick: function() {        var menu = this.getMenu(),            activeHeader = menu.activeHeader;        activeHeader.setSortState('DESC');    },<span id='Ext-grid-header-Container-method-getColumnMenu'>    /**</span>     * Returns an array of menu CheckItems corresponding to all immediate children     * of the passed Container which have been configured as hideable.     */    getColumnMenu: function(headerContainer) {        var menuItems = [],            i = 0,            item,            items = headerContainer.query('>gridcolumn[hideable]'),            itemsLn = items.length,            menuItem;        for (; i < itemsLn; i++) {            item = items[i];            menuItem = new Ext.menu.CheckItem({                text: item.menuText || item.text,                checked: !item.hidden,                hideOnClick: false,                headerId: item.id,                menu: item.isGroupHeader ? this.getColumnMenu(item) : undefined,                checkHandler: this.onColumnCheckChange,                scope: this            });            menuItems.push(menuItem);            // If the header is ever destroyed - for instance by dragging out the last remaining sub header,            // then the associated menu item must also be destroyed.            item.on({                destroy: Ext.Function.bind(menuItem.destroy, menuItem)            });        }        return menuItems;    },    onColumnCheckChange: function(checkItem, checked) {        var header = Ext.getCmp(checkItem.headerId);        header[checked ? 'show' : 'hide']();    },<span id='Ext-grid-header-Container-method-getColumnsForTpl'>    /**</span>     * Get the columns used for generating a template via TableChunker.     * Returns an array of all columns and their     *     *  - dataIndex     *  - align     *  - width     *  - id     *  - columnId - used to create an identifying CSS class     *  - cls The tdCls configuration from the Column object     *     * @private     */    getColumnsForTpl: function(flushCache) {        var cols    = [],            headers   = this.getGridColumns(flushCache),            headersLn = headers.length,            i = 0,            header,            width;        for (; i < headersLn; i++) {            header = headers[i];            if (header.hidden || header.up('headercontainer[hidden=true]')) {                width = 0;            } else {                width = header.getDesiredWidth();            }            cols.push({                dataIndex: header.dataIndex,                align: header.align,                width: width,                id: header.id,                cls: header.tdCls,                columnId: header.getItemId()            });        }        return cols;    },<span id='Ext-grid-header-Container-method-getColumnCount'>    /**</span>     * Returns the number of <b>grid columns</b> descended from this HeaderContainer.     * Group Columns are HeaderContainers. All grid columns are returned, including hidden ones.     */    getColumnCount: function() {        return this.getGridColumns().length;    },<span id='Ext-grid-header-Container-method-getFullWidth'>    /**</span>     * Gets the full width of all columns that are visible.     */    getFullWidth: function(flushCache) {        var fullWidth = 0,            headers = this.getVisibleGridColumns(flushCache),            headersLn = headers.length,            i = 0,            header;                   for (; i < headersLn; i++) {            header = headers[i];            // use headers getDesiredWidth if its there            if (header.getDesiredWidth) {                fullWidth += header.getDesiredWidth() || 0;            // if injected a diff cmp use getWidth            } else {                fullWidth += header.getWidth();            }        }        return fullWidth;    },    // invoked internally by a header when not using triStateSorting    clearOtherSortStates: function(activeHeader) {        var headers   = this.getGridColumns(),            headersLn = headers.length,            i         = 0;        for (; i < headersLn; i++) {            if (headers[i] !== activeHeader) {                // unset the sortstate and dont recurse                headers[i].setSortState(null, true);            }        }    },<span id='Ext-grid-header-Container-method-getVisibleGridColumns'>    /**</span>     * Returns an array of the **visible** columns in the grid. This goes down to the lowest column header     * level, and does not return **grouped** headers which contain sub headers.     * @param {Boolean} refreshCache If omitted, the cached set of columns will be returned. Pass true to refresh the cache.     * @returns {Array}     */    getVisibleGridColumns: function(refreshCache) {        return Ext.ComponentQuery.query(':not([hidden])', this.getGridColumns(refreshCache));    }, <span id='Ext-grid-header-Container-method-getGridColumns'>    /**</span>     * Returns an array of all columns which map to Store fields. This goes down to the lowest column header     * level, and does not return **grouped** headers which contain sub headers.     * @param {Boolean} refreshCache If omitted, the cached set of columns will be returned. Pass true to refresh the cache.     * @returns {Array}     */    getGridColumns: function(refreshCache) {        var me = this,            result = refreshCache ? null : me.gridDataColumns;        // Not already got the column cache, so collect the base columns        if (!result) {            me.gridDataColumns = result = [];            me.cascade(function(c) {                if ((c !== me) && !c.isGroupHeader) {                    result.push(c);                }            });        }        return result;    },<span id='Ext-grid-header-Container-method-getHideableColumns'>    /**</span>     * @private     * For use by column headers in determining whether there are any hideable columns when deciding whether or not     * the header menu should be disabled.     */    getHideableColumns: function(refreshCache) {        var me = this,            result = refreshCache ? null : me.hideableColumns;        if (!result) {            result = me.hideableColumns = me.query('[hideable]');        }        return result;    },<span id='Ext-grid-header-Container-method-getHeaderIndex'>    /**</span>     * Returns the index of a leaf level header regardless of what the nesting     * structure is.     *     * If a group header is passed, the index of the first leaf level heder within it is returned.     *     * @param {Ext.grid.column.Column} header The header to find the index of     * @return {Number} The index of the specified column header     */    getHeaderIndex: function(header) {        // If we are being asked the index of a group header, find the first leaf header node, and return the index of that        if (header.isGroupHeader) {            header = header.down(':not([isgroupHeader])');        }        return Ext.Array.indexOf(this.getGridColumns(), header);    },<span id='Ext-grid-header-Container-method-getHeaderAtIndex'>    /**</span>     * Get a leaf level header by index regardless of what the nesting     * structure is.     * @param {Number} The column index for which to retrieve the column.     */    getHeaderAtIndex: function(index) {        var columns = this.getGridColumns();        return columns.length ? columns[index] : null;    },<span id='Ext-grid-header-Container-method-getVisibleHeaderClosestToIndex'>    /**</span>     * When passed a column index, returns the closet *visible* column to that. If the column at the passed index is visible,     * that is returned. If it is hidden, either the next visible, or the previous visible column is returned.     * @param {Number} index Position at which to find the closest visible column.     */    getVisibleHeaderClosestToIndex: function(index) {        var result = this.getHeaderAtIndex(index);        if (result && result.hidden) {            result = result.next(':not([hidden])') || result.prev(':not([hidden])');        }        return result;    },<span id='Ext-grid-header-Container-method-prepareData'>    /**</span>     * Maps the record data to base it on the header id's.     * This correlates to the markup/template generated by     * TableChunker.     */    prepareData: function(data, rowIdx, record, view, panel) {        var me        = this,            obj       = {},            headers   = me.gridDataColumns || me.getGridColumns(),            headersLn = headers.length,            colIdx    = 0,            header,            headerId,            renderer,            value,            metaData,            store = panel.store;        for (; colIdx < headersLn; colIdx++) {            metaData = {                tdCls: '',                style: ''            };            header = headers[colIdx];            headerId = header.id;            renderer = header.renderer;            value = data[header.dataIndex];            if (typeof renderer == "function") {                value = renderer.call(                    header.scope || me.ownerCt,                    value,                    // metadata per cell passing an obj by reference so that                    // it can be manipulated inside the renderer                    metaData,                    record,                    rowIdx,                    colIdx,                    store,                    view                );            }            // <debug>            if (metaData.css) {                // This warning attribute is used by the compat layer                obj.cssWarning = true;                metaData.tdCls = metaData.css;                delete metaData.css;            }            // </debug>            if (me.markDirty) {                obj[headerId + '-modified'] = record.isModified(header.dataIndex) ? Ext.baseCSSPrefix + 'grid-dirty-cell' : '';            }            obj[headerId+'-tdCls'] = metaData.tdCls;            obj[headerId+'-tdAttr'] = metaData.tdAttr;            obj[headerId+'-style'] = metaData.style;            if (typeof value === 'undefined' || value === null || value === '') {                value = header.emptyCellText;            }            obj[headerId] = value;        }        return obj;    },    expandToFit: function(header) {        var view = this.view;        if (view) {            view.expandToFit(header);        }    }});</pre></body></html>
 |