4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>The source code</title>
6 <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7 <script type="text/javascript" src="../prettify/prettify.js"></script>
8 <style type="text/css">
9 .highlight { display: block; background-color: #ddd; }
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> * @class Ext.panel.Table
20 * @extends Ext.panel.Panel
21 * @author Nicolas Ferrero
22 * TablePanel is the basis of both TreePanel and GridPanel.
24 * TablePanel aggregates:
30 * - Ext.grid.header.Container
33 Ext.define('Ext.panel.Table', {
34 extend: 'Ext.panel.Panel',
36 alias: 'widget.tablepanel',
39 'Ext.selection.RowModel',
41 'Ext.grid.header.Container',
45 cls: Ext.baseCSSPrefix + 'grid',
46 extraBodyCls: Ext.baseCSSPrefix + 'grid-body',
49 <span id='Ext-panel-Table-property-hasView'> /**
50 </span> * Boolean to indicate that a view has been injected into the panel.
55 // each panel should dictate what viewType and selType to use
59 <span id='Ext-panel-Table-cfg-scrollDelta'> /**
60 </span> * @cfg {Number} scrollDelta
61 * Number of pixels to scroll when scrolling with mousewheel.
66 <span id='Ext-panel-Table-cfg-scroll'> /**
67 </span> * @cfg {String/Boolean} scroll
68 * Valid values are 'both', 'horizontal' or 'vertical'. true implies 'both'. false implies 'none'.
73 <span id='Ext-panel-Table-cfg-columns'> /**
74 </span> * @cfg {Array} columns
75 * An array of {@link Ext.grid.column.Column column} definition objects which define all columns that appear in this grid. Each
76 * column definition provides the header text for the column, and a definition of where the data for that column comes from.
79 <span id='Ext-panel-Table-cfg-forceFit'> /**
80 </span> * @cfg {Boolean} forceFit
81 * Specify as <code>true</code> to force the columns to fit into the available width. Headers are first sized according to configuration, whether that be
82 * a specific width, or flex. Then they are all proportionally changed in width so that the entire content width is used..
85 <span id='Ext-panel-Table-cfg-hideHeaders'> /**
86 </span> * @cfg {Boolean} hideHeaders
87 * Specify as <code>true</code> to hide the headers.
90 <span id='Ext-panel-Table-cfg-deferRowRender'> /**
91 </span> * @cfg {Boolean} deferRowRender <P>Defaults to <code>true</code> to enable deferred row rendering.</p>
92 * <p>This allows the GridView to execute a refresh quickly, with the expensive update of the row
93 * structure deferred so that layouts with GridPanels appear, and lay out more quickly.</p>
96 <span id='Ext-panel-Table-cfg-sortableColumns'> /**
97 </span> * @cfg {Boolean} sortableColumns
98 * Defaults to <code>true</code>. Set to <code>false</code> to disable column sorting via clicking the
99 * header and via the Sorting menu items.
101 sortableColumns: true,
103 verticalScrollDock: 'right',
104 verticalScrollerType: 'gridscroller',
106 horizontalScrollerPresentCls: Ext.baseCSSPrefix + 'horizontal-scroller-present',
107 verticalScrollerPresentCls: Ext.baseCSSPrefix + 'vertical-scroller-present',
109 // private property used to determine where to go down to find views
110 // this is here to support locking.
113 invalidateScrollerOnRefresh: true,
115 <span id='Ext-panel-Table-cfg-enableColumnMove'> /**
116 </span> * @cfg {Boolean} enableColumnMove
117 * Defaults to <code>true</code>. Set to <code>false</code> to disable column dragging within this grid.
119 enableColumnMove: true,
121 <span id='Ext-panel-Table-cfg-enableColumnResize'> /**
122 </span> * @cfg {Boolean} enableColumnResize
123 * Defaults to <code>true</code>. Set to <code>false</code> to disable column resizing within this grid.
125 enableColumnResize: true,
127 <span id='Ext-panel-Table-cfg-enableColumnHide'> /**
128 </span> * @cfg {Boolean} enableColumnHide
129 * Defaults to <code>true</code>. Set to <code>false</code> to disable column hiding within this grid.
131 enableColumnHide: true,
133 initComponent: function() {
135 if (!this.viewType) {
136 Ext.Error.raise("You must specify a viewType config.");
139 Ext.Error.raise("You must specify a store config");
142 Ext.Error.raise("The headers config is not supported. Please specify columns instead.");
150 headerCtCfg = me.columns || me.colModel,
155 // We cannot buffer this because that will wait for the 30msec from afterLayout (or what
156 // ever event triggers it) and we may be in the middle of an animation; that is a bad
157 // time to injectView because it causes a layout (by calling add on the container). A
158 // throttled func will be called immediately on first call and then block subsequent
159 // (rapid fire) calls for 30msec before allowing another call to go through. Similar
160 // results, but the action moves from the trailing edge of the interval to the leading
162 me.injectView = Ext.Function.createThrottled(me.injectView, 30, me);
164 if (me.hideHeaders) {
168 // The columns/colModel config may be either a fully instantiated HeaderContainer, or an array of Column definitions, or a config object of a HeaderContainer
169 // Either way, we extract a columns property referencing an array of Column definitions.
170 if (headerCtCfg instanceof Ext.grid.header.Container) {
171 me.headerCt = headerCtCfg;
172 me.headerCt.border = border;
173 me.columns = me.headerCt.items.items;
175 if (Ext.isArray(headerCtCfg)) {
181 Ext.apply(headerCtCfg, {
182 forceFit: me.forceFit,
183 sortable: me.sortableColumns,
184 enableColumnMove: me.enableColumnMove,
185 enableColumnResize: me.enableColumnResize,
186 enableColumnHide: me.enableColumnHide,
189 me.columns = headerCtCfg.items;
191 // If any of the Column objects contain a locked property, and are not processed, this is a lockable TablePanel, a
192 // special view will be injected by the Ext.grid.Lockable mixin, so no processing of .
193 if (Ext.ComponentQuery.query('{locked !== undefined}{processed != true}', me.columns).length) {
194 me.self.mixin('lockable', Ext.grid.Lockable);
199 me.store = Ext.data.StoreManager.lookup(me.store);
201 <span id='Ext-panel-Table-event-reconfigure'> /**
202 </span> * @event reconfigure
203 * Fires after a reconfigure
204 * @param {Ext.panel.Table} this
207 <span id='Ext-panel-Table-event-scrollerhide'> /**
208 </span> * @event scrollerhide
209 * Fires when a scroller is hidden
210 * @param {Ext.grid.Scroller} scroller
211 * @param {String} orientation Orientation, can be 'vertical' or 'horizontal'
214 <span id='Ext-panel-Table-event-scrollershow'> /**
215 </span> * @event scrollershow
216 * Fires when a scroller is shown
217 * @param {Ext.grid.Scroller} scroller
218 * @param {String} orientation Orientation, can be 'vertical' or 'horizontal'
223 me.bodyCls = me.bodyCls || '';
224 me.bodyCls += (' ' + me.extraBodyCls);
226 // autoScroll is not a valid configuration
227 delete me.autoScroll;
229 // If this TablePanel is lockable (Either configured lockable, or any of the defined columns has a 'locked' property)
230 // 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.
233 // If we were not configured with a ready-made headerCt (either by direct config with a headerCt property, or by passing
234 // a HeaderContainer instance as the 'columns' property, then go ahead and create one from the config object created above.
236 me.headerCt = Ext.create('Ext.grid.header.Container', headerCtCfg);
239 // Extract the array of Column objects
240 me.columns = me.headerCt.items.items;
242 if (me.hideHeaders) {
243 me.headerCt.height = 0;
244 me.headerCt.border = false;
245 me.headerCt.addCls(Ext.baseCSSPrefix + 'grid-header-ct-hidden');
246 me.addCls(Ext.baseCSSPrefix + 'grid-header-hidden');
247 // IE Quirks Mode fix
248 // If hidden configuration option was used, several layout calculations will be bypassed.
249 if (Ext.isIEQuirks) {
250 me.headerCt.style = {
257 if (scroll === true || scroll === 'both') {
258 vertical = horizontal = true;
259 } else if (scroll === 'horizontal') {
261 } else if (scroll === 'vertical') {
263 // All other values become 'none' or false.
265 me.headerCt.availableSpaceOffset = 0;
269 me.verticalScroller = Ext.ComponentManager.create(me.initVerticalScroller());
270 me.mon(me.verticalScroller, {
271 bodyscroll: me.onVerticalScroll,
277 me.horizontalScroller = Ext.ComponentManager.create(me.initHorizontalScroller());
278 me.mon(me.horizontalScroller, {
279 bodyscroll: me.onHorizontalScroll,
284 me.headerCt.on('columnresize', me.onHeaderResize, me);
285 me.relayEvents(me.headerCt, ['columnresize', 'columnmove', 'columnhide', 'columnshow', 'sortchange']);
286 me.features = me.features || [];
287 me.dockedItems = me.dockedItems || [];
288 me.dockedItems.unshift(me.headerCt);
289 me.viewConfig = me.viewConfig || {};
290 me.viewConfig.invalidateScrollerOnRefresh = me.invalidateScrollerOnRefresh;
292 // AbstractDataView will look up a Store configured as an object
293 // getView converts viewConfig into a View instance
298 load: me.onStoreLoad,
302 refresh: me.onViewRefresh,
305 this.relayEvents(view, [
306 <span id='Ext-panel-Table-event-beforeitemmousedown'> /**
307 </span> * @event beforeitemmousedown
308 * Fires before the mousedown event on an item is processed. Returns false to cancel the default action.
309 * @param {Ext.view.View} this
310 * @param {Ext.data.Model} record The record that belongs to the item
311 * @param {HTMLElement} item The item's element
312 * @param {Number} index The item's index
313 * @param {Ext.EventObject} e The raw event object
315 'beforeitemmousedown',
316 <span id='Ext-panel-Table-event-beforeitemmouseup'> /**
317 </span> * @event beforeitemmouseup
318 * Fires before the mouseup event on an item is processed. Returns false to cancel the default action.
319 * @param {Ext.view.View} this
320 * @param {Ext.data.Model} record The record that belongs to the item
321 * @param {HTMLElement} item The item's element
322 * @param {Number} index The item's index
323 * @param {Ext.EventObject} e The raw event object
326 <span id='Ext-panel-Table-event-beforeitemmouseenter'> /**
327 </span> * @event beforeitemmouseenter
328 * Fires before the mouseenter event on an item is processed. Returns false to cancel the default action.
329 * @param {Ext.view.View} this
330 * @param {Ext.data.Model} record The record that belongs to the item
331 * @param {HTMLElement} item The item's element
332 * @param {Number} index The item's index
333 * @param {Ext.EventObject} e The raw event object
335 'beforeitemmouseenter',
336 <span id='Ext-panel-Table-event-beforeitemmouseleave'> /**
337 </span> * @event beforeitemmouseleave
338 * Fires before the mouseleave event on an item is processed. Returns false to cancel the default action.
339 * @param {Ext.view.View} this
340 * @param {Ext.data.Model} record The record that belongs to the item
341 * @param {HTMLElement} item The item's element
342 * @param {Number} index The item's index
343 * @param {Ext.EventObject} e The raw event object
345 'beforeitemmouseleave',
346 <span id='Ext-panel-Table-event-beforeitemclick'> /**
347 </span> * @event beforeitemclick
348 * Fires before the click event on an item is processed. Returns false to cancel the default action.
349 * @param {Ext.view.View} this
350 * @param {Ext.data.Model} record The record that belongs to the item
351 * @param {HTMLElement} item The item's element
352 * @param {Number} index The item's index
353 * @param {Ext.EventObject} e The raw event object
356 <span id='Ext-panel-Table-event-beforeitemdblclick'> /**
357 </span> * @event beforeitemdblclick
358 * Fires before the dblclick event on an item is processed. Returns false to cancel the default action.
359 * @param {Ext.view.View} this
360 * @param {Ext.data.Model} record The record that belongs to the item
361 * @param {HTMLElement} item The item's element
362 * @param {Number} index The item's index
363 * @param {Ext.EventObject} e The raw event object
365 'beforeitemdblclick',
366 <span id='Ext-panel-Table-event-beforeitemcontextmenu'> /**
367 </span> * @event beforeitemcontextmenu
368 * Fires before the contextmenu event on an item is processed. Returns false to cancel the default action.
369 * @param {Ext.view.View} this
370 * @param {Ext.data.Model} record The record that belongs to the item
371 * @param {HTMLElement} item The item's element
372 * @param {Number} index The item's index
373 * @param {Ext.EventObject} e The raw event object
375 'beforeitemcontextmenu',
376 <span id='Ext-panel-Table-event-itemmousedown'> /**
377 </span> * @event itemmousedown
378 * Fires when there is a mouse down on an item
379 * @param {Ext.view.View} this
380 * @param {Ext.data.Model} record The record that belongs to the item
381 * @param {HTMLElement} item The item's element
382 * @param {Number} index The item's index
383 * @param {Ext.EventObject} e The raw event object
386 <span id='Ext-panel-Table-event-itemmouseup'> /**
387 </span> * @event itemmouseup
388 * Fires when there is a mouse up on an item
389 * @param {Ext.view.View} this
390 * @param {Ext.data.Model} record The record that belongs to the item
391 * @param {HTMLElement} item The item's element
392 * @param {Number} index The item's index
393 * @param {Ext.EventObject} e The raw event object
396 <span id='Ext-panel-Table-event-itemmouseenter'> /**
397 </span> * @event itemmouseenter
398 * Fires when the mouse enters an item.
399 * @param {Ext.view.View} this
400 * @param {Ext.data.Model} record The record that belongs to the item
401 * @param {HTMLElement} item The item's element
402 * @param {Number} index The item's index
403 * @param {Ext.EventObject} e The raw event object
406 <span id='Ext-panel-Table-event-itemmouseleave'> /**
407 </span> * @event itemmouseleave
408 * Fires when the mouse leaves an item.
409 * @param {Ext.view.View} this
410 * @param {Ext.data.Model} record The record that belongs to the item
411 * @param {HTMLElement} item The item's element
412 * @param {Number} index The item's index
413 * @param {Ext.EventObject} e The raw event object
416 <span id='Ext-panel-Table-event-itemclick'> /**
417 </span> * @event itemclick
418 * Fires when an item is clicked.
419 * @param {Ext.view.View} this
420 * @param {Ext.data.Model} record The record that belongs to the item
421 * @param {HTMLElement} item The item's element
422 * @param {Number} index The item's index
423 * @param {Ext.EventObject} e The raw event object
426 <span id='Ext-panel-Table-event-itemdblclick'> /**
427 </span> * @event itemdblclick
428 * Fires when an item is double clicked.
429 * @param {Ext.view.View} this
430 * @param {Ext.data.Model} record The record that belongs to the item
431 * @param {HTMLElement} item The item's element
432 * @param {Number} index The item's index
433 * @param {Ext.EventObject} e The raw event object
436 <span id='Ext-panel-Table-event-itemcontextmenu'> /**
437 </span> * @event itemcontextmenu
438 * Fires when an item is right clicked.
439 * @param {Ext.view.View} this
440 * @param {Ext.data.Model} record The record that belongs to the item
441 * @param {HTMLElement} item The item's element
442 * @param {Number} index The item's index
443 * @param {Ext.EventObject} e The raw event object
446 <span id='Ext-panel-Table-event-beforecontainermousedown'> /**
447 </span> * @event beforecontainermousedown
448 * Fires before the mousedown event on the container is processed. Returns false to cancel the default action.
449 * @param {Ext.view.View} this
450 * @param {Ext.EventObject} e The raw event object
452 'beforecontainermousedown',
453 <span id='Ext-panel-Table-event-beforecontainermouseup'> /**
454 </span> * @event beforecontainermouseup
455 * Fires before the mouseup event on the container is processed. Returns false to cancel the default action.
456 * @param {Ext.view.View} this
457 * @param {Ext.EventObject} e The raw event object
459 'beforecontainermouseup',
460 <span id='Ext-panel-Table-event-beforecontainermouseover'> /**
461 </span> * @event beforecontainermouseover
462 * Fires before the mouseover event on the container is processed. Returns false to cancel the default action.
463 * @param {Ext.view.View} this
464 * @param {Ext.EventObject} e The raw event object
466 'beforecontainermouseover',
467 <span id='Ext-panel-Table-event-beforecontainermouseout'> /**
468 </span> * @event beforecontainermouseout
469 * Fires before the mouseout event on the container is processed. Returns false to cancel the default action.
470 * @param {Ext.view.View} this
471 * @param {Ext.EventObject} e The raw event object
473 'beforecontainermouseout',
474 <span id='Ext-panel-Table-event-beforecontainerclick'> /**
475 </span> * @event beforecontainerclick
476 * Fires before the click event on the container is processed. Returns false to cancel the default action.
477 * @param {Ext.view.View} this
478 * @param {Ext.EventObject} e The raw event object
480 'beforecontainerclick',
481 <span id='Ext-panel-Table-event-beforecontainerdblclick'> /**
482 </span> * @event beforecontainerdblclick
483 * Fires before the dblclick event on the container is processed. Returns false to cancel the default action.
484 * @param {Ext.view.View} this
485 * @param {Ext.EventObject} e The raw event object
487 'beforecontainerdblclick',
488 <span id='Ext-panel-Table-event-beforecontainercontextmenu'> /**
489 </span> * @event beforecontainercontextmenu
490 * Fires before the contextmenu event on the container is processed. Returns false to cancel the default action.
491 * @param {Ext.view.View} this
492 * @param {Ext.EventObject} e The raw event object
494 'beforecontainercontextmenu',
495 <span id='Ext-panel-Table-event-containermouseup'> /**
496 </span> * @event containermouseup
497 * Fires when there is a mouse up on the container
498 * @param {Ext.view.View} this
499 * @param {Ext.EventObject} e The raw event object
502 <span id='Ext-panel-Table-event-containermouseover'> /**
503 </span> * @event containermouseover
504 * Fires when you move the mouse over the container.
505 * @param {Ext.view.View} this
506 * @param {Ext.EventObject} e The raw event object
508 'containermouseover',
509 <span id='Ext-panel-Table-event-containermouseout'> /**
510 </span> * @event containermouseout
511 * Fires when you move the mouse out of the container.
512 * @param {Ext.view.View} this
513 * @param {Ext.EventObject} e The raw event object
516 <span id='Ext-panel-Table-event-containerclick'> /**
517 </span> * @event containerclick
518 * Fires when the container is clicked.
519 * @param {Ext.view.View} this
520 * @param {Ext.EventObject} e The raw event object
523 <span id='Ext-panel-Table-event-containerdblclick'> /**
524 </span> * @event containerdblclick
525 * Fires when the container is double clicked.
526 * @param {Ext.view.View} this
527 * @param {Ext.EventObject} e The raw event object
530 <span id='Ext-panel-Table-event-containercontextmenu'> /**
531 </span> * @event containercontextmenu
532 * Fires when the container is right clicked.
533 * @param {Ext.view.View} this
534 * @param {Ext.EventObject} e The raw event object
536 'containercontextmenu',
538 <span id='Ext-panel-Table-event-selectionchange'> /**
539 </span> * @event selectionchange
540 * Fires when the selected nodes change. Relayed event from the underlying selection model.
541 * @param {Ext.view.View} this
542 * @param {Array} selections Array of the selected nodes
545 <span id='Ext-panel-Table-event-beforeselect'> /**
546 </span> * @event beforeselect
547 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
548 * @param {Ext.view.View} this
549 * @param {HTMLElement} node The node to be selected
550 * @param {Array} selections Array of currently selected nodes
556 me.callParent(arguments);
560 initStateEvents: function(){
561 var events = this.stateEvents;
562 // push on stateEvents if they don't exist
563 Ext.each(['columnresize', 'columnmove', 'columnhide', 'columnshow', 'sortchange'], function(event){
564 if (Ext.Array.indexOf(events, event)) {
571 <span id='Ext-panel-Table-method-initHorizontalScroller'> /**
572 </span> * Returns the horizontal scroller config.
574 initHorizontalScroller: function () {
577 xtype: 'gridscroller',
586 <span id='Ext-panel-Table-method-initVerticalScroller'> /**
587 </span> * Returns the vertical scroller config.
589 initVerticalScroller: function () {
591 ret = me.verticalScroller || {};
594 xtype: me.verticalScrollerType,
595 dock: me.verticalScrollDock,
602 getState: function(){
603 var state = this.callParent(),
604 sorter = this.store.sorters.first(),
605 headers = this.headerCt.items.items,
607 len = headers.length,
611 for (; i < len; i++) {
617 // We only store state which has changed from the initial state.
618 // So that current software settings do not override future software settings.
619 // Only user-changed state should be saved.
620 if (header.hidden !== (header.initialConfig.hidden||header.self.prototype.hidden)) {
621 state.columns[i].hidden = header.hidden;
623 if (header.sortable !== header.initialConfig.sortable) {
624 state.columns[i].sortable = header.sortable;
627 if (header.flex !== header.initialConfig.flex) {
628 state.columns[i].flex = header.flex;
631 if (header.width !== header.initialConfig.width) {
632 state.columns[i].width = header.width;
639 property: sorter.property,
640 direction: sorter.direction
646 applyState: function(state) {
647 var headers = state.columns,
648 length = headers ? headers.length : 0,
649 headerCt = this.headerCt,
650 items = headerCt.items,
658 headerCt.suspendLayout = true;
660 // Ensure superclass has applied *its* state.
661 // AbstractComponent saves dimensions (and anchor/flex) plus collapsed state.
662 this.callParent(arguments);
664 for (; i < length; ++i) {
665 headerState = headers[i];
666 header = headerCt.down('gridcolumn[headerId=' + headerState.id + ']');
667 index = items.indexOf(header);
669 headerCt.moveHeader(index, i);
672 // Only state properties which were saved should be restored.
673 // (Only user-changed properties were saved by getState)
674 if (Ext.isDefined(headerState.hidden)) {
675 header.hidden = headerState.hidden;
677 if (Ext.isDefined(headerState.sortable)) {
678 header.sortable = headerState.sortable;
680 if (Ext.isDefined(headerState.flex)) {
682 header.flex = headerState.flex;
683 } else if (Ext.isDefined(headerState.width)) {
685 header.minWidth = headerState.width;
686 if (header.rendered) {
687 header.setWidth(headerState.width);
689 header.width = headerState.width;
693 headerCt.suspendLayout = false;
695 // After setting width and flexes while layout is suspended, column Container's Container layout needs running.
699 if (store.remoteSort) {
700 store.sorters.add(Ext.create('Ext.util.Sorter', {
701 property: sorter.property,
702 direction: sorter.direction
706 store.sort(sorter.property, sorter.direction);
711 <span id='Ext-panel-Table-method-getStore'> /**
712 </span> * Returns the store associated with this Panel.
713 * @return {Ext.data.Store} The store
715 getStore: function(){
719 <span id='Ext-panel-Table-method-getView'> /**
720 </span> * Gets the view for this panel.
721 * @return {Ext.view.Table}
723 getView: function() {
728 sm = me.getSelectionModel();
729 me.view = me.createComponent(Ext.apply({}, me.viewConfig, {
730 deferRowRender: me.deferRowRender,
733 headerCt: me.headerCt,
735 features: me.features,
739 uievent: me.processEvent,
743 me.headerCt.view = me.view;
744 me.relayEvents(me.view, ['cellclick', 'celldblclick']);
749 <span id='Ext-panel-Table-property-setAutoScroll'> /**
752 * autoScroll is never valid for all classes which extend TablePanel.
754 setAutoScroll: Ext.emptyFn,
756 // This method hijacks Ext.view.Table's el scroll method.
757 // This enables us to keep the virtualized scrollbars in sync
758 // with the view. It currently does NOT support animation.
759 elScroll: function(direction, distance, animate) {
763 if (direction === "up" || direction === "left") {
764 distance = -distance;
767 if (direction === "down" || direction === "up") {
768 scroller = me.getVerticalScroller();
769 scroller.scrollByDeltaY(distance);
771 scroller = me.getHorizontalScroller();
772 scroller.scrollByDeltaX(distance);
776 <span id='Ext-panel-Table-method-injectView'> /**
778 * Called after this Component has achieved its correct initial size, after all layouts have done their thing.
779 * This is so we can add the View only after the initial size is known. This method is throttled 30ms.
781 injectView: function() {
782 if (!this.hasView && !this.collapsed) {
789 function viewReady () {
790 // hijack the view el's scroll method
791 view.el.scroll = Ext.Function.bind(me.elScroll, me);
792 // We use to listen to document.body wheel events, but that's a
793 // little much. We scope just to the view now.
795 mousewheel: me.onMouseWheel,
799 me.doComponentLayout();
807 afterrender: viewReady,
814 afterExpand: function() {
815 // TODO - this is *not* called when part of an accordion!
816 this.callParent(arguments);
822 <span id='Ext-panel-Table-method-processEvent'> /**
824 * Process UI events from the view. Propagate them to whatever internal Components need to process them
825 * @param {String} type Event type, eg 'click'
826 * @param {TableView} view TableView Component
827 * @param {HtmlElement} cell Cell HtmlElement the event took place within
828 * @param {Number} recordIndex Index of the associated Store Model (-1 if none)
829 * @param {Number} cellIndex Cell index within the row
830 * @param {EventObject} e Original event
832 processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
836 if (cellIndex !== -1) {
837 header = me.headerCt.getGridColumns()[cellIndex];
838 return header.processEvent.apply(header, arguments);
842 <span id='Ext-panel-Table-method-determineScrollbars'> /**
843 </span> * Request a recalculation of scrollbars and put them in if they are needed.
845 determineScrollbars: function() {
853 verticalScroller = me.verticalScroller,
854 horizontalScroller = me.horizontalScroller,
855 curScrollbars = (verticalScroller && verticalScroller.ownerCt === me ? 1 : 0) |
856 (horizontalScroller && horizontalScroller.ownerCt === me ? 2 : 0),
857 reqScrollbars = 0; // 1 = vertical, 2 = horizontal, 3 = both
859 // If we are not collapsed, and the view has been rendered AND filled, then we can determine scrollbars
860 if (!me.collapsed && me.view && me.view.el && me.view.el.dom.firstChild) {
862 // Calculate maximum, *scrollbarless* space which the view has available.
863 // It will be the Fit Layout's calculated size, plus the widths of any currently shown scrollbars
864 box = me.layout.getLayoutTargetSize();
865 clientWidth = box.width + ((curScrollbars & 1) ? verticalScroller.width : 0);
866 clientHeight = box.height + ((curScrollbars & 2) ? horizontalScroller.height : 0);
868 // Calculate the width of the scrolling block
869 // There will never be a horizontal scrollbar if all columns are flexed.
871 scrollWidth = (me.headerCt.query('[flex]').length && !me.headerCt.layout.tooNarrow) ? 0 : me.headerCt.getFullWidth();
873 // Calculate the height of the scrolling block
874 if (verticalScroller && verticalScroller.el) {
875 scrollHeight = verticalScroller.getSizeCalculation().height;
877 tableEl = me.view.el.child('table', true);
878 scrollHeight = tableEl ? tableEl.offsetHeight : 0;
882 // Definitely need a vertical scrollbar
883 if (scrollHeight > clientHeight) {
886 // But if scrollable block width goes into the zone required by the vertical scrollbar, we'll also need a horizontal
887 if (horizontalScroller && ((clientWidth - scrollWidth) < verticalScroller.width)) {
892 // View height fits. But we stil may need a horizontal scrollbar, and this might necessitate a vertical one.
895 // Definitely need a horizontal scrollbar
896 if (scrollWidth > clientWidth) {
899 // But if scrollable block height goes into the zone required by the horizontal scrollbar, we'll also need a vertical
900 if (verticalScroller && ((clientHeight - scrollHeight) < horizontalScroller.height)) {
906 // If scrollbar requirements have changed, change 'em...
907 if (reqScrollbars !== curScrollbars) {
909 // Suspend component layout while we add/remove the docked scrollers
910 me.suspendLayout = true;
911 if (reqScrollbars & 1) {
912 me.showVerticalScroller();
914 me.hideVerticalScroller();
916 if (reqScrollbars & 2) {
917 me.showHorizontalScroller();
919 me.hideHorizontalScroller();
921 me.suspendLayout = false;
923 // After docked scrollers are correctly configured, lay out the Component.
924 // Set a flag so that afterComponentLayout does not recurse back into here.
925 me.changingScrollBars = true;
926 me.doComponentLayout(me.getWidth(), me.getHeight(), false, me.ownerCt);
927 me.changingScrollBars = false;
932 afterComponentLayout: function() {
934 me.callParent(arguments);
936 // Insert the View the first time the Panel has a Component layout performed.
940 if (!me.changingScrollBars) {
941 me.determineScrollbars();
943 me.invalidateScroller();
946 onHeaderResize: function() {
947 if (this.view && this.view.rendered) {
948 this.determineScrollbars();
949 this.invalidateScroller();
953 afterCollapse: function() {
955 if (me.verticalScroller) {
956 me.verticalScroller.saveScrollPos();
958 if (me.horizontalScroller) {
959 me.horizontalScroller.saveScrollPos();
961 me.callParent(arguments);
964 afterExpand: function() {
966 me.callParent(arguments);
967 if (me.verticalScroller) {
968 me.verticalScroller.restoreScrollPos();
970 if (me.horizontalScroller) {
971 me.horizontalScroller.restoreScrollPos();
975 <span id='Ext-panel-Table-method-hideHorizontalScroller'> /**
976 </span> * Hide the verticalScroller and remove the horizontalScrollerPresentCls.
978 hideHorizontalScroller: function() {
981 if (me.horizontalScroller && me.horizontalScroller.ownerCt === me) {
982 me.verticalScroller.setReservedSpace(0);
983 me.removeDocked(me.horizontalScroller, false);
984 me.removeCls(me.horizontalScrollerPresentCls);
985 me.fireEvent('scrollerhide', me.horizontalScroller, 'horizontal');
990 <span id='Ext-panel-Table-method-showHorizontalScroller'> /**
991 </span> * Show the horizontalScroller and add the horizontalScrollerPresentCls.
993 showHorizontalScroller: function() {
996 if (me.verticalScroller) {
997 me.verticalScroller.setReservedSpace(Ext.getScrollbarSize().height - 1);
999 if (me.horizontalScroller && me.horizontalScroller.ownerCt !== me) {
1000 me.addDocked(me.horizontalScroller);
1001 me.addCls(me.horizontalScrollerPresentCls);
1002 me.fireEvent('scrollershow', me.horizontalScroller, 'horizontal');
1006 <span id='Ext-panel-Table-method-hideVerticalScroller'> /**
1007 </span> * Hide the verticalScroller and remove the verticalScrollerPresentCls.
1009 hideVerticalScroller: function() {
1012 me.setHeaderReserveOffset(false);
1013 if (me.verticalScroller && me.verticalScroller.ownerCt === me) {
1014 me.removeDocked(me.verticalScroller, false);
1015 me.removeCls(me.verticalScrollerPresentCls);
1016 me.fireEvent('scrollerhide', me.verticalScroller, 'vertical');
1020 <span id='Ext-panel-Table-method-showVerticalScroller'> /**
1021 </span> * Show the verticalScroller and add the verticalScrollerPresentCls.
1023 showVerticalScroller: function() {
1026 me.setHeaderReserveOffset(true);
1027 if (me.verticalScroller && me.verticalScroller.ownerCt !== me) {
1028 me.addDocked(me.verticalScroller);
1029 me.addCls(me.verticalScrollerPresentCls);
1030 me.fireEvent('scrollershow', me.verticalScroller, 'vertical');
1034 setHeaderReserveOffset: function (reserveOffset) {
1035 var headerCt = this.headerCt,
1036 layout = headerCt.layout;
1038 // only trigger a layout when reserveOffset is changing
1039 if (layout && layout.reserveOffset !== reserveOffset) {
1040 layout.reserveOffset = reserveOffset;
1041 headerCt.doLayout();
1045 <span id='Ext-panel-Table-method-invalidateScroller'> /**
1046 </span> * Invalides scrollers that are present and forces a recalculation.
1047 * (Not related to showing/hiding the scrollers)
1049 invalidateScroller: function() {
1051 vScroll = me.verticalScroller,
1052 hScroll = me.horizontalScroller;
1055 vScroll.invalidate();
1058 hScroll.invalidate();
1062 // refresh the view when a header moves
1063 onHeaderMove: function(headerCt, header, fromIdx, toIdx) {
1064 this.view.refresh();
1067 // Section onHeaderHide is invoked after view.
1068 onHeaderHide: function(headerCt, header) {
1069 this.invalidateScroller();
1072 onHeaderShow: function(headerCt, header) {
1073 this.invalidateScroller();
1076 getVerticalScroller: function() {
1077 return this.getScrollerOwner().down('gridscroller[dock=' + this.verticalScrollDock + ']');
1080 getHorizontalScroller: function() {
1081 return this.getScrollerOwner().down('gridscroller[dock=bottom]');
1084 onMouseWheel: function(e) {
1086 vertScroller = me.getVerticalScroller(),
1087 horizScroller = me.getHorizontalScroller(),
1088 scrollDelta = me.scrollDelta / -5,
1089 deltas = e.getWheelDeltas(),
1090 deltaX = scrollDelta * deltas.x,
1091 deltaY = scrollDelta * deltas.y,
1092 vertScrollerEl, horizScrollerEl,
1093 vertScrollerElDom, horizScrollerElDom,
1094 horizontalCanScrollLeft, horizontalCanScrollRight,
1095 verticalCanScrollDown, verticalCanScrollUp;
1097 // calculate whether or not both scrollbars can scroll right/left and up/down
1098 if (horizScroller) {
1099 horizScrollerEl = horizScroller.scrollEl;
1100 if (horizScrollerEl) {
1101 horizScrollerElDom = horizScrollerEl.dom;
1102 horizontalCanScrollRight = horizScrollerElDom.scrollLeft !== horizScrollerElDom.scrollWidth - horizScrollerElDom.clientWidth;
1103 horizontalCanScrollLeft = horizScrollerElDom.scrollLeft !== 0;
1107 vertScrollerEl = vertScroller.scrollEl;
1108 if (vertScrollerEl) {
1109 vertScrollerElDom = vertScrollerEl.dom;
1110 verticalCanScrollDown = vertScrollerElDom.scrollTop !== vertScrollerElDom.scrollHeight - vertScrollerElDom.clientHeight;
1111 verticalCanScrollUp = vertScrollerElDom.scrollTop !== 0;
1115 if (horizScroller) {
1116 if ((deltaX < 0 && horizontalCanScrollLeft) || (deltaX > 0 && horizontalCanScrollRight)) {
1118 horizScroller.scrollByDeltaX(deltaX);
1122 if ((deltaY < 0 && verticalCanScrollUp) || (deltaY > 0 && verticalCanScrollDown)) {
1124 vertScroller.scrollByDeltaY(deltaY);
1129 <span id='Ext-panel-Table-method-onViewRefresh'> /**
1131 * Determine and invalidate scrollers on view refresh
1133 onViewRefresh: function() {
1134 this.determineScrollbars();
1135 if (this.invalidateScrollerOnRefresh) {
1136 this.invalidateScroller();
1140 <span id='Ext-panel-Table-method-setScrollTop'> /**
1141 </span> * Sets the scrollTop of the TablePanel.
1142 * @param {Number} deltaY
1144 setScrollTop: function(top) {
1146 rootCmp = me.getScrollerOwner(),
1147 verticalScroller = me.getVerticalScroller();
1149 rootCmp.virtualScrollTop = top;
1150 if (verticalScroller) {
1151 verticalScroller.setScrollTop(top);
1155 getScrollerOwner: function() {
1157 if (!this.scrollerOwner) {
1158 rootCmp = this.up('[scrollerOwner]');
1163 <span id='Ext-panel-Table-method-scrollByDeltaY'> /**
1164 </span> * Scrolls the TablePanel by deltaY
1165 * @param {Number} deltaY
1167 scrollByDeltaY: function(deltaY) {
1168 var verticalScroller = this.getVerticalScroller();
1170 if (verticalScroller) {
1171 verticalScroller.scrollByDeltaY(deltaY);
1175 <span id='Ext-panel-Table-method-scrollByDeltaX'> /**
1176 </span> * Scrolls the TablePanel by deltaX
1177 * @param {Number} deltaY
1179 scrollByDeltaX: function(deltaX) {
1180 var horizontalScroller = this.getVerticalScroller();
1182 if (horizontalScroller) {
1183 horizontalScroller.scrollByDeltaX(deltaX);
1187 <span id='Ext-panel-Table-method-getLhsMarker'> /**
1188 </span> * Get left hand side marker for header resizing.
1191 getLhsMarker: function() {
1194 if (!me.lhsMarker) {
1195 me.lhsMarker = Ext.core.DomHelper.append(me.el, {
1196 cls: Ext.baseCSSPrefix + 'grid-resize-marker'
1199 return me.lhsMarker;
1202 <span id='Ext-panel-Table-method-getRhsMarker'> /**
1203 </span> * Get right hand side marker for header resizing.
1206 getRhsMarker: function() {
1209 if (!me.rhsMarker) {
1210 me.rhsMarker = Ext.core.DomHelper.append(me.el, {
1211 cls: Ext.baseCSSPrefix + 'grid-resize-marker'
1214 return me.rhsMarker;
1217 <span id='Ext-panel-Table-method-getSelectionModel'> /**
1218 </span> * Returns the selection model being used and creates it via the configuration
1219 * if it has not been created already.
1220 * @return {Ext.selection.Model} selModel
1222 getSelectionModel: function(){
1223 if (!this.selModel) {
1227 var mode = 'SINGLE',
1229 if (this.simpleSelect) {
1231 } else if (this.multiSelect) {
1235 Ext.applyIf(this.selModel, {
1236 allowDeselect: this.allowDeselect,
1240 if (!this.selModel.events) {
1241 type = this.selModel.selType || this.selType;
1242 this.selModel = Ext.create('selection.' + type, this.selModel);
1245 if (!this.selModel.hasRelaySetup) {
1246 this.relayEvents(this.selModel, [
1247 'selectionchange', 'beforeselect', 'beforedeselect', 'select', 'deselect'
1249 this.selModel.hasRelaySetup = true;
1252 // lock the selection model if user
1253 // has disabled selection
1254 if (this.disableSelection) {
1255 this.selModel.locked = true;
1257 return this.selModel;
1260 onVerticalScroll: function(event, target) {
1261 var owner = this.getScrollerOwner(),
1262 items = owner.query('tableview'),
1266 for (; i < len; i++) {
1267 items[i].el.dom.scrollTop = target.scrollTop;
1271 onHorizontalScroll: function(event, target) {
1272 var owner = this.getScrollerOwner(),
1273 items = owner.query('tableview'),
1274 center = items[1] || items[0];
1276 center.el.dom.scrollLeft = target.scrollLeft;
1277 this.headerCt.el.dom.scrollLeft = target.scrollLeft;
1280 // template method meant to be overriden
1281 onStoreLoad: Ext.emptyFn,
1283 getEditorParent: function() {
1287 bindStore: function(store) {
1290 me.getView().bindStore(store);
1293 <span id='Ext-panel-Table-method-reconfigure'> /**
1294 </span> * Reconfigure the table with a new store/column.
1295 * Either the store or the column can be ommitted if you don't wish to change them.
1296 * @param {Ext.data.Store} store The new store.
1297 * @param {Array} columns An array of column configs
1299 reconfigure: function(store, columns) {
1301 headerCt = me.headerCt;
1304 me.reconfigureLockable(store, columns);
1306 headerCt.suspendLayout = true;
1307 headerCt.removeAll();
1309 headerCt.add(columns);
1311 headerCt.doLayout();
1314 store = Ext.StoreManager.lookup(store);
1315 me.bindStore(store);
1317 me.getView().refresh();
1320 me.forceComponentLayout();
1323 me.fireEvent('reconfigure', me);