*/
/**
- * @class Ext.panel.Table
- * @extends Ext.panel.Panel
* @author Nicolas Ferrero
- * TablePanel is the basis of both TreePanel and GridPanel.
+ *
+ * TablePanel is the basis of both {@link Ext.tree.Panel TreePanel} and {@link Ext.grid.Panel GridPanel}.
*
* TablePanel aggregates:
*
* - a Store
* - Scrollers
* - Ext.grid.header.Container
- *
*/
Ext.define('Ext.panel.Table', {
extend: 'Ext.panel.Panel',
'Ext.grid.Lockable'
],
- cls: Ext.baseCSSPrefix + 'grid',
+ extraBaseCls: Ext.baseCSSPrefix + 'grid',
extraBodyCls: Ext.baseCSSPrefix + 'grid-body',
layout: 'fit',
/**
- * Boolean to indicate that a view has been injected into the panel.
- * @property hasView
+ * @property {Boolean} hasView
+ * True to indicate that a view has been injected into the panel.
*/
hasView: false,
// each panel should dictate what viewType and selType to use
+ /**
+ * @cfg {String} viewType
+ * An xtype of view to use. This is automatically set to 'gridview' by {@link Ext.grid.Panel Grid}
+ * and to 'treeview' by {@link Ext.tree.Panel Tree}.
+ */
viewType: null,
+
+ /**
+ * @cfg {Object} viewConfig
+ * A config object that will be applied to the grid's UI view. Any of the config options available for
+ * {@link Ext.view.Table} can be specified here. This option is ignored if {@link #view} is specified.
+ */
+
+ /**
+ * @cfg {Ext.view.Table} view
+ * The {@link Ext.view.Table} used by the grid. Use {@link #viewConfig} to just supply some config options to
+ * view (instead of creating an entire View instance).
+ */
+
+ /**
+ * @cfg {String} selType
+ * An xtype of selection model to use. Defaults to 'rowmodel'. This is used to create selection model if just
+ * a config object or nothing at all given in {@link #selModel} config.
+ */
selType: 'rowmodel',
+ /**
+ * @cfg {Ext.selection.Model/Object} selModel
+ * A {@link Ext.selection.Model selection model} instance or config object. In latter case the {@link #selType}
+ * config option determines to which type of selection model this config is applied.
+ */
+
+ /**
+ * @cfg {Boolean} multiSelect
+ * True to enable 'MULTI' selection mode on selection model. See {@link Ext.selection.Model#mode}.
+ */
+
+ /**
+ * @cfg {Boolean} simpleSelect
+ * True to enable 'SIMPLE' selection mode on selection model. See {@link Ext.selection.Model#mode}.
+ */
+
+ /**
+ * @cfg {Ext.data.Store} store (required)
+ * The {@link Ext.data.Store Store} the grid should use as its data source.
+ */
+
/**
* @cfg {Number} scrollDelta
* Number of pixels to scroll when scrolling with mousewheel.
- * Defaults to 40.
*/
scrollDelta: 40,
/**
* @cfg {String/Boolean} scroll
- * Valid values are 'both', 'horizontal' or 'vertical'. true implies 'both'. false implies 'none'.
- * Defaults to true.
+ * Scrollers configuration. Valid values are 'both', 'horizontal' or 'vertical'.
+ * True implies 'both'. False implies 'none'.
*/
scroll: true,
/**
- * @cfg {Array} columns
- * An array of {@link Ext.grid.column.Column column} definition objects which define all columns that appear in this grid. Each
- * column definition provides the header text for the column, and a definition of where the data for that column comes from.
+ * @cfg {Ext.grid.column.Column[]} columns
+ * An array of {@link Ext.grid.column.Column column} definition objects which define all columns that appear in this
+ * grid. Each column definition provides the header text for the column, and a definition of where the data for that
+ * column comes from.
*/
/**
* @cfg {Boolean} forceFit
- * 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
- * a specific width, or flex. Then they are all proportionally changed in width so that the entire content width is used..
+ * Ttrue to force the columns to fit into the available width. Headers are first sized according to configuration,
+ * whether that be a specific width, or flex. Then they are all proportionally changed in width so that the entire
+ * content width is used.
*/
/**
- * @cfg {Boolean} hideHeaders
- * Specify as <code>true</code> to hide the headers.
+ * @cfg {Ext.grid.feature.Feature[]} features
+ * An array of grid Features to be added to this grid. See {@link Ext.grid.feature.Feature} for usage.
*/
/**
- * @cfg {Boolean} deferRowRender <P>Defaults to <code>true</code> to enable deferred row rendering.</p>
- * <p>This allows the GridView to execute a refresh quickly, with the expensive update of the row
- * structure deferred so that layouts with GridPanels appear, and lay out more quickly.</p>
+ * @cfg {Boolean} [hideHeaders=false]
+ * True to hide column headers.
*/
+ /**
+ * @cfg {Boolean} deferRowRender
+ * Defaults to true to enable deferred row rendering.
+ *
+ * This allows the View to execute a refresh quickly, with the expensive update of the row structure deferred so
+ * that layouts with GridPanels appear, and lay out more quickly.
+ */
+
+ deferRowRender: true,
+
/**
* @cfg {Boolean} sortableColumns
- * Defaults to <code>true</code>. Set to <code>false</code> to disable column sorting via clicking the
- * header and via the Sorting menu items.
+ * False to disable column sorting via clicking the header and via the Sorting menu items.
*/
sortableColumns: true,
+ /**
+ * @cfg {Boolean} [enableLocking=false]
+ * True to enable locking support for this grid. Alternatively, locking will also be automatically
+ * enabled if any of the columns in the column configuration contain the locked config option.
+ */
+ enableLocking: false,
+
verticalScrollDock: 'right',
verticalScrollerType: 'gridscroller',
/**
* @cfg {Boolean} enableColumnMove
- * Defaults to <code>true</code>. Set to <code>false</code> to disable column dragging within this grid.
+ * False to disable column dragging within this grid.
*/
enableColumnMove: true,
/**
* @cfg {Boolean} enableColumnResize
- * Defaults to <code>true</code>. Set to <code>false</code> to disable column resizing within this grid.
+ * False to disable column resizing within this grid.
*/
enableColumnResize: true,
/**
* @cfg {Boolean} enableColumnHide
- * Defaults to <code>true</code>. Set to <code>false</code> to disable column hiding within this grid.
+ * False to disable column hiding within this grid.
*/
enableColumnHide: true,
if (!this.viewType) {
Ext.Error.raise("You must specify a viewType config.");
}
- if (!this.store) {
- Ext.Error.raise("You must specify a store config");
- }
if (this.headers) {
Ext.Error.raise("The headers config is not supported. Please specify columns instead.");
}
view,
border = me.border;
- // We cannot buffer this because that will wait for the 30msec from afterLayout (or what
- // ever event triggers it) and we may be in the middle of an animation; that is a bad
- // time to injectView because it causes a layout (by calling add on the container). A
- // throttled func will be called immediately on first call and then block subsequent
- // (rapid fire) calls for 30msec before allowing another call to go through. Similar
- // results, but the action moves from the trailing edge of the interval to the leading
- // edge.
- me.injectView = Ext.Function.createThrottled(me.injectView, 30, me);
-
if (me.hideHeaders) {
border = false;
}
+ // Look up the configured Store. If none configured, use the fieldless, empty Store defined in Ext.data.Store.
+ me.store = Ext.data.StoreManager.lookup(me.store || 'ext-empty-store');
+
// The columns/colModel config may be either a fully instantiated HeaderContainer, or an array of Column definitions, or a config object of a HeaderContainer
// Either way, we extract a columns property referencing an array of Column definitions.
if (headerCtCfg instanceof Ext.grid.header.Container) {
// If any of the Column objects contain a locked property, and are not processed, this is a lockable TablePanel, a
// special view will be injected by the Ext.grid.Lockable mixin, so no processing of .
- if (Ext.ComponentQuery.query('{locked !== undefined}{processed != true}', me.columns).length) {
+ if (me.enableLocking || Ext.ComponentQuery.query('{locked !== undefined}{processed != true}', me.columns).length) {
me.self.mixin('lockable', Ext.grid.Lockable);
me.injectLockable();
}
}
- me.store = Ext.data.StoreManager.lookup(me.store);
me.addEvents(
/**
* @event reconfigure
- * Fires after a reconfigure
+ * Fires after a reconfigure.
* @param {Ext.panel.Table} this
*/
'reconfigure',
+ /**
+ * @event viewready
+ * Fires when the grid view is available (use this for selecting a default row).
+ * @param {Ext.panel.Table} this
+ */
+ 'viewready',
/**
* @event scrollerhide
- * Fires when a scroller is hidden
+ * Fires when a scroller is hidden.
* @param {Ext.grid.Scroller} scroller
* @param {String} orientation Orientation, can be 'vertical' or 'horizontal'
*/
'scrollerhide',
/**
* @event scrollershow
- * Fires when a scroller is shown
+ * Fires when a scroller is shown.
* @param {Ext.grid.Scroller} scroller
* @param {String} orientation Orientation, can be 'vertical' or 'horizontal'
*/
me.bodyCls = me.bodyCls || '';
me.bodyCls += (' ' + me.extraBodyCls);
+
+ me.cls = me.cls || '';
+ me.cls += (' ' + me.extraBaseCls);
// autoScroll is not a valid configuration
delete me.autoScroll;
});
}
- me.headerCt.on('columnresize', me.onHeaderResize, me);
- me.relayEvents(me.headerCt, ['columnresize', 'columnmove', 'columnhide', 'columnshow', 'sortchange']);
+ me.headerCt.on('resize', me.onHeaderResize, me);
+ me.relayHeaderCtEvents(me.headerCt);
me.features = me.features || [];
+ if (!Ext.isArray(me.features)) {
+ me.features = [me.features];
+ }
me.dockedItems = me.dockedItems || [];
me.dockedItems.unshift(me.headerCt);
me.viewConfig = me.viewConfig || {};
// getView converts viewConfig into a View instance
view = me.getView();
- if (view) {
- me.mon(view.store, {
- load: me.onStoreLoad,
- scope: me
- });
- me.mon(view, {
- refresh: me.onViewRefresh,
- scope: me
- });
- this.relayEvents(view, [
- /**
- * @event beforeitemmousedown
- * Fires before the mousedown event on an item is processed. Returns false to cancel the default action.
- * @param {Ext.view.View} this
- * @param {Ext.data.Model} record The record that belongs to the item
- * @param {HTMLElement} item The item's element
- * @param {Number} index The item's index
- * @param {Ext.EventObject} e The raw event object
- */
- 'beforeitemmousedown',
- /**
- * @event beforeitemmouseup
- * Fires before the mouseup event on an item is processed. Returns false to cancel the default action.
- * @param {Ext.view.View} this
- * @param {Ext.data.Model} record The record that belongs to the item
- * @param {HTMLElement} item The item's element
- * @param {Number} index The item's index
- * @param {Ext.EventObject} e The raw event object
- */
- 'beforeitemmouseup',
- /**
- * @event beforeitemmouseenter
- * Fires before the mouseenter event on an item is processed. Returns false to cancel the default action.
- * @param {Ext.view.View} this
- * @param {Ext.data.Model} record The record that belongs to the item
- * @param {HTMLElement} item The item's element
- * @param {Number} index The item's index
- * @param {Ext.EventObject} e The raw event object
- */
- 'beforeitemmouseenter',
- /**
- * @event beforeitemmouseleave
- * Fires before the mouseleave event on an item is processed. Returns false to cancel the default action.
- * @param {Ext.view.View} this
- * @param {Ext.data.Model} record The record that belongs to the item
- * @param {HTMLElement} item The item's element
- * @param {Number} index The item's index
- * @param {Ext.EventObject} e The raw event object
- */
- 'beforeitemmouseleave',
- /**
- * @event beforeitemclick
- * Fires before the click event on an item is processed. Returns false to cancel the default action.
- * @param {Ext.view.View} this
- * @param {Ext.data.Model} record The record that belongs to the item
- * @param {HTMLElement} item The item's element
- * @param {Number} index The item's index
- * @param {Ext.EventObject} e The raw event object
- */
- 'beforeitemclick',
- /**
- * @event beforeitemdblclick
- * Fires before the dblclick event on an item is processed. Returns false to cancel the default action.
- * @param {Ext.view.View} this
- * @param {Ext.data.Model} record The record that belongs to the item
- * @param {HTMLElement} item The item's element
- * @param {Number} index The item's index
- * @param {Ext.EventObject} e The raw event object
- */
- 'beforeitemdblclick',
- /**
- * @event beforeitemcontextmenu
- * Fires before the contextmenu event on an item is processed. Returns false to cancel the default action.
- * @param {Ext.view.View} this
- * @param {Ext.data.Model} record The record that belongs to the item
- * @param {HTMLElement} item The item's element
- * @param {Number} index The item's index
- * @param {Ext.EventObject} e The raw event object
- */
- 'beforeitemcontextmenu',
- /**
- * @event itemmousedown
- * Fires when there is a mouse down on an item
- * @param {Ext.view.View} this
- * @param {Ext.data.Model} record The record that belongs to the item
- * @param {HTMLElement} item The item's element
- * @param {Number} index The item's index
- * @param {Ext.EventObject} e The raw event object
- */
- 'itemmousedown',
- /**
- * @event itemmouseup
- * Fires when there is a mouse up on an item
- * @param {Ext.view.View} this
- * @param {Ext.data.Model} record The record that belongs to the item
- * @param {HTMLElement} item The item's element
- * @param {Number} index The item's index
- * @param {Ext.EventObject} e The raw event object
- */
- 'itemmouseup',
- /**
- * @event itemmouseenter
- * Fires when the mouse enters an item.
- * @param {Ext.view.View} this
- * @param {Ext.data.Model} record The record that belongs to the item
- * @param {HTMLElement} item The item's element
- * @param {Number} index The item's index
- * @param {Ext.EventObject} e The raw event object
- */
- 'itemmouseenter',
- /**
- * @event itemmouseleave
- * Fires when the mouse leaves an item.
- * @param {Ext.view.View} this
- * @param {Ext.data.Model} record The record that belongs to the item
- * @param {HTMLElement} item The item's element
- * @param {Number} index The item's index
- * @param {Ext.EventObject} e The raw event object
- */
- 'itemmouseleave',
- /**
- * @event itemclick
- * Fires when an item is clicked.
- * @param {Ext.view.View} this
- * @param {Ext.data.Model} record The record that belongs to the item
- * @param {HTMLElement} item The item's element
- * @param {Number} index The item's index
- * @param {Ext.EventObject} e The raw event object
- */
- 'itemclick',
- /**
- * @event itemdblclick
- * Fires when an item is double clicked.
- * @param {Ext.view.View} this
- * @param {Ext.data.Model} record The record that belongs to the item
- * @param {HTMLElement} item The item's element
- * @param {Number} index The item's index
- * @param {Ext.EventObject} e The raw event object
- */
- 'itemdblclick',
- /**
- * @event itemcontextmenu
- * Fires when an item is right clicked.
- * @param {Ext.view.View} this
- * @param {Ext.data.Model} record The record that belongs to the item
- * @param {HTMLElement} item The item's element
- * @param {Number} index The item's index
- * @param {Ext.EventObject} e The raw event object
- */
- 'itemcontextmenu',
- /**
- * @event beforecontainermousedown
- * Fires before the mousedown event on the container is processed. Returns false to cancel the default action.
- * @param {Ext.view.View} this
- * @param {Ext.EventObject} e The raw event object
- */
- 'beforecontainermousedown',
- /**
- * @event beforecontainermouseup
- * Fires before the mouseup event on the container is processed. Returns false to cancel the default action.
- * @param {Ext.view.View} this
- * @param {Ext.EventObject} e The raw event object
- */
- 'beforecontainermouseup',
- /**
- * @event beforecontainermouseover
- * Fires before the mouseover event on the container is processed. Returns false to cancel the default action.
- * @param {Ext.view.View} this
- * @param {Ext.EventObject} e The raw event object
- */
- 'beforecontainermouseover',
- /**
- * @event beforecontainermouseout
- * Fires before the mouseout event on the container is processed. Returns false to cancel the default action.
- * @param {Ext.view.View} this
- * @param {Ext.EventObject} e The raw event object
- */
- 'beforecontainermouseout',
- /**
- * @event beforecontainerclick
- * Fires before the click event on the container is processed. Returns false to cancel the default action.
- * @param {Ext.view.View} this
- * @param {Ext.EventObject} e The raw event object
- */
- 'beforecontainerclick',
- /**
- * @event beforecontainerdblclick
- * Fires before the dblclick event on the container is processed. Returns false to cancel the default action.
- * @param {Ext.view.View} this
- * @param {Ext.EventObject} e The raw event object
- */
- 'beforecontainerdblclick',
- /**
- * @event beforecontainercontextmenu
- * Fires before the contextmenu event on the container is processed. Returns false to cancel the default action.
- * @param {Ext.view.View} this
- * @param {Ext.EventObject} e The raw event object
- */
- 'beforecontainercontextmenu',
- /**
- * @event containermouseup
- * Fires when there is a mouse up on the container
- * @param {Ext.view.View} this
- * @param {Ext.EventObject} e The raw event object
- */
- 'containermouseup',
- /**
- * @event containermouseover
- * Fires when you move the mouse over the container.
- * @param {Ext.view.View} this
- * @param {Ext.EventObject} e The raw event object
- */
- 'containermouseover',
- /**
- * @event containermouseout
- * Fires when you move the mouse out of the container.
- * @param {Ext.view.View} this
- * @param {Ext.EventObject} e The raw event object
- */
- 'containermouseout',
- /**
- * @event containerclick
- * Fires when the container is clicked.
- * @param {Ext.view.View} this
- * @param {Ext.EventObject} e The raw event object
- */
- 'containerclick',
- /**
- * @event containerdblclick
- * Fires when the container is double clicked.
- * @param {Ext.view.View} this
- * @param {Ext.EventObject} e The raw event object
- */
- 'containerdblclick',
- /**
- * @event containercontextmenu
- * Fires when the container is right clicked.
- * @param {Ext.view.View} this
- * @param {Ext.EventObject} e The raw event object
- */
- 'containercontextmenu',
-
- /**
- * @event selectionchange
- * Fires when the selected nodes change. Relayed event from the underlying selection model.
- * @param {Ext.view.View} this
- * @param {Array} selections Array of the selected nodes
- */
- 'selectionchange',
- /**
- * @event beforeselect
- * Fires before a selection is made. If any handlers return false, the selection is cancelled.
- * @param {Ext.view.View} this
- * @param {HTMLElement} node The node to be selected
- * @param {Array} selections Array of currently selected nodes
- */
- 'beforeselect'
- ]);
- }
+ view.on({
+ afterrender: function () {
+ // hijack the view el's scroll method
+ view.el.scroll = Ext.Function.bind(me.elScroll, me);
+ // We use to listen to document.body wheel events, but that's a
+ // little much. We scope just to the view now.
+ me.mon(view.el, {
+ mousewheel: me.onMouseWheel,
+ scope: me
+ });
+ },
+ single: true
+ });
+ me.items = [view];
+ me.hasView = true;
+
+ me.mon(view.store, {
+ load: me.onStoreLoad,
+ scope: me
+ });
+ me.mon(view, {
+ viewReady: me.onViewReady,
+ resize: me.onViewResize,
+ refresh: {
+ fn: me.onViewRefresh,
+ scope: me,
+ buffer: 50
+ },
+ scope: me
+ });
+ this.relayEvents(view, [
+ /**
+ * @event beforeitemmousedown
+ * @alias Ext.view.View#beforeitemmousedown
+ */
+ 'beforeitemmousedown',
+ /**
+ * @event beforeitemmouseup
+ * @alias Ext.view.View#beforeitemmouseup
+ */
+ 'beforeitemmouseup',
+ /**
+ * @event beforeitemmouseenter
+ * @alias Ext.view.View#beforeitemmouseenter
+ */
+ 'beforeitemmouseenter',
+ /**
+ * @event beforeitemmouseleave
+ * @alias Ext.view.View#beforeitemmouseleave
+ */
+ 'beforeitemmouseleave',
+ /**
+ * @event beforeitemclick
+ * @alias Ext.view.View#beforeitemclick
+ */
+ 'beforeitemclick',
+ /**
+ * @event beforeitemdblclick
+ * @alias Ext.view.View#beforeitemdblclick
+ */
+ 'beforeitemdblclick',
+ /**
+ * @event beforeitemcontextmenu
+ * @alias Ext.view.View#beforeitemcontextmenu
+ */
+ 'beforeitemcontextmenu',
+ /**
+ * @event itemmousedown
+ * @alias Ext.view.View#itemmousedown
+ */
+ 'itemmousedown',
+ /**
+ * @event itemmouseup
+ * @alias Ext.view.View#itemmouseup
+ */
+ 'itemmouseup',
+ /**
+ * @event itemmouseenter
+ * @alias Ext.view.View#itemmouseenter
+ */
+ 'itemmouseenter',
+ /**
+ * @event itemmouseleave
+ * @alias Ext.view.View#itemmouseleave
+ */
+ 'itemmouseleave',
+ /**
+ * @event itemclick
+ * @alias Ext.view.View#itemclick
+ */
+ 'itemclick',
+ /**
+ * @event itemdblclick
+ * @alias Ext.view.View#itemdblclick
+ */
+ 'itemdblclick',
+ /**
+ * @event itemcontextmenu
+ * @alias Ext.view.View#itemcontextmenu
+ */
+ 'itemcontextmenu',
+ /**
+ * @event beforecontainermousedown
+ * @alias Ext.view.View#beforecontainermousedown
+ */
+ 'beforecontainermousedown',
+ /**
+ * @event beforecontainermouseup
+ * @alias Ext.view.View#beforecontainermouseup
+ */
+ 'beforecontainermouseup',
+ /**
+ * @event beforecontainermouseover
+ * @alias Ext.view.View#beforecontainermouseover
+ */
+ 'beforecontainermouseover',
+ /**
+ * @event beforecontainermouseout
+ * @alias Ext.view.View#beforecontainermouseout
+ */
+ 'beforecontainermouseout',
+ /**
+ * @event beforecontainerclick
+ * @alias Ext.view.View#beforecontainerclick
+ */
+ 'beforecontainerclick',
+ /**
+ * @event beforecontainerdblclick
+ * @alias Ext.view.View#beforecontainerdblclick
+ */
+ 'beforecontainerdblclick',
+ /**
+ * @event beforecontainercontextmenu
+ * @alias Ext.view.View#beforecontainercontextmenu
+ */
+ 'beforecontainercontextmenu',
+ /**
+ * @event containermouseup
+ * @alias Ext.view.View#containermouseup
+ */
+ 'containermouseup',
+ /**
+ * @event containermouseover
+ * @alias Ext.view.View#containermouseover
+ */
+ 'containermouseover',
+ /**
+ * @event containermouseout
+ * @alias Ext.view.View#containermouseout
+ */
+ 'containermouseout',
+ /**
+ * @event containerclick
+ * @alias Ext.view.View#containerclick
+ */
+ 'containerclick',
+ /**
+ * @event containerdblclick
+ * @alias Ext.view.View#containerdblclick
+ */
+ 'containerdblclick',
+ /**
+ * @event containercontextmenu
+ * @alias Ext.view.View#containercontextmenu
+ */
+ 'containercontextmenu',
+ /**
+ * @event selectionchange
+ * @alias Ext.selection.Model#selectionchange
+ */
+ 'selectionchange',
+ /**
+ * @event beforeselect
+ * @alias Ext.selection.RowModel#beforeselect
+ */
+ 'beforeselect',
+ /**
+ * @event select
+ * @alias Ext.selection.RowModel#select
+ */
+ 'select',
+ /**
+ * @event beforedeselect
+ * @alias Ext.selection.RowModel#beforedeselect
+ */
+ 'beforedeselect',
+ /**
+ * @event deselect
+ * @alias Ext.selection.RowModel#deselect
+ */
+ 'deselect'
+ ]);
}
+
me.callParent(arguments);
},
+
+ onRender: function(){
+ var vScroll = this.verticalScroller,
+ hScroll = this.horizontalScroller;
+
+ if (vScroll) {
+ vScroll.ensureDimension();
+ }
+ if (hScroll) {
+ hScroll.ensureDimension();
+ }
+ this.callParent(arguments);
+ },
// state management
initStateEvents: function(){
return ret;
},
+ relayHeaderCtEvents: function (headerCt) {
+ this.relayEvents(headerCt, [
+ /**
+ * @event columnresize
+ * @alias Ext.grid.header.Container#columnresize
+ */
+ 'columnresize',
+ /**
+ * @event columnmove
+ * @alias Ext.grid.header.Container#columnmove
+ */
+ 'columnmove',
+ /**
+ * @event columnhide
+ * @alias Ext.grid.header.Container#columnhide
+ */
+ 'columnhide',
+ /**
+ * @event columnshow
+ * @alias Ext.grid.header.Container#columnshow
+ */
+ 'columnshow',
+ /**
+ * @event sortchange
+ * @alias Ext.grid.header.Container#sortchange
+ */
+ 'sortchange'
+ ]);
+ },
+
getState: function(){
- var state = this.callParent(),
- sorter = this.store.sorters.first(),
- headers = this.headerCt.items.items,
- header,
- len = headers.length,
- i = 0;
-
- state.columns = [];
- for (; i < len; i++) {
- header = headers[i];
- state.columns[i] = {
- id: header.headerId
- };
+ var me = this,
+ state = me.callParent(),
+ sorter = me.store.sorters.first();
- // We only store state which has changed from the initial state.
- // So that current software settings do not override future software settings.
- // Only user-changed state should be saved.
- if (header.hidden !== (header.initialConfig.hidden||header.self.prototype.hidden)) {
- state.columns[i].hidden = header.hidden;
- }
- if (header.sortable !== header.initialConfig.sortable) {
- state.columns[i].sortable = header.sortable;
- }
- if (header.flex) {
- if (header.flex !== header.initialConfig.flex) {
- state.columns[i].flex = header.flex;
- }
- } else {
- if (header.width !== header.initialConfig.width) {
- state.columns[i].width = header.width;
- }
- }
- }
+ state.columns = (me.headerCt || me).getColumnsState();
if (sorter) {
state.sort = {
direction: sorter.direction
};
}
+
return state;
},
applyState: function(state) {
- var headers = state.columns,
- length = headers ? headers.length : 0,
- headerCt = this.headerCt,
- items = headerCt.items,
+ var me = this,
sorter = state.sort,
- store = this.store,
- i = 0,
- index,
- headerState,
- header;
+ store = me.store,
+ columns = state.columns;
- headerCt.suspendLayout = true;
+ delete state.columns;
// Ensure superclass has applied *its* state.
// AbstractComponent saves dimensions (and anchor/flex) plus collapsed state.
- this.callParent(arguments);
-
- for (; i < length; ++i) {
- headerState = headers[i];
- header = headerCt.down('gridcolumn[headerId=' + headerState.id + ']');
- index = items.indexOf(header);
- if (i !== index) {
- headerCt.moveHeader(index, i);
- }
+ me.callParent(arguments);
- // Only state properties which were saved should be restored.
- // (Only user-changed properties were saved by getState)
- if (Ext.isDefined(headerState.hidden)) {
- header.hidden = headerState.hidden;
- }
- if (Ext.isDefined(headerState.sortable)) {
- header.sortable = headerState.sortable;
- }
- if (Ext.isDefined(headerState.flex)) {
- delete header.width;
- header.flex = headerState.flex;
- } else if (Ext.isDefined(headerState.width)) {
- delete header.flex;
- header.minWidth = headerState.width;
- if (header.rendered) {
- header.setWidth(headerState.width);
- } else {
- header.width = headerState.width;
- }
- }
+ if (columns) {
+ (me.headerCt || me).applyColumnsState(columns);
}
- headerCt.suspendLayout = false;
-
- // After setting width and flexes while layout is suspended, column Container's Container layout needs running.
- headerCt.doLayout();
if (sorter) {
if (store.remoteSort) {
if (!me.view) {
sm = me.getSelectionModel();
me.view = me.createComponent(Ext.apply({}, me.viewConfig, {
- deferRowRender: me.deferRowRender,
+ deferInitialRefresh: me.deferRowRender,
xtype: me.viewType,
store: me.store,
headerCt: me.headerCt,
if (direction === "up" || direction === "left") {
distance = -distance;
}
-
+
if (direction === "down" || direction === "up") {
scroller = me.getVerticalScroller();
- scroller.scrollByDeltaY(distance);
+
+ //if the grid does not currently need a vertical scroller don't try to update it (EXTJSIV-3891)
+ if (scroller) {
+ scroller.scrollByDeltaY(distance);
+ }
} else {
scroller = me.getHorizontalScroller();
- scroller.scrollByDeltaX(distance);
- }
- },
-
- /**
- * @private
- * Called after this Component has achieved its correct initial size, after all layouts have done their thing.
- * This is so we can add the View only after the initial size is known. This method is throttled 30ms.
- */
- injectView: function() {
- if (!this.hasView && !this.collapsed) {
- var me = this,
- view = me.getView();
-
- me.hasView = true;
- me.add(view);
-
- function viewReady () {
- // hijack the view el's scroll method
- view.el.scroll = Ext.Function.bind(me.elScroll, me);
- // We use to listen to document.body wheel events, but that's a
- // little much. We scope just to the view now.
- me.mon(view.el, {
- mousewheel: me.onMouseWheel,
- scope: me
- });
- if (!me.height) {
- me.doComponentLayout();
- }
+
+ //if the grid does not currently need a horizontal scroller don't try to update it (EXTJSIV-3891)
+ if (scroller) {
+ scroller.scrollByDeltaX(distance);
}
-
- if (view.rendered) {
- viewReady();
- } else {
- view.on({
- afterrender: viewReady,
- single: true
- });
- }
- }
- },
-
- afterExpand: function() {
- // TODO - this is *not* called when part of an accordion!
- this.callParent(arguments);
- if (!this.hasView) {
- this.injectView();
}
},
/**
* @private
- * Process UI events from the view. Propagate them to whatever internal Components need to process them
+ * Processes UI events from the view. Propagates them to whatever internal Components need to process them.
* @param {String} type Event type, eg 'click'
- * @param {TableView} view TableView Component
- * @param {HtmlElement} cell Cell HtmlElement the event took place within
+ * @param {Ext.view.Table} view TableView Component
+ * @param {HTMLElement} cell Cell HtmlElement the event took place within
* @param {Number} recordIndex Index of the associated Store Model (-1 if none)
* @param {Number} cellIndex Cell index within the row
- * @param {EventObject} e Original event
+ * @param {Ext.EventObject} e Original event
*/
processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
var me = this,
},
/**
- * Request a recalculation of scrollbars and put them in if they are needed.
+ * Requests a recalculation of scrollbars and puts them in if they are needed.
*/
determineScrollbars: function() {
+ // Set a flag so that afterComponentLayout does not recurse back into here.
+ if (this.determineScrollbarsRunning) {
+ return;
+ }
+ this.determineScrollbarsRunning = true;
var me = this,
+ view = me.view,
box,
tableEl,
scrollWidth,
reqScrollbars = 0; // 1 = vertical, 2 = horizontal, 3 = both
// If we are not collapsed, and the view has been rendered AND filled, then we can determine scrollbars
- if (!me.collapsed && me.view && me.view.el && me.view.el.dom.firstChild) {
+ if (!me.collapsed && view && view.viewReady) {
// Calculate maximum, *scrollbarless* space which the view has available.
// It will be the Fit Layout's calculated size, plus the widths of any currently shown scrollbars
- box = me.layout.getLayoutTargetSize();
+ box = view.el.getSize();
+
clientWidth = box.width + ((curScrollbars & 1) ? verticalScroller.width : 0);
clientHeight = box.height + ((curScrollbars & 2) ? horizontalScroller.height : 0);
if (verticalScroller && verticalScroller.el) {
scrollHeight = verticalScroller.getSizeCalculation().height;
} else {
- tableEl = me.view.el.child('table', true);
+ tableEl = view.el.child('table', true);
scrollHeight = tableEl ? tableEl.offsetHeight : 0;
}
}
me.suspendLayout = false;
- // After docked scrollers are correctly configured, lay out the Component.
- // Set a flag so that afterComponentLayout does not recurse back into here.
- me.changingScrollBars = true;
- me.doComponentLayout(me.getWidth(), me.getHeight(), false, me.ownerCt);
- me.changingScrollBars = false;
+ // Lay out the Component.
+ me.doComponentLayout();
+ // Lay out me.items
+ me.getLayout().layout();
}
}
+ delete me.determineScrollbarsRunning;
},
- afterComponentLayout: function() {
- var me = this;
- me.callParent(arguments);
-
- // Insert the View the first time the Panel has a Component layout performed.
- me.injectView();
+ onViewResize: function() {
+ this.determineScrollbars();
+ },
- // Avoid recursion
- if (!me.changingScrollBars) {
- me.determineScrollbars();
- }
- me.invalidateScroller();
+ afterComponentLayout: function() {
+ this.callParent(arguments);
+ this.determineScrollbars();
+ this.invalidateScroller();
},
onHeaderResize: function() {
- if (this.view && this.view.rendered) {
+ if (!this.componentLayout.layoutBusy && this.view && this.view.rendered) {
this.determineScrollbars();
this.invalidateScroller();
}
},
/**
- * Hide the verticalScroller and remove the horizontalScrollerPresentCls.
+ * Hides the verticalScroller and removes the horizontalScrollerPresentCls.
*/
hideHorizontalScroller: function() {
var me = this;
},
/**
- * Show the horizontalScroller and add the horizontalScrollerPresentCls.
+ * Shows the horizontalScroller and add the horizontalScrollerPresentCls.
*/
showHorizontalScroller: function() {
var me = this;
},
/**
- * Hide the verticalScroller and remove the verticalScrollerPresentCls.
+ * Hides the verticalScroller and removes the verticalScrollerPresentCls.
*/
hideVerticalScroller: function() {
var me = this;
},
/**
- * Show the verticalScroller and add the verticalScrollerPresentCls.
+ * Shows the verticalScroller and adds the verticalScrollerPresentCls.
*/
showVerticalScroller: function() {
var me = this;
// only trigger a layout when reserveOffset is changing
if (layout && layout.reserveOffset !== reserveOffset) {
layout.reserveOffset = reserveOffset;
- headerCt.doLayout();
+ if (!this.suspendLayout) {
+ headerCt.doLayout();
+ }
}
},
/**
- * Invalides scrollers that are present and forces a recalculation.
- * (Not related to showing/hiding the scrollers)
+ * Invalides scrollers that are present and forces a recalculation. (Not related to showing/hiding the scrollers)
*/
invalidateScroller: function() {
var me = this,
var me = this,
vertScroller = me.getVerticalScroller(),
horizScroller = me.getHorizontalScroller(),
- scrollDelta = me.scrollDelta / -5,
+ scrollDelta = -me.scrollDelta,
deltas = e.getWheelDeltas(),
deltaX = scrollDelta * deltas.x,
deltaY = scrollDelta * deltas.y,
/**
* @private
- * Determine and invalidate scrollers on view refresh
+ * Fires the TablePanel's viewready event when the view declares that its internal DOM is ready
+ */
+ onViewReady: function() {
+ var me = this;
+ me.fireEvent('viewready', me);
+ if (me.deferRowRender) {
+ me.determineScrollbars();
+ me.invalidateScroller();
+ }
+ },
+
+ /**
+ * @private
+ * Determines and invalidates scrollers on view refresh
*/
onViewRefresh: function() {
- this.determineScrollbars();
- if (this.invalidateScrollerOnRefresh) {
- this.invalidateScroller();
+ var me = this;
+
+ // Refresh *during* render must be ignored.
+ if (!me.rendering) {
+ this.determineScrollbars();
+ if (this.invalidateScrollerOnRefresh) {
+ this.invalidateScroller();
+ }
}
},
/**
* Sets the scrollTop of the TablePanel.
- * @param {Number} deltaY
+ * @param {Number} top
*/
setScrollTop: function(top) {
var me = this,
/**
* Scrolls the TablePanel by deltaX
- * @param {Number} deltaY
+ * @param {Number} deltaX
*/
scrollByDeltaX: function(deltaX) {
- var horizontalScroller = this.getVerticalScroller();
+ var horizontalScroller = this.getHorizontalScroller();
if (horizontalScroller) {
horizontalScroller.scrollByDeltaX(deltaX);
},
/**
- * Get left hand side marker for header resizing.
+ * Gets left hand side marker for header resizing.
* @private
*/
getLhsMarker: function() {
var me = this;
if (!me.lhsMarker) {
- me.lhsMarker = Ext.core.DomHelper.append(me.el, {
+ me.lhsMarker = Ext.DomHelper.append(me.el, {
cls: Ext.baseCSSPrefix + 'grid-resize-marker'
}, true);
}
},
/**
- * Get right hand side marker for header resizing.
+ * Gets right hand side marker for header resizing.
* @private
*/
getRhsMarker: function() {
var me = this;
if (!me.rhsMarker) {
- me.rhsMarker = Ext.core.DomHelper.append(me.el, {
+ me.rhsMarker = Ext.DomHelper.append(me.el, {
cls: Ext.baseCSSPrefix + 'grid-resize-marker'
}, true);
}
},
/**
- * Returns the selection model being used and creates it via the configuration
- * if it has not been created already.
+ * Returns the selection model being used and creates it via the configuration if it has not been created already.
* @return {Ext.selection.Model} selModel
*/
getSelectionModel: function(){
me.store = store;
me.getView().bindStore(store);
},
+
+ beforeDestroy: function(){
+ // may be some duplication here since the horizontal and vertical
+ // scroller may be part of the docked items, but we need to clean
+ // them up in case they aren't visible.
+ Ext.destroy(this.horizontalScroller, this.verticalScroller);
+ this.callParent();
+ },
/**
- * Reconfigure the table with a new store/column.
- * Either the store or the column can be ommitted if you don't wish to change them.
- * @param {Ext.data.Store} store The new store.
- * @param {Array} columns An array of column configs
+ * Reconfigures the table with a new store/columns. Either the store or the columns can be ommitted if you don't wish
+ * to change them.
+ * @param {Ext.data.Store} store (Optional) The new store.
+ * @param {Object[]} columns (Optional) An array of column configs
*/
reconfigure: function(store, columns) {
var me = this,
if (me.lockable) {
me.reconfigureLockable(store, columns);
} else {
- headerCt.suspendLayout = true;
- headerCt.removeAll();
if (columns) {
+ headerCt.suspendLayout = true;
+ headerCt.removeAll();
headerCt.add(columns);
- } else {
- headerCt.doLayout();
}
if (store) {
store = Ext.StoreManager.lookup(store);
me.getView().refresh();
}
if (columns) {
+ headerCt.suspendLayout = false;
me.forceComponentLayout();
}
}