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-panel-Table'>/**
19 </span> * @author Nicolas Ferrero
21 * TablePanel is the basis of both {@link Ext.tree.Panel TreePanel} and {@link Ext.grid.Panel GridPanel}.
23 * TablePanel aggregates:
29 * - Ext.grid.header.Container
31 Ext.define('Ext.panel.Table', {
32 extend: 'Ext.panel.Panel',
34 alias: 'widget.tablepanel',
37 'Ext.selection.RowModel',
39 'Ext.grid.header.Container',
43 extraBaseCls: Ext.baseCSSPrefix + 'grid',
44 extraBodyCls: Ext.baseCSSPrefix + 'grid-body',
47 <span id='Ext-panel-Table-property-hasView'> /**
48 </span> * @property {Boolean} hasView
49 * True to indicate that a view has been injected into the panel.
53 // each panel should dictate what viewType and selType to use
54 <span id='Ext-panel-Table-cfg-viewType'> /**
55 </span> * @cfg {String} viewType
56 * An xtype of view to use. This is automatically set to 'gridview' by {@link Ext.grid.Panel Grid}
57 * and to 'treeview' by {@link Ext.tree.Panel Tree}.
61 <span id='Ext-panel-Table-cfg-viewConfig'> /**
62 </span> * @cfg {Object} viewConfig
63 * A config object that will be applied to the grid's UI view. Any of the config options available for
64 * {@link Ext.view.Table} can be specified here. This option is ignored if {@link #view} is specified.
67 <span id='Ext-panel-Table-cfg-view'> /**
68 </span> * @cfg {Ext.view.Table} view
69 * The {@link Ext.view.Table} used by the grid. Use {@link #viewConfig} to just supply some config options to
70 * view (instead of creating an entire View instance).
73 <span id='Ext-panel-Table-cfg-selType'> /**
74 </span> * @cfg {String} selType
75 * An xtype of selection model to use. Defaults to 'rowmodel'. This is used to create selection model if just
76 * a config object or nothing at all given in {@link #selModel} config.
80 <span id='Ext-panel-Table-cfg-selModel'> /**
81 </span> * @cfg {Ext.selection.Model/Object} selModel
82 * A {@link Ext.selection.Model selection model} instance or config object. In latter case the {@link #selType}
83 * config option determines to which type of selection model this config is applied.
86 <span id='Ext-panel-Table-cfg-multiSelect'> /**
87 </span> * @cfg {Boolean} multiSelect
88 * True to enable 'MULTI' selection mode on selection model. See {@link Ext.selection.Model#mode}.
91 <span id='Ext-panel-Table-cfg-simpleSelect'> /**
92 </span> * @cfg {Boolean} simpleSelect
93 * True to enable 'SIMPLE' selection mode on selection model. See {@link Ext.selection.Model#mode}.
96 <span id='Ext-panel-Table-cfg-store'> /**
97 </span> * @cfg {Ext.data.Store} store (required)
98 * The {@link Ext.data.Store Store} the grid should use as its data source.
101 <span id='Ext-panel-Table-cfg-scrollDelta'> /**
102 </span> * @cfg {Number} scrollDelta
103 * Number of pixels to scroll when scrolling with mousewheel.
107 <span id='Ext-panel-Table-cfg-scroll'> /**
108 </span> * @cfg {String/Boolean} scroll
109 * Scrollers configuration. Valid values are 'both', 'horizontal' or 'vertical'.
110 * True implies 'both'. False implies 'none'.
114 <span id='Ext-panel-Table-cfg-columns'> /**
115 </span> * @cfg {Ext.grid.column.Column[]} columns
116 * An array of {@link Ext.grid.column.Column column} definition objects which define all columns that appear in this
117 * grid. Each column definition provides the header text for the column, and a definition of where the data for that
121 <span id='Ext-panel-Table-cfg-forceFit'> /**
122 </span> * @cfg {Boolean} forceFit
123 * Ttrue to force the columns to fit into the available width. Headers are first sized according to configuration,
124 * whether that be a specific width, or flex. Then they are all proportionally changed in width so that the entire
125 * content width is used.
128 <span id='Ext-panel-Table-cfg-features'> /**
129 </span> * @cfg {Ext.grid.feature.Feature[]} features
130 * An array of grid Features to be added to this grid. See {@link Ext.grid.feature.Feature} for usage.
133 <span id='Ext-panel-Table-cfg-hideHeaders'> /**
134 </span> * @cfg {Boolean} [hideHeaders=false]
135 * True to hide column headers.
138 <span id='Ext-panel-Table-cfg-deferRowRender'> /**
139 </span> * @cfg {Boolean} deferRowRender
140 * Defaults to true to enable deferred row rendering.
142 * This allows the View to execute a refresh quickly, with the expensive update of the row structure deferred so
143 * that layouts with GridPanels appear, and lay out more quickly.
146 deferRowRender: true,
148 <span id='Ext-panel-Table-cfg-sortableColumns'> /**
149 </span> * @cfg {Boolean} sortableColumns
150 * False to disable column sorting via clicking the header and via the Sorting menu items.
152 sortableColumns: true,
154 <span id='Ext-panel-Table-cfg-enableLocking'> /**
155 </span> * @cfg {Boolean} [enableLocking=false]
156 * True to enable locking support for this grid. Alternatively, locking will also be automatically
157 * enabled if any of the columns in the column configuration contain the locked config option.
159 enableLocking: false,
161 verticalScrollDock: 'right',
162 verticalScrollerType: 'gridscroller',
164 horizontalScrollerPresentCls: Ext.baseCSSPrefix + 'horizontal-scroller-present',
165 verticalScrollerPresentCls: Ext.baseCSSPrefix + 'vertical-scroller-present',
167 // private property used to determine where to go down to find views
168 // this is here to support locking.
171 invalidateScrollerOnRefresh: true,
173 <span id='Ext-panel-Table-cfg-enableColumnMove'> /**
174 </span> * @cfg {Boolean} enableColumnMove
175 * False to disable column dragging within this grid.
177 enableColumnMove: true,
179 <span id='Ext-panel-Table-cfg-enableColumnResize'> /**
180 </span> * @cfg {Boolean} enableColumnResize
181 * False to disable column resizing within this grid.
183 enableColumnResize: true,
185 <span id='Ext-panel-Table-cfg-enableColumnHide'> /**
186 </span> * @cfg {Boolean} enableColumnHide
187 * False to disable column hiding within this grid.
189 enableColumnHide: true,
191 initComponent: function() {
193 if (!this.viewType) {
194 Ext.Error.raise("You must specify a viewType config.");
197 Ext.Error.raise("The headers config is not supported. Please specify columns instead.");
205 headerCtCfg = me.columns || me.colModel,
210 if (me.hideHeaders) {
214 // Look up the configured Store. If none configured, use the fieldless, empty Store defined in Ext.data.Store.
215 me.store = Ext.data.StoreManager.lookup(me.store || 'ext-empty-store');
217 // The columns/colModel config may be either a fully instantiated HeaderContainer, or an array of Column definitions, or a config object of a HeaderContainer
218 // Either way, we extract a columns property referencing an array of Column definitions.
219 if (headerCtCfg instanceof Ext.grid.header.Container) {
220 me.headerCt = headerCtCfg;
221 me.headerCt.border = border;
222 me.columns = me.headerCt.items.items;
224 if (Ext.isArray(headerCtCfg)) {
230 Ext.apply(headerCtCfg, {
231 forceFit: me.forceFit,
232 sortable: me.sortableColumns,
233 enableColumnMove: me.enableColumnMove,
234 enableColumnResize: me.enableColumnResize,
235 enableColumnHide: me.enableColumnHide,
238 me.columns = headerCtCfg.items;
240 // If any of the Column objects contain a locked property, and are not processed, this is a lockable TablePanel, a
241 // special view will be injected by the Ext.grid.Lockable mixin, so no processing of .
242 if (me.enableLocking || Ext.ComponentQuery.query('{locked !== undefined}{processed != true}', me.columns).length) {
243 me.self.mixin('lockable', Ext.grid.Lockable);
249 <span id='Ext-panel-Table-event-reconfigure'> /**
250 </span> * @event reconfigure
251 * Fires after a reconfigure.
252 * @param {Ext.panel.Table} this
255 <span id='Ext-panel-Table-event-viewready'> /**
256 </span> * @event viewready
257 * Fires when the grid view is available (use this for selecting a default row).
258 * @param {Ext.panel.Table} this
261 <span id='Ext-panel-Table-event-scrollerhide'> /**
262 </span> * @event scrollerhide
263 * Fires when a scroller is hidden.
264 * @param {Ext.grid.Scroller} scroller
265 * @param {String} orientation Orientation, can be 'vertical' or 'horizontal'
268 <span id='Ext-panel-Table-event-scrollershow'> /**
269 </span> * @event scrollershow
270 * Fires when a scroller is shown.
271 * @param {Ext.grid.Scroller} scroller
272 * @param {String} orientation Orientation, can be 'vertical' or 'horizontal'
277 me.bodyCls = me.bodyCls || '';
278 me.bodyCls += (' ' + me.extraBodyCls);
280 me.cls = me.cls || '';
281 me.cls += (' ' + me.extraBaseCls);
283 // autoScroll is not a valid configuration
284 delete me.autoScroll;
286 // If this TablePanel is lockable (Either configured lockable, or any of the defined columns has a 'locked' property)
287 // than a special lockable view containing 2 side-by-side grids will have been injected so we do not need to set up any UI.
290 // If we were not configured with a ready-made headerCt (either by direct config with a headerCt property, or by passing
291 // a HeaderContainer instance as the 'columns' property, then go ahead and create one from the config object created above.
293 me.headerCt = Ext.create('Ext.grid.header.Container', headerCtCfg);
296 // Extract the array of Column objects
297 me.columns = me.headerCt.items.items;
299 if (me.hideHeaders) {
300 me.headerCt.height = 0;
301 me.headerCt.border = false;
302 me.headerCt.addCls(Ext.baseCSSPrefix + 'grid-header-ct-hidden');
303 me.addCls(Ext.baseCSSPrefix + 'grid-header-hidden');
304 // IE Quirks Mode fix
305 // If hidden configuration option was used, several layout calculations will be bypassed.
306 if (Ext.isIEQuirks) {
307 me.headerCt.style = {
314 if (scroll === true || scroll === 'both') {
315 vertical = horizontal = true;
316 } else if (scroll === 'horizontal') {
318 } else if (scroll === 'vertical') {
320 // All other values become 'none' or false.
322 me.headerCt.availableSpaceOffset = 0;
326 me.verticalScroller = Ext.ComponentManager.create(me.initVerticalScroller());
327 me.mon(me.verticalScroller, {
328 bodyscroll: me.onVerticalScroll,
334 me.horizontalScroller = Ext.ComponentManager.create(me.initHorizontalScroller());
335 me.mon(me.horizontalScroller, {
336 bodyscroll: me.onHorizontalScroll,
341 me.headerCt.on('resize', me.onHeaderResize, me);
342 me.relayHeaderCtEvents(me.headerCt);
343 me.features = me.features || [];
344 if (!Ext.isArray(me.features)) {
345 me.features = [me.features];
347 me.dockedItems = me.dockedItems || [];
348 me.dockedItems.unshift(me.headerCt);
349 me.viewConfig = me.viewConfig || {};
350 me.viewConfig.invalidateScrollerOnRefresh = me.invalidateScrollerOnRefresh;
352 // AbstractDataView will look up a Store configured as an object
353 // getView converts viewConfig into a View instance
357 afterrender: function () {
358 // hijack the view el's scroll method
359 view.el.scroll = Ext.Function.bind(me.elScroll, me);
360 // We use to listen to document.body wheel events, but that's a
361 // little much. We scope just to the view now.
363 mousewheel: me.onMouseWheel,
373 load: me.onStoreLoad,
377 viewReady: me.onViewReady,
378 resize: me.onViewResize,
380 fn: me.onViewRefresh,
386 this.relayEvents(view, [
387 <span id='Ext-panel-Table-event-beforeitemmousedown'> /**
388 </span> * @event beforeitemmousedown
389 * @alias Ext.view.View#beforeitemmousedown
391 'beforeitemmousedown',
392 <span id='Ext-panel-Table-event-beforeitemmouseup'> /**
393 </span> * @event beforeitemmouseup
394 * @alias Ext.view.View#beforeitemmouseup
397 <span id='Ext-panel-Table-event-beforeitemmouseenter'> /**
398 </span> * @event beforeitemmouseenter
399 * @alias Ext.view.View#beforeitemmouseenter
401 'beforeitemmouseenter',
402 <span id='Ext-panel-Table-event-beforeitemmouseleave'> /**
403 </span> * @event beforeitemmouseleave
404 * @alias Ext.view.View#beforeitemmouseleave
406 'beforeitemmouseleave',
407 <span id='Ext-panel-Table-event-beforeitemclick'> /**
408 </span> * @event beforeitemclick
409 * @alias Ext.view.View#beforeitemclick
412 <span id='Ext-panel-Table-event-beforeitemdblclick'> /**
413 </span> * @event beforeitemdblclick
414 * @alias Ext.view.View#beforeitemdblclick
416 'beforeitemdblclick',
417 <span id='Ext-panel-Table-event-beforeitemcontextmenu'> /**
418 </span> * @event beforeitemcontextmenu
419 * @alias Ext.view.View#beforeitemcontextmenu
421 'beforeitemcontextmenu',
422 <span id='Ext-panel-Table-event-itemmousedown'> /**
423 </span> * @event itemmousedown
424 * @alias Ext.view.View#itemmousedown
427 <span id='Ext-panel-Table-event-itemmouseup'> /**
428 </span> * @event itemmouseup
429 * @alias Ext.view.View#itemmouseup
432 <span id='Ext-panel-Table-event-itemmouseenter'> /**
433 </span> * @event itemmouseenter
434 * @alias Ext.view.View#itemmouseenter
437 <span id='Ext-panel-Table-event-itemmouseleave'> /**
438 </span> * @event itemmouseleave
439 * @alias Ext.view.View#itemmouseleave
442 <span id='Ext-panel-Table-event-itemclick'> /**
443 </span> * @event itemclick
444 * @alias Ext.view.View#itemclick
447 <span id='Ext-panel-Table-event-itemdblclick'> /**
448 </span> * @event itemdblclick
449 * @alias Ext.view.View#itemdblclick
452 <span id='Ext-panel-Table-event-itemcontextmenu'> /**
453 </span> * @event itemcontextmenu
454 * @alias Ext.view.View#itemcontextmenu
457 <span id='Ext-panel-Table-event-beforecontainermousedown'> /**
458 </span> * @event beforecontainermousedown
459 * @alias Ext.view.View#beforecontainermousedown
461 'beforecontainermousedown',
462 <span id='Ext-panel-Table-event-beforecontainermouseup'> /**
463 </span> * @event beforecontainermouseup
464 * @alias Ext.view.View#beforecontainermouseup
466 'beforecontainermouseup',
467 <span id='Ext-panel-Table-event-beforecontainermouseover'> /**
468 </span> * @event beforecontainermouseover
469 * @alias Ext.view.View#beforecontainermouseover
471 'beforecontainermouseover',
472 <span id='Ext-panel-Table-event-beforecontainermouseout'> /**
473 </span> * @event beforecontainermouseout
474 * @alias Ext.view.View#beforecontainermouseout
476 'beforecontainermouseout',
477 <span id='Ext-panel-Table-event-beforecontainerclick'> /**
478 </span> * @event beforecontainerclick
479 * @alias Ext.view.View#beforecontainerclick
481 'beforecontainerclick',
482 <span id='Ext-panel-Table-event-beforecontainerdblclick'> /**
483 </span> * @event beforecontainerdblclick
484 * @alias Ext.view.View#beforecontainerdblclick
486 'beforecontainerdblclick',
487 <span id='Ext-panel-Table-event-beforecontainercontextmenu'> /**
488 </span> * @event beforecontainercontextmenu
489 * @alias Ext.view.View#beforecontainercontextmenu
491 'beforecontainercontextmenu',
492 <span id='Ext-panel-Table-event-containermouseup'> /**
493 </span> * @event containermouseup
494 * @alias Ext.view.View#containermouseup
497 <span id='Ext-panel-Table-event-containermouseover'> /**
498 </span> * @event containermouseover
499 * @alias Ext.view.View#containermouseover
501 'containermouseover',
502 <span id='Ext-panel-Table-event-containermouseout'> /**
503 </span> * @event containermouseout
504 * @alias Ext.view.View#containermouseout
507 <span id='Ext-panel-Table-event-containerclick'> /**
508 </span> * @event containerclick
509 * @alias Ext.view.View#containerclick
512 <span id='Ext-panel-Table-event-containerdblclick'> /**
513 </span> * @event containerdblclick
514 * @alias Ext.view.View#containerdblclick
517 <span id='Ext-panel-Table-event-containercontextmenu'> /**
518 </span> * @event containercontextmenu
519 * @alias Ext.view.View#containercontextmenu
521 'containercontextmenu',
522 <span id='Ext-panel-Table-event-selectionchange'> /**
523 </span> * @event selectionchange
524 * @alias Ext.selection.Model#selectionchange
527 <span id='Ext-panel-Table-event-beforeselect'> /**
528 </span> * @event beforeselect
529 * @alias Ext.selection.RowModel#beforeselect
532 <span id='Ext-panel-Table-event-select'> /**
533 </span> * @event select
534 * @alias Ext.selection.RowModel#select
537 <span id='Ext-panel-Table-event-beforedeselect'> /**
538 </span> * @event beforedeselect
539 * @alias Ext.selection.RowModel#beforedeselect
542 <span id='Ext-panel-Table-event-deselect'> /**
543 </span> * @event deselect
544 * @alias Ext.selection.RowModel#deselect
550 me.callParent(arguments);
553 onRender: function(){
554 var vScroll = this.verticalScroller,
555 hScroll = this.horizontalScroller;
558 vScroll.ensureDimension();
561 hScroll.ensureDimension();
563 this.callParent(arguments);
567 initStateEvents: function(){
568 var events = this.stateEvents;
569 // push on stateEvents if they don't exist
570 Ext.each(['columnresize', 'columnmove', 'columnhide', 'columnshow', 'sortchange'], function(event){
571 if (Ext.Array.indexOf(events, event)) {
578 <span id='Ext-panel-Table-method-initHorizontalScroller'> /**
579 </span> * Returns the horizontal scroller config.
581 initHorizontalScroller: function () {
584 xtype: 'gridscroller',
593 <span id='Ext-panel-Table-method-initVerticalScroller'> /**
594 </span> * Returns the vertical scroller config.
596 initVerticalScroller: function () {
598 ret = me.verticalScroller || {};
601 xtype: me.verticalScrollerType,
602 dock: me.verticalScrollDock,
609 relayHeaderCtEvents: function (headerCt) {
610 this.relayEvents(headerCt, [
611 <span id='Ext-panel-Table-event-columnresize'> /**
612 </span> * @event columnresize
613 * @alias Ext.grid.header.Container#columnresize
616 <span id='Ext-panel-Table-event-columnmove'> /**
617 </span> * @event columnmove
618 * @alias Ext.grid.header.Container#columnmove
621 <span id='Ext-panel-Table-event-columnhide'> /**
622 </span> * @event columnhide
623 * @alias Ext.grid.header.Container#columnhide
626 <span id='Ext-panel-Table-event-columnshow'> /**
627 </span> * @event columnshow
628 * @alias Ext.grid.header.Container#columnshow
631 <span id='Ext-panel-Table-event-sortchange'> /**
632 </span> * @event sortchange
633 * @alias Ext.grid.header.Container#sortchange
639 getState: function(){
641 state = me.callParent(),
642 sorter = me.store.sorters.first();
644 state.columns = (me.headerCt || me).getColumnsState();
648 property: sorter.property,
649 direction: sorter.direction
656 applyState: function(state) {
660 columns = state.columns;
662 delete state.columns;
664 // Ensure superclass has applied *its* state.
665 // AbstractComponent saves dimensions (and anchor/flex) plus collapsed state.
666 me.callParent(arguments);
669 (me.headerCt || me).applyColumnsState(columns);
673 if (store.remoteSort) {
674 store.sorters.add(Ext.create('Ext.util.Sorter', {
675 property: sorter.property,
676 direction: sorter.direction
680 store.sort(sorter.property, sorter.direction);
685 <span id='Ext-panel-Table-method-getStore'> /**
686 </span> * Returns the store associated with this Panel.
687 * @return {Ext.data.Store} The store
689 getStore: function(){
693 <span id='Ext-panel-Table-method-getView'> /**
694 </span> * Gets the view for this panel.
695 * @return {Ext.view.Table}
697 getView: function() {
702 sm = me.getSelectionModel();
703 me.view = me.createComponent(Ext.apply({}, me.viewConfig, {
704 deferInitialRefresh: me.deferRowRender,
707 headerCt: me.headerCt,
709 features: me.features,
713 uievent: me.processEvent,
717 me.headerCt.view = me.view;
718 me.relayEvents(me.view, ['cellclick', 'celldblclick']);
723 <span id='Ext-panel-Table-property-setAutoScroll'> /**
726 * autoScroll is never valid for all classes which extend TablePanel.
728 setAutoScroll: Ext.emptyFn,
730 // This method hijacks Ext.view.Table's el scroll method.
731 // This enables us to keep the virtualized scrollbars in sync
732 // with the view. It currently does NOT support animation.
733 elScroll: function(direction, distance, animate) {
737 if (direction === "up" || direction === "left") {
738 distance = -distance;
741 if (direction === "down" || direction === "up") {
742 scroller = me.getVerticalScroller();
744 //if the grid does not currently need a vertical scroller don't try to update it (EXTJSIV-3891)
746 scroller.scrollByDeltaY(distance);
749 scroller = me.getHorizontalScroller();
751 //if the grid does not currently need a horizontal scroller don't try to update it (EXTJSIV-3891)
753 scroller.scrollByDeltaX(distance);
758 <span id='Ext-panel-Table-method-processEvent'> /**
760 * Processes UI events from the view. Propagates them to whatever internal Components need to process them.
761 * @param {String} type Event type, eg 'click'
762 * @param {Ext.view.Table} view TableView Component
763 * @param {HTMLElement} cell Cell HtmlElement the event took place within
764 * @param {Number} recordIndex Index of the associated Store Model (-1 if none)
765 * @param {Number} cellIndex Cell index within the row
766 * @param {Ext.EventObject} e Original event
768 processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
772 if (cellIndex !== -1) {
773 header = me.headerCt.getGridColumns()[cellIndex];
774 return header.processEvent.apply(header, arguments);
778 <span id='Ext-panel-Table-method-determineScrollbars'> /**
779 </span> * Requests a recalculation of scrollbars and puts them in if they are needed.
781 determineScrollbars: function() {
782 // Set a flag so that afterComponentLayout does not recurse back into here.
783 if (this.determineScrollbarsRunning) {
786 this.determineScrollbarsRunning = true;
795 verticalScroller = me.verticalScroller,
796 horizontalScroller = me.horizontalScroller,
797 curScrollbars = (verticalScroller && verticalScroller.ownerCt === me ? 1 : 0) |
798 (horizontalScroller && horizontalScroller.ownerCt === me ? 2 : 0),
799 reqScrollbars = 0; // 1 = vertical, 2 = horizontal, 3 = both
801 // If we are not collapsed, and the view has been rendered AND filled, then we can determine scrollbars
802 if (!me.collapsed && view && view.viewReady) {
804 // Calculate maximum, *scrollbarless* space which the view has available.
805 // It will be the Fit Layout's calculated size, plus the widths of any currently shown scrollbars
806 box = view.el.getSize();
808 clientWidth = box.width + ((curScrollbars & 1) ? verticalScroller.width : 0);
809 clientHeight = box.height + ((curScrollbars & 2) ? horizontalScroller.height : 0);
811 // Calculate the width of the scrolling block
812 // There will never be a horizontal scrollbar if all columns are flexed.
814 scrollWidth = (me.headerCt.query('[flex]').length && !me.headerCt.layout.tooNarrow) ? 0 : me.headerCt.getFullWidth();
816 // Calculate the height of the scrolling block
817 if (verticalScroller && verticalScroller.el) {
818 scrollHeight = verticalScroller.getSizeCalculation().height;
820 tableEl = view.el.child('table', true);
821 scrollHeight = tableEl ? tableEl.offsetHeight : 0;
825 // Definitely need a vertical scrollbar
826 if (scrollHeight > clientHeight) {
829 // But if scrollable block width goes into the zone required by the vertical scrollbar, we'll also need a horizontal
830 if (horizontalScroller && ((clientWidth - scrollWidth) < verticalScroller.width)) {
835 // View height fits. But we stil may need a horizontal scrollbar, and this might necessitate a vertical one.
838 // Definitely need a horizontal scrollbar
839 if (scrollWidth > clientWidth) {
842 // But if scrollable block height goes into the zone required by the horizontal scrollbar, we'll also need a vertical
843 if (verticalScroller && ((clientHeight - scrollHeight) < horizontalScroller.height)) {
849 // If scrollbar requirements have changed, change 'em...
850 if (reqScrollbars !== curScrollbars) {
852 // Suspend component layout while we add/remove the docked scrollers
853 me.suspendLayout = true;
854 if (reqScrollbars & 1) {
855 me.showVerticalScroller();
857 me.hideVerticalScroller();
859 if (reqScrollbars & 2) {
860 me.showHorizontalScroller();
862 me.hideHorizontalScroller();
864 me.suspendLayout = false;
866 // Lay out the Component.
867 me.doComponentLayout();
869 me.getLayout().layout();
872 delete me.determineScrollbarsRunning;
875 onViewResize: function() {
876 this.determineScrollbars();
879 afterComponentLayout: function() {
880 this.callParent(arguments);
881 this.determineScrollbars();
882 this.invalidateScroller();
885 onHeaderResize: function() {
886 if (!this.componentLayout.layoutBusy && this.view && this.view.rendered) {
887 this.determineScrollbars();
888 this.invalidateScroller();
892 afterCollapse: function() {
894 if (me.verticalScroller) {
895 me.verticalScroller.saveScrollPos();
897 if (me.horizontalScroller) {
898 me.horizontalScroller.saveScrollPos();
900 me.callParent(arguments);
903 afterExpand: function() {
905 me.callParent(arguments);
906 if (me.verticalScroller) {
907 me.verticalScroller.restoreScrollPos();
909 if (me.horizontalScroller) {
910 me.horizontalScroller.restoreScrollPos();
914 <span id='Ext-panel-Table-method-hideHorizontalScroller'> /**
915 </span> * Hides the verticalScroller and removes the horizontalScrollerPresentCls.
917 hideHorizontalScroller: function() {
920 if (me.horizontalScroller && me.horizontalScroller.ownerCt === me) {
921 me.verticalScroller.setReservedSpace(0);
922 me.removeDocked(me.horizontalScroller, false);
923 me.removeCls(me.horizontalScrollerPresentCls);
924 me.fireEvent('scrollerhide', me.horizontalScroller, 'horizontal');
929 <span id='Ext-panel-Table-method-showHorizontalScroller'> /**
930 </span> * Shows the horizontalScroller and add the horizontalScrollerPresentCls.
932 showHorizontalScroller: function() {
935 if (me.verticalScroller) {
936 me.verticalScroller.setReservedSpace(Ext.getScrollbarSize().height - 1);
938 if (me.horizontalScroller && me.horizontalScroller.ownerCt !== me) {
939 me.addDocked(me.horizontalScroller);
940 me.addCls(me.horizontalScrollerPresentCls);
941 me.fireEvent('scrollershow', me.horizontalScroller, 'horizontal');
945 <span id='Ext-panel-Table-method-hideVerticalScroller'> /**
946 </span> * Hides the verticalScroller and removes the verticalScrollerPresentCls.
948 hideVerticalScroller: function() {
951 me.setHeaderReserveOffset(false);
952 if (me.verticalScroller && me.verticalScroller.ownerCt === me) {
953 me.removeDocked(me.verticalScroller, false);
954 me.removeCls(me.verticalScrollerPresentCls);
955 me.fireEvent('scrollerhide', me.verticalScroller, 'vertical');
959 <span id='Ext-panel-Table-method-showVerticalScroller'> /**
960 </span> * Shows the verticalScroller and adds the verticalScrollerPresentCls.
962 showVerticalScroller: function() {
965 me.setHeaderReserveOffset(true);
966 if (me.verticalScroller && me.verticalScroller.ownerCt !== me) {
967 me.addDocked(me.verticalScroller);
968 me.addCls(me.verticalScrollerPresentCls);
969 me.fireEvent('scrollershow', me.verticalScroller, 'vertical');
973 setHeaderReserveOffset: function (reserveOffset) {
974 var headerCt = this.headerCt,
975 layout = headerCt.layout;
977 // only trigger a layout when reserveOffset is changing
978 if (layout && layout.reserveOffset !== reserveOffset) {
979 layout.reserveOffset = reserveOffset;
980 if (!this.suspendLayout) {
986 <span id='Ext-panel-Table-method-invalidateScroller'> /**
987 </span> * Invalides scrollers that are present and forces a recalculation. (Not related to showing/hiding the scrollers)
989 invalidateScroller: function() {
991 vScroll = me.verticalScroller,
992 hScroll = me.horizontalScroller;
995 vScroll.invalidate();
998 hScroll.invalidate();
1002 // refresh the view when a header moves
1003 onHeaderMove: function(headerCt, header, fromIdx, toIdx) {
1004 this.view.refresh();
1007 // Section onHeaderHide is invoked after view.
1008 onHeaderHide: function(headerCt, header) {
1009 this.invalidateScroller();
1012 onHeaderShow: function(headerCt, header) {
1013 this.invalidateScroller();
1016 getVerticalScroller: function() {
1017 return this.getScrollerOwner().down('gridscroller[dock=' + this.verticalScrollDock + ']');
1020 getHorizontalScroller: function() {
1021 return this.getScrollerOwner().down('gridscroller[dock=bottom]');
1024 onMouseWheel: function(e) {
1026 vertScroller = me.getVerticalScroller(),
1027 horizScroller = me.getHorizontalScroller(),
1028 scrollDelta = -me.scrollDelta,
1029 deltas = e.getWheelDeltas(),
1030 deltaX = scrollDelta * deltas.x,
1031 deltaY = scrollDelta * deltas.y,
1032 vertScrollerEl, horizScrollerEl,
1033 vertScrollerElDom, horizScrollerElDom,
1034 horizontalCanScrollLeft, horizontalCanScrollRight,
1035 verticalCanScrollDown, verticalCanScrollUp;
1037 // calculate whether or not both scrollbars can scroll right/left and up/down
1038 if (horizScroller) {
1039 horizScrollerEl = horizScroller.scrollEl;
1040 if (horizScrollerEl) {
1041 horizScrollerElDom = horizScrollerEl.dom;
1042 horizontalCanScrollRight = horizScrollerElDom.scrollLeft !== horizScrollerElDom.scrollWidth - horizScrollerElDom.clientWidth;
1043 horizontalCanScrollLeft = horizScrollerElDom.scrollLeft !== 0;
1047 vertScrollerEl = vertScroller.scrollEl;
1048 if (vertScrollerEl) {
1049 vertScrollerElDom = vertScrollerEl.dom;
1050 verticalCanScrollDown = vertScrollerElDom.scrollTop !== vertScrollerElDom.scrollHeight - vertScrollerElDom.clientHeight;
1051 verticalCanScrollUp = vertScrollerElDom.scrollTop !== 0;
1055 if (horizScroller) {
1056 if ((deltaX < 0 && horizontalCanScrollLeft) || (deltaX > 0 && horizontalCanScrollRight)) {
1058 horizScroller.scrollByDeltaX(deltaX);
1062 if ((deltaY < 0 && verticalCanScrollUp) || (deltaY > 0 && verticalCanScrollDown)) {
1064 vertScroller.scrollByDeltaY(deltaY);
1069 <span id='Ext-panel-Table-method-onViewReady'> /**
1071 * Fires the TablePanel's viewready event when the view declares that its internal DOM is ready
1073 onViewReady: function() {
1075 me.fireEvent('viewready', me);
1076 if (me.deferRowRender) {
1077 me.determineScrollbars();
1078 me.invalidateScroller();
1082 <span id='Ext-panel-Table-method-onViewRefresh'> /**
1084 * Determines and invalidates scrollers on view refresh
1086 onViewRefresh: function() {
1089 // Refresh *during* render must be ignored.
1090 if (!me.rendering) {
1091 this.determineScrollbars();
1092 if (this.invalidateScrollerOnRefresh) {
1093 this.invalidateScroller();
1098 <span id='Ext-panel-Table-method-setScrollTop'> /**
1099 </span> * Sets the scrollTop of the TablePanel.
1100 * @param {Number} top
1102 setScrollTop: function(top) {
1104 rootCmp = me.getScrollerOwner(),
1105 verticalScroller = me.getVerticalScroller();
1107 rootCmp.virtualScrollTop = top;
1108 if (verticalScroller) {
1109 verticalScroller.setScrollTop(top);
1113 getScrollerOwner: function() {
1115 if (!this.scrollerOwner) {
1116 rootCmp = this.up('[scrollerOwner]');
1121 <span id='Ext-panel-Table-method-scrollByDeltaY'> /**
1122 </span> * Scrolls the TablePanel by deltaY
1123 * @param {Number} deltaY
1125 scrollByDeltaY: function(deltaY) {
1126 var verticalScroller = this.getVerticalScroller();
1128 if (verticalScroller) {
1129 verticalScroller.scrollByDeltaY(deltaY);
1133 <span id='Ext-panel-Table-method-scrollByDeltaX'> /**
1134 </span> * Scrolls the TablePanel by deltaX
1135 * @param {Number} deltaX
1137 scrollByDeltaX: function(deltaX) {
1138 var horizontalScroller = this.getHorizontalScroller();
1140 if (horizontalScroller) {
1141 horizontalScroller.scrollByDeltaX(deltaX);
1145 <span id='Ext-panel-Table-method-getLhsMarker'> /**
1146 </span> * Gets left hand side marker for header resizing.
1149 getLhsMarker: function() {
1152 if (!me.lhsMarker) {
1153 me.lhsMarker = Ext.DomHelper.append(me.el, {
1154 cls: Ext.baseCSSPrefix + 'grid-resize-marker'
1157 return me.lhsMarker;
1160 <span id='Ext-panel-Table-method-getRhsMarker'> /**
1161 </span> * Gets right hand side marker for header resizing.
1164 getRhsMarker: function() {
1167 if (!me.rhsMarker) {
1168 me.rhsMarker = Ext.DomHelper.append(me.el, {
1169 cls: Ext.baseCSSPrefix + 'grid-resize-marker'
1172 return me.rhsMarker;
1175 <span id='Ext-panel-Table-method-getSelectionModel'> /**
1176 </span> * Returns the selection model being used and creates it via the configuration if it has not been created already.
1177 * @return {Ext.selection.Model} selModel
1179 getSelectionModel: function(){
1180 if (!this.selModel) {
1184 var mode = 'SINGLE',
1186 if (this.simpleSelect) {
1188 } else if (this.multiSelect) {
1192 Ext.applyIf(this.selModel, {
1193 allowDeselect: this.allowDeselect,
1197 if (!this.selModel.events) {
1198 type = this.selModel.selType || this.selType;
1199 this.selModel = Ext.create('selection.' + type, this.selModel);
1202 if (!this.selModel.hasRelaySetup) {
1203 this.relayEvents(this.selModel, [
1204 'selectionchange', 'beforeselect', 'beforedeselect', 'select', 'deselect'
1206 this.selModel.hasRelaySetup = true;
1209 // lock the selection model if user
1210 // has disabled selection
1211 if (this.disableSelection) {
1212 this.selModel.locked = true;
1214 return this.selModel;
1217 onVerticalScroll: function(event, target) {
1218 var owner = this.getScrollerOwner(),
1219 items = owner.query('tableview'),
1223 for (; i < len; i++) {
1224 items[i].el.dom.scrollTop = target.scrollTop;
1228 onHorizontalScroll: function(event, target) {
1229 var owner = this.getScrollerOwner(),
1230 items = owner.query('tableview'),
1231 center = items[1] || items[0];
1233 center.el.dom.scrollLeft = target.scrollLeft;
1234 this.headerCt.el.dom.scrollLeft = target.scrollLeft;
1237 // template method meant to be overriden
1238 onStoreLoad: Ext.emptyFn,
1240 getEditorParent: function() {
1244 bindStore: function(store) {
1247 me.getView().bindStore(store);
1250 beforeDestroy: function(){
1251 // may be some duplication here since the horizontal and vertical
1252 // scroller may be part of the docked items, but we need to clean
1253 // them up in case they aren't visible.
1254 Ext.destroy(this.horizontalScroller, this.verticalScroller);
1258 <span id='Ext-panel-Table-method-reconfigure'> /**
1259 </span> * Reconfigures the table with a new store/columns. Either the store or the columns can be ommitted if you don't wish
1261 * @param {Ext.data.Store} store (Optional) The new store.
1262 * @param {Object[]} columns (Optional) An array of column configs
1264 reconfigure: function(store, columns) {
1266 headerCt = me.headerCt;
1269 me.reconfigureLockable(store, columns);
1272 headerCt.suspendLayout = true;
1273 headerCt.removeAll();
1274 headerCt.add(columns);
1277 store = Ext.StoreManager.lookup(store);
1278 me.bindStore(store);
1280 me.getView().refresh();
1283 headerCt.suspendLayout = false;
1284 me.forceComponentLayout();
1287 me.fireEvent('reconfigure', me);