X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/0494b8d9b9bb03ab6c22b34dae81261e3cd7e3e6..7a654f8d43fdb43d78b63d90528bed6e86b608cc:/src/grid/Scroller.js diff --git a/src/grid/Scroller.js b/src/grid/Scroller.js new file mode 100644 index 00000000..5f03158c --- /dev/null +++ b/src/grid/Scroller.js @@ -0,0 +1,197 @@ +/** + * @class Ext.grid.Scroller + * @extends Ext.Component + * + * Docked in an Ext.grid.Panel, controls virtualized scrolling and synchronization + * across different sections. + * + * @private + */ +Ext.define('Ext.grid.Scroller', { + extend: 'Ext.Component', + alias: 'widget.gridscroller', + weight: 110, + cls: Ext.baseCSSPrefix + 'scroller', + focusable: false, + + renderTpl: ['
'], + + initComponent: function() { + var me = this, + dock = me.dock, + cls = Ext.baseCSSPrefix + 'scroller-vertical', + sizeProp = 'width', + // Subtracting 2px would give us a perfect fit of the scroller + // however, some browsers wont allow us to scroll content thats not + // visible, therefore we use 1px. + // Note: This 1px offset matches code in Ext.grid.ColumnLayout when + // reserving room for the scrollbar + scrollbarWidth = Ext.getScrollBarWidth() + (Ext.isIE ? 1 : -1); + + me.offsets = {bottom: 0}; + + if (dock === 'top' || dock === 'bottom') { + cls = Ext.baseCSSPrefix + 'scroller-horizontal'; + sizeProp = 'height'; + } + me[sizeProp] = scrollbarWidth; + + me.cls += (' ' + cls); + + Ext.applyIf(me.renderSelectors, { + stretchEl: '.' + Ext.baseCSSPrefix + 'stretcher' + }); + me.callParent(); + }, + + + afterRender: function() { + var me = this; + me.callParent(); + me.ownerCt.on('afterlayout', me.onOwnerAfterLayout, me); + me.mon(me.el, 'scroll', me.onElScroll, me); + Ext.cache[me.el.id].skipGarbageCollection = true; + }, + + getSizeCalculation: function() { + var owner = this.getPanel(), + dock = this.dock, + elDom = this.el.dom, + width = 1, + height = 1, + view, tbl; + + if (dock === 'top' || dock === 'bottom') { + // TODO: Must gravitate to a single region.. + // Horizontal scrolling only scrolls virtualized region + var items = owner.query('tableview'), + center = items[1] || items[0]; + + if (!center) { + return false; + } + // center is not guaranteed to have content, such as when there + // are zero rows in the grid/tree. We read the width from the + // headerCt instead. + width = center.headerCt.getFullWidth(); + + if (Ext.isIEQuirks) { + width--; + } + // Account for the 1px removed in Scroller. + width--; + } else { + view = owner.down('tableview:not([lockableInjected])'); + if (!view) { + return false; + } + tbl = view.el; + if (!tbl) { + return false; + } + + // needs to also account for header and scroller (if still in picture) + // should calculate from headerCt. + height = tbl.dom.scrollHeight; + } + if (isNaN(width)) { + width = 1; + } + if (isNaN(height)) { + height = 1; + } + return { + width: width, + height: height + }; + }, + + invalidate: function(firstPass) { + if (!this.stretchEl || !this.ownerCt) { + return; + } + var size = this.getSizeCalculation(), + elDom = this.el.dom; + if (size) { + this.stretchEl.setSize(size); + + // BrowserBug: IE7 + // This makes the scroller enabled, when initially rendering. + elDom.scrollTop = elDom.scrollTop; + } + }, + + onOwnerAfterLayout: function(owner, layout) { + this.invalidate(); + }, + + /** + * Sets the scrollTop and constrains the value between 0 and max. + * @param {Number} scrollTop + * @return {Number} The resulting scrollTop value after being constrained + */ + setScrollTop: function(scrollTop) { + if (this.el) { + var elDom = this.el.dom; + return elDom.scrollTop = Ext.Number.constrain(scrollTop, 0, elDom.scrollHeight - elDom.clientHeight); + } + }, + + /** + * Sets the scrollLeft and constrains the value between 0 and max. + * @param {Number} scrollLeft + * @return {Number} The resulting scrollLeft value after being constrained + */ + setScrollLeft: function(scrollLeft) { + if (this.el) { + var elDom = this.el.dom; + return elDom.scrollLeft = Ext.Number.constrain(scrollLeft, 0, elDom.scrollWidth - elDom.clientWidth); + } + }, + + /** + * Scroll by deltaY + * @param {Number} delta + * @return {Number} The resulting scrollTop value + */ + scrollByDeltaY: function(delta) { + if (this.el) { + var elDom = this.el.dom; + return this.setScrollTop(elDom.scrollTop + delta); + } + }, + + /** + * Scroll by deltaX + * @param {Number} delta + * @return {Number} The resulting scrollLeft value + */ + scrollByDeltaX: function(delta) { + if (this.el) { + var elDom = this.el.dom; + return this.setScrollLeft(elDom.scrollLeft + delta); + } + }, + + + /** + * Scroll to the top. + */ + scrollToTop : function(){ + this.setScrollTop(0); + }, + + // synchronize the scroller with the bound gridviews + onElScroll: function(event, target) { + this.fireEvent('bodyscroll', event, target); + }, + + getPanel: function() { + var me = this; + if (!me.panel) { + me.panel = this.up('[scrollerOwner]'); + } + return me.panel; + } +}); +