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; }
11 <script type="text/javascript">
12 function highlight() {
13 document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
17 <body onload="prettyPrint(); highlight();">
18 <pre class="prettyprint lang-js"><span id='Ext-view-Table'>/**
19 </span> * This class encapsulates the user interface for a tabular data set.
20 * It acts as a centralized manager for controlling the various interface
21 * elements of the view. This includes handling events, such as row and cell
22 * level based DOM events. It also reacts to events from the underlying {@link Ext.selection.Model}
23 * to provide visual feedback to the user.
25 * This class does not provide ways to manipulate the underlying data of the configured
26 * {@link Ext.data.Store}.
28 * This is the base class for both {@link Ext.grid.View} and {@link Ext.tree.View} and is not
29 * to be used directly.
31 Ext.define('Ext.view.Table', {
32 extend: 'Ext.view.View',
33 alias: 'widget.tableview',
35 'Ext.view.TableChunker',
36 'Ext.util.DelayedTask',
37 'Ext.util.MixedCollection'
40 baseCls: Ext.baseCSSPrefix + 'grid-view',
43 itemSelector: '.' + Ext.baseCSSPrefix + 'grid-row',
45 cellSelector: '.' + Ext.baseCSSPrefix + 'grid-cell',
47 selectedItemCls: Ext.baseCSSPrefix + 'grid-row-selected',
48 selectedCellCls: Ext.baseCSSPrefix + 'grid-cell-selected',
49 focusedItemCls: Ext.baseCSSPrefix + 'grid-row-focused',
50 overItemCls: Ext.baseCSSPrefix + 'grid-row-over',
51 altRowCls: Ext.baseCSSPrefix + 'grid-row-alt',
52 rowClsRe: /(?:^|\s*)grid-row-(first|last|alt)(?:\s+|$)/g,
53 cellRe: new RegExp('x-grid-cell-([^\\s]+) ', ''),
58 <span id='Ext-view-Table-method-getRowClass'> /**
59 </span> * Override this function to apply custom CSS classes to rows during rendering. This function should return the
60 * CSS class name (or empty string '' for none) that will be added to the row's wrapping div. To apply multiple
61 * class names, simply return them space-delimited within the string (e.g. 'my-class another-class').
65 * getRowClass: function(record, rowIndex, rowParams, store){
66 * return record.get("valid") ? "row-valid" : "row-error";
70 * @param {Ext.data.Model} record The record corresponding to the current row.
71 * @param {Number} index The row index.
72 * @param {Object} rowParams **DEPRECATED.** For row body use the
73 * {@link Ext.grid.feature.RowBody#getAdditionalData getAdditionalData} method of the rowbody feature.
74 * @param {Ext.data.Store} store The store this grid is bound to
75 * @return {String} a CSS class name to add to the row.
80 initComponent: function() {
84 me.selModel.view = me;
85 me.headerCt.view = me;
87 me.tpl = '<div></div>';
97 // * @param {Ext.data.Model} record
98 // * @param {HTMLElement} row
99 // * @param {Number} rowIdx
105 // scroll to top of the grid when store loads
106 onStoreLoad: function(){
109 if (me.invalidateScrollerOnRefresh) {
111 if (!me.scrollToTopTask) {
112 me.scrollToTopTask = Ext.create('Ext.util.DelayedTask', me.scrollToTop, me);
114 me.scrollToTopTask.delay(1);
121 // scroll the view to the top
122 scrollToTop: Ext.emptyFn,
124 <span id='Ext-view-Table-method-addElListener'> /**
125 </span> * Add a listener to the main view element. It will be destroyed with the view.
128 addElListener: function(eventName, fn, scope){
129 this.mon(this, eventName, fn, scope, {
134 <span id='Ext-view-Table-method-getGridColumns'> /**
135 </span> * Get the columns used for generating a template via TableChunker.
136 * See {@link Ext.grid.header.Container#getGridColumns}.
139 getGridColumns: function() {
140 return this.headerCt.getGridColumns();
143 <span id='Ext-view-Table-method-getHeaderAtIndex'> /**
144 </span> * Get a leaf level header by index regardless of what the nesting
147 * @param {Number} index The index
149 getHeaderAtIndex: function(index) {
150 return this.headerCt.getHeaderAtIndex(index);
153 <span id='Ext-view-Table-method-getCell'> /**
154 </span> * Get the cell (td) for a particular record and column.
155 * @param {Ext.data.Model} record
156 * @param {Ext.grid.column.Column} column
159 getCell: function(record, column) {
160 var row = this.getNode(record);
161 return Ext.fly(row).down(column.getCellSelector());
164 <span id='Ext-view-Table-method-getFeature'> /**
165 </span> * Get a reference to a feature
166 * @param {String} id The id of the feature
167 * @return {Ext.grid.feature.Feature} The feature. Undefined if not found
169 getFeature: function(id) {
170 var features = this.featuresMC;
172 return features.get(id);
176 <span id='Ext-view-Table-method-initFeatures'> /**
177 </span> * Initializes each feature and bind it to this view.
180 initFeatures: function() {
186 me.features = me.features || [];
187 features = me.features;
188 len = features.length;
190 me.featuresMC = Ext.create('Ext.util.MixedCollection');
191 for (; i < len; i++) {
192 // ensure feature hasnt already been instantiated
193 if (!features[i].isFeature) {
194 features[i] = Ext.create('feature.' + features[i].ftype, features[i]);
196 // inject a reference to view
197 features[i].view = me;
198 me.featuresMC.add(features[i]);
202 <span id='Ext-view-Table-method-attachEventsForFeatures'> /**
203 </span> * Gives features an injection point to attach events to the markup that
204 * has been created for this view.
207 attachEventsForFeatures: function() {
208 var features = this.features,
209 ln = features.length,
212 for (; i < ln; i++) {
213 if (features[i].isFeature) {
214 features[i].attachEvents();
219 afterRender: function() {
224 scroll: me.fireBodyScroll,
227 me.el.unselectable();
228 me.attachEventsForFeatures();
231 fireBodyScroll: function(e, t) {
232 this.fireEvent('bodyscroll', e, t);
235 // TODO: Refactor headerCt dependency here to colModel
236 <span id='Ext-view-Table-method-prepareData'> /**
237 </span> * Uses the headerCt to transform data from dataIndex keys in a record to
238 * headerId keys in each header and then run them through each feature to
239 * get additional data for variables they have injected into the view template.
242 prepareData: function(data, idx, record) {
244 orig = me.headerCt.prepareData(data, idx, record, me, me.ownerCt),
245 features = me.features,
246 ln = features.length,
250 for (; i < ln; i++) {
251 feature = features[i];
252 if (feature.isFeature) {
253 Ext.apply(orig, feature.getAdditionalData(data, idx, record, orig, me));
260 // TODO: Refactor headerCt dependency here to colModel
261 collectData: function(records, startIndex) {
262 var preppedRecords = this.callParent(arguments),
263 headerCt = this.headerCt,
264 fullWidth = headerCt.getFullWidth(),
265 features = this.features,
266 ln = features.length,
268 rows: preppedRecords,
277 jln = preppedRecords.length;
278 // process row classes, rowParams has been deprecated and has been moved
279 // to the individual features that implement the behavior.
280 if (this.getRowClass) {
281 for (; j < jln; j++) {
283 preppedRecords[j]['rowCls'] = this.getRowClass(records[j], j, rowParams, this.store);
286 Ext.Error.raise("The getRowClass alt property is no longer supported.");
288 if (rowParams.tstyle) {
289 Ext.Error.raise("The getRowClass tstyle property is no longer supported.");
291 if (rowParams.cells) {
292 Ext.Error.raise("The getRowClass cells property is no longer supported.");
294 if (rowParams.body) {
295 Ext.Error.raise("The getRowClass body property is no longer supported. Use the getAdditionalData method of the rowbody feature.");
297 if (rowParams.bodyStyle) {
298 Ext.Error.raise("The getRowClass bodyStyle property is no longer supported.");
300 if (rowParams.cols) {
301 Ext.Error.raise("The getRowClass cols property is no longer supported.");
306 // currently only one feature may implement collectData. This is to modify
307 // what's returned to the view before its rendered
308 for (; i < ln; i++) {
309 feature = features[i];
310 if (feature.isFeature && feature.collectData && !feature.disabled) {
311 o = feature.collectData(records, preppedRecords, startIndex, fullWidth, o);
318 // TODO: Refactor header resizing to column resizing
319 <span id='Ext-view-Table-method-onHeaderResize'> /**
320 </span> * When a header is resized, setWidth on the individual columns resizer class,
321 * the top level table, save/restore scroll state, generate a new template and
322 * restore focus to the grid view's element so that keyboard navigation
326 onHeaderResize: function(header, w, suppressFocus) {
331 me.saveScrollState();
332 // Grab the col and set the width, css
333 // class is generated in TableChunker.
334 // Select composites because there may be several chunks.
337 // Setting the width of the first TD does not work - ends up with a 1 pixel discrepancy.
338 // We need to increment the passed with in this case.
339 if (Ext.isIE6 || Ext.isIE7) {
340 if (header.el.hasCls(Ext.baseCSSPrefix + 'column-header-first')) {
344 el.select('.' + Ext.baseCSSPrefix + 'grid-col-resizer-'+header.id).setWidth(w);
345 el.select('.' + Ext.baseCSSPrefix + 'grid-table-resizer').setWidth(me.headerCt.getFullWidth());
346 me.restoreScrollState();
347 if (!me.ignoreTemplate) {
350 if (!suppressFocus) {
356 <span id='Ext-view-Table-method-onHeaderShow'> /**
357 </span> * When a header is shown restore its oldWidth if it was previously hidden.
360 onHeaderShow: function(headerCt, header, suppressFocus) {
362 me.ignoreTemplate = true;
363 // restore headers that were dynamically hidden
364 if (header.oldWidth) {
365 me.onHeaderResize(header, header.oldWidth, suppressFocus);
366 delete header.oldWidth;
367 // flexed headers will have a calculated size set
368 // this additional check has to do with the fact that
369 // defaults: {width: 100} will fight with a flex value
370 } else if (header.width && !header.flex) {
371 me.onHeaderResize(header, header.width, suppressFocus);
373 delete me.ignoreTemplate;
377 <span id='Ext-view-Table-method-onHeaderHide'> /**
378 </span> * When the header hides treat it as a resize to 0.
381 onHeaderHide: function(headerCt, header, suppressFocus) {
382 this.onHeaderResize(header, 0, suppressFocus);
385 <span id='Ext-view-Table-method-setNewTemplate'> /**
386 </span> * Set a new template based on the current columns displayed in the
390 setNewTemplate: function() {
392 columns = me.headerCt.getColumnsForTpl(true);
394 me.tpl = me.getTableChunker().getTableTpl({
396 features: me.features
400 <span id='Ext-view-Table-method-getTableChunker'> /**
401 </span> * Returns the configured chunker or default of Ext.view.TableChunker
403 getTableChunker: function() {
404 return this.chunker || Ext.view.TableChunker;
407 <span id='Ext-view-Table-method-addRowCls'> /**
408 </span> * Adds a CSS Class to a specific row.
409 * @param {HTMLElement/String/Number/Ext.data.Model} rowInfo An HTMLElement, index or instance of a model
410 * representing this row
411 * @param {String} cls
413 addRowCls: function(rowInfo, cls) {
414 var row = this.getNode(rowInfo);
416 Ext.fly(row).addCls(cls);
420 <span id='Ext-view-Table-method-removeRowCls'> /**
421 </span> * Removes a CSS Class from a specific row.
422 * @param {HTMLElement/String/Number/Ext.data.Model} rowInfo An HTMLElement, index or instance of a model
423 * representing this row
424 * @param {String} cls
426 removeRowCls: function(rowInfo, cls) {
427 var row = this.getNode(rowInfo);
429 Ext.fly(row).removeCls(cls);
433 // GridSelectionModel invokes onRowSelect as selection changes
434 onRowSelect : function(rowIdx) {
435 this.addRowCls(rowIdx, this.selectedItemCls);
438 // GridSelectionModel invokes onRowDeselect as selection changes
439 onRowDeselect : function(rowIdx) {
442 me.removeRowCls(rowIdx, me.selectedItemCls);
443 me.removeRowCls(rowIdx, me.focusedItemCls);
446 onCellSelect: function(position) {
447 var cell = this.getCellByPosition(position);
449 cell.addCls(this.selectedCellCls);
453 onCellDeselect: function(position) {
454 var cell = this.getCellByPosition(position);
456 cell.removeCls(this.selectedCellCls);
461 onCellFocus: function(position) {
462 //var cell = this.getCellByPosition(position);
463 this.focusCell(position);
466 getCellByPosition: function(position) {
467 var row = position.row,
468 column = position.column,
470 node = this.getNode(row),
471 header = this.headerCt.getHeaderAtIndex(column),
475 if (header && node) {
476 cellSelector = header.getCellSelector();
477 cell = Ext.fly(node).down(cellSelector);
482 // GridSelectionModel invokes onRowFocus to 'highlight'
483 // the last row focused
484 onRowFocus: function(rowIdx, highlight, supressFocus) {
486 row = me.getNode(rowIdx);
489 me.addRowCls(rowIdx, me.focusedItemCls);
493 //this.el.dom.setAttribute('aria-activedescendant', row.id);
495 me.removeRowCls(rowIdx, me.focusedItemCls);
499 <span id='Ext-view-Table-method-focusRow'> /**
500 </span> * Focuses a particular row and brings it into view. Will fire the rowfocus event.
501 * @param {HTMLElement/String/Number/Ext.data.Model} rowIdx
502 * An HTMLElement template node, index of a template node, the id of a template node or the
503 * record associated with the node.
505 focusRow: function(rowIdx) {
507 row = me.getNode(rowIdx),
515 if (row && el) {
516 elRegion = el.getRegion();
517 rowRegion = Ext.fly(row).getRegion();
519 if (rowRegion.top < elRegion.top) {
520 adjustment = rowRegion.top - elRegion.top;
522 } else if (rowRegion.bottom > elRegion.bottom) {
523 adjustment = rowRegion.bottom - elRegion.bottom;
525 record = me.getRecord(row);
526 rowIdx = me.store.indexOf(record);
529 // scroll the grid itself, so that all gridview's update.
530 panel.scrollByDeltaY(adjustment);
532 me.fireEvent('rowfocus', record, row, rowIdx);
536 focusCell: function(position) {
538 cell = me.getCellByPosition(position),
542 elRegion = el.getRegion(),
548 cellRegion = cell.getRegion();
550 if (cellRegion.top < elRegion.top) {
551 adjustmentY = cellRegion.top - elRegion.top;
553 } else if (cellRegion.bottom > elRegion.bottom) {
554 adjustmentY = cellRegion.bottom - elRegion.bottom;
558 if (cellRegion.left < elRegion.left) {
559 adjustmentX = cellRegion.left - elRegion.left;
561 } else if (cellRegion.right > elRegion.right) {
562 adjustmentX = cellRegion.right - elRegion.right;
566 // scroll the grid itself, so that all gridview's update.
567 panel.scrollByDeltaY(adjustmentY);
570 panel.scrollByDeltaX(adjustmentX);
573 me.fireEvent('cellfocus', record, cell, position);
577 <span id='Ext-view-Table-method-scrollByDelta'> /**
578 </span> * Scrolls by delta. This affects this individual view ONLY and does not
579 * synchronize across views or scrollers.
580 * @param {Number} delta
581 * @param {String} dir (optional) Valid values are scrollTop and scrollLeft. Defaults to scrollTop.
584 scrollByDelta: function(delta, dir) {
585 dir = dir || 'scrollTop';
586 var elDom = this.el.dom;
587 elDom[dir] = (elDom[dir] += delta);
590 onUpdate: function(ds, index) {
591 this.callParent(arguments);
594 <span id='Ext-view-Table-method-saveScrollState'> /**
595 </span> * Saves the scrollState in a private variable. Must be used in conjunction with restoreScrollState
597 saveScrollState: function() {
599 var dom = this.el.dom,
600 state = this.scrollState;
602 state.left = dom.scrollLeft;
603 state.top = dom.scrollTop;
607 <span id='Ext-view-Table-method-restoreScrollState'> /**
608 </span> * Restores the scrollState.
609 * Must be used in conjunction with saveScrollState
612 restoreScrollState: function() {
614 var dom = this.el.dom,
615 state = this.scrollState,
616 headerEl = this.headerCt.el.dom;
618 headerEl.scrollLeft = dom.scrollLeft = state.left;
619 dom.scrollTop = state.top;
623 <span id='Ext-view-Table-method-refresh'> /**
624 </span> * Refreshes the grid view. Saves and restores the scroll state, generates a new template, stripes rows and
625 * invalidates the scrollers.
627 refresh: function() {
628 this.setNewTemplate();
629 this.callParent(arguments);
632 processItemEvent: function(record, row, rowIndex, e) {
634 cell = e.getTarget(me.cellSelector, row),
635 cellIndex = cell ? cell.cellIndex : -1,
636 map = me.statics().EventMap,
637 selModel = me.getSelectionModel(),
641 if (type == 'keydown' && !cell && selModel.getCurrentPosition) {
642 // CellModel, otherwise we can't tell which cell to invoke
643 cell = me.getCellByPosition(selModel.getCurrentPosition());
646 cellIndex = cell.cellIndex;
650 result = me.fireEvent('uievent', type, me, cell, rowIndex, cellIndex, e);
652 if (result === false || me.callParent(arguments) === false) {
656 // Don't handle cellmouseenter and cellmouseleave events for now
657 if (type == 'mouseover' || type == 'mouseout') {
662 // We are adding cell and feature events
663 (me['onBeforeCell' + map[type]](cell, cellIndex, record, row, rowIndex, e) === false) ||
664 (me.fireEvent('beforecell' + type, me, cell, cellIndex, record, row, rowIndex, e) === false) ||
665 (me['onCell' + map[type]](cell, cellIndex, record, row, rowIndex, e) === false) ||
666 (me.fireEvent('cell' + type, me, cell, cellIndex, record, row, rowIndex, e) === false)
670 processSpecialEvent: function(e) {
672 map = me.statics().EventMap,
673 features = me.features,
674 ln = features.length,
676 i, feature, prefix, featureTarget,
680 me.callParent(arguments);
682 if (type == 'mouseover' || type == 'mouseout') {
686 for (i = 0; i < ln; i++) {
687 feature = features[i];
688 if (feature.hasFeatureEvent) {
689 featureTarget = e.getTarget(feature.eventSelector, me.getTargetEl());
691 prefix = feature.eventPrefix;
692 // allows features to implement getFireEventArgs to change the
693 // fireEvent signature
694 beforeArgs = feature.getFireEventArgs('before' + prefix + type, me, featureTarget, e);
695 args = feature.getFireEventArgs(prefix + type, me, featureTarget, e);
699 (me.fireEvent.apply(me, beforeArgs) === false) ||
701 (panel.fireEvent.apply(panel, beforeArgs) === false) ||
703 (me.fireEvent.apply(me, args) === false) ||
705 (panel.fireEvent.apply(panel, args) === false)
715 onCellMouseDown: Ext.emptyFn,
716 onCellMouseUp: Ext.emptyFn,
717 onCellClick: Ext.emptyFn,
718 onCellDblClick: Ext.emptyFn,
719 onCellContextMenu: Ext.emptyFn,
720 onCellKeyDown: Ext.emptyFn,
721 onBeforeCellMouseDown: Ext.emptyFn,
722 onBeforeCellMouseUp: Ext.emptyFn,
723 onBeforeCellClick: Ext.emptyFn,
724 onBeforeCellDblClick: Ext.emptyFn,
725 onBeforeCellContextMenu: Ext.emptyFn,
726 onBeforeCellKeyDown: Ext.emptyFn,
728 <span id='Ext-view-Table-method-expandToFit'> /**
729 </span> * Expands a particular header to fit the max content width.
730 * This will ONLY expand, not contract.
733 expandToFit: function(header) {
735 var maxWidth = this.getMaxContentWidth(header);
737 header.setWidth(maxWidth);
741 <span id='Ext-view-Table-method-getMaxContentWidth'> /**
742 </span> * Returns the max contentWidth of the header's text and all cells
743 * in the grid under this header.
746 getMaxContentWidth: function(header) {
747 var cellSelector = header.getCellInnerSelector(),
748 cells = this.el.query(cellSelector),
751 maxWidth = header.el.dom.scrollWidth,
754 for (; i < ln; i++) {
755 scrollWidth = cells[i].scrollWidth;
756 if (scrollWidth > maxWidth) {
757 maxWidth = scrollWidth;
763 getPositionByEvent: function(e) {
765 cellNode = e.getTarget(me.cellSelector),
766 rowNode = e.getTarget(me.itemSelector),
767 record = me.getRecord(rowNode),
768 header = me.getHeaderByCell(cellNode);
770 return me.getPosition(record, header);
773 getHeaderByCell: function(cell) {
775 var m = cell.className.match(this.cellRe);
776 if (m && m[1]) {
777 return Ext.getCmp(m[1]);
783 <span id='Ext-view-Table-method-walkCells'> /**
784 </span> * @param {Object} position The current row and column: an object containing the following properties:
786 * - row - The row index
787 * - column - The column index
789 * @param {String} direction 'up', 'down', 'right' and 'left'
790 * @param {Ext.EventObject} e event
791 * @param {Boolean} preventWrap Set to true to prevent wrap around to the next or previous row.
792 * @param {Function} verifierFn A function to verify the validity of the calculated position.
793 * When using this function, you must return true to allow the newPosition to be returned.
794 * @param {Object} scope Scope to run the verifierFn in
795 * @returns {Object} newPosition An object containing the following properties:
797 * - row - The row index
798 * - column - The column index
802 walkCells: function(pos, direction, e, preventWrap, verifierFn, scope) {
806 rowCount = me.store.getCount(),
807 firstCol = me.getFirstVisibleColumnIndex(),
808 lastCol = me.getLastVisibleColumnIndex(),
809 newPos = {row: row, column: column},
810 activeHeader = me.headerCt.getHeaderAtIndex(column);
812 // no active header or its currently hidden
813 if (!activeHeader || activeHeader.hidden) {
818 direction = direction.toLowerCase();
821 // has the potential to wrap if its last
822 if (column === lastCol) {
823 // if bottom row and last column, deny right
824 if (preventWrap || row === rowCount - 1) {
828 // otherwise wrap to nextRow and firstCol
829 newPos.row = row + 1;
830 newPos.column = firstCol;
835 newPos.column = column + me.getRightGap(activeHeader);
837 newPos.column = lastCol;
843 // has the potential to wrap
844 if (column === firstCol) {
845 // if top row and first column, deny left
846 if (preventWrap || row === 0) {
850 // otherwise wrap to prevRow and lastCol
851 newPos.row = row - 1;
852 newPos.column = lastCol;
857 newPos.column = column + me.getLeftGap(activeHeader);
859 newPos.column = firstCol;
865 // if top row, deny up
871 newPos.row = row - 1;
879 // if bottom row, deny down
880 if (row === rowCount - 1) {
885 newPos.row = row + 1;
887 newPos.row = rowCount - 1;
893 if (verifierFn && verifierFn.call(scope || window, newPos) !== true) {
899 getFirstVisibleColumnIndex: function() {
900 var headerCt = this.getHeaderCt(),
901 allColumns = headerCt.getGridColumns(),
902 visHeaders = Ext.ComponentQuery.query(':not([hidden])', allColumns),
903 firstHeader = visHeaders[0];
905 return headerCt.getHeaderIndex(firstHeader);
908 getLastVisibleColumnIndex: function() {
909 var headerCt = this.getHeaderCt(),
910 allColumns = headerCt.getGridColumns(),
911 visHeaders = Ext.ComponentQuery.query(':not([hidden])', allColumns),
912 lastHeader = visHeaders[visHeaders.length - 1];
914 return headerCt.getHeaderIndex(lastHeader);
917 getHeaderCt: function() {
918 return this.headerCt;
921 getPosition: function(record, header) {
924 gridCols = me.headerCt.getGridColumns();
927 row: store.indexOf(record),
928 column: Ext.Array.indexOf(gridCols, header)
932 <span id='Ext-view-Table-method-getRightGap'> /**
933 </span> * Determines the 'gap' between the closest adjacent header to the right
934 * that is not hidden.
937 getRightGap: function(activeHeader) {
938 var headerCt = this.getHeaderCt(),
939 headers = headerCt.getGridColumns(),
940 activeHeaderIdx = Ext.Array.indexOf(headers, activeHeader),
941 i = activeHeaderIdx + 1,
944 for (; i <= headers.length; i++) {
945 if (!headers[i].hidden) {
951 return nextIdx - activeHeaderIdx;
954 beforeDestroy: function() {
956 this.el.removeAllListeners();
958 this.callParent(arguments);
961 <span id='Ext-view-Table-method-getLeftGap'> /**
962 </span> * Determines the 'gap' between the closest adjacent header to the left
963 * that is not hidden.
966 getLeftGap: function(activeHeader) {
967 var headerCt = this.getHeaderCt(),
968 headers = headerCt.getGridColumns(),
969 activeHeaderIdx = Ext.Array.indexOf(headers, activeHeader),
970 i = activeHeaderIdx - 1,
973 for (; i >= 0; i--) {
974 if (!headers[i].hidden) {
980 return prevIdx - activeHeaderIdx;