X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/3789b528d8dd8aad4558e38e22d775bcab1cbd36..6746dc89c47ed01b165cc1152533605f97eb8e8d:/docs/source/Scroller2.html diff --git a/docs/source/Scroller2.html b/docs/source/Scroller2.html index 4d6da8cc..972abe60 100644 --- a/docs/source/Scroller2.html +++ b/docs/source/Scroller2.html @@ -15,418 +15,280 @@
-/** - * @class Ext.layout.container.boxOverflow.Scroller - * @extends Ext.layout.container.boxOverflow.None +/** + * @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.layout.container.boxOverflow.Scroller', { - - /* Begin Definitions */ +Ext.define('Ext.grid.Scroller', { + extend: 'Ext.Component', + alias: 'widget.gridscroller', + weight: 110, + cls: Ext.baseCSSPrefix + 'scroller', + focusable: false, + reservedSpace: 0, + + renderTpl: [ + '<div class="' + Ext.baseCSSPrefix + 'scroller-ct" id="{baseId}_ct">', + '<div class="' + Ext.baseCSSPrefix + 'stretcher" id="{baseId}_stretch"></div>', + '</div>' + ], + + initComponent: function() { + var me = this, + dock = me.dock, + cls = Ext.baseCSSPrefix + 'scroller-vertical', + sizeProp = 'width'; + + me.offsets = {bottom: 0}; + me.scrollProp = 'scrollTop'; + me.vertical = true; + + if (dock === 'top' || dock === 'bottom') { + cls = Ext.baseCSSPrefix + 'scroller-horizontal'; + sizeProp = 'height'; + me.scrollProp = 'scrollLeft'; + me.vertical = false; + me.weight += 5; + } - extend: 'Ext.layout.container.boxOverflow.None', - requires: ['Ext.util.ClickRepeater', 'Ext.core.Element'], - alternateClassName: 'Ext.layout.boxOverflow.Scroller', - mixins: { - observable: 'Ext.util.Observable' - }, - - /* End Definitions */ + me[sizeProp] = me.scrollerSize = Ext.getScrollbarSize()[sizeProp]; - /** - * @cfg {Boolean} animateScroll - * True to animate the scrolling of items within the layout (defaults to true, ignored if enableScroll is false) - */ - animateScroll: false, + me.cls += (' ' + cls); - /** - * @cfg {Number} scrollIncrement - * The number of pixels to scroll by on scroller click (defaults to 24) - */ - scrollIncrement: 20, + Ext.applyIf(me.renderSelectors, { + stretchEl: '.' + Ext.baseCSSPrefix + 'stretcher', + scrollEl: '.' + Ext.baseCSSPrefix + 'scroller-ct' + }); + me.callParent(); + }, - /** - * @cfg {Number} wheelIncrement - * The number of pixels to increment on mouse wheel scrolling (defaults to <tt>3</tt>). - */ - wheelIncrement: 10, + initRenderData: function () { + var me = this, + ret = me.callParent(arguments) || {}; - /** - * @cfg {Number} scrollRepeatInterval - * Number of milliseconds between each scroll while a scroller button is held down (defaults to 20) - */ - scrollRepeatInterval: 60, + ret.baseId = me.id; - /** - * @cfg {Number} scrollDuration - * Number of milliseconds that each scroll animation lasts (defaults to 400) - */ - scrollDuration: 400, + return ret; + }, - /** - * @cfg {String} beforeCtCls - * CSS class added to the beforeCt element. This is the element that holds any special items such as scrollers, - * which must always be present at the leftmost edge of the Container - */ + afterRender: function() { + var me = this; + me.callParent(); + + me.mon(me.scrollEl, 'scroll', me.onElScroll, me); + Ext.cache[me.el.id].skipGarbageCollection = true; + }, - /** - * @cfg {String} afterCtCls - * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers, - * which must always be present at the rightmost edge of the Container - */ + onAdded: function(container) { + // Capture the controlling grid Panel so that we can use it even when we are undocked, and don't have an ownerCt + this.ownerGrid = container; + this.callParent(arguments); + }, - /** - * @cfg {String} scrollerCls - * CSS class added to both scroller elements if enableScroll is used - */ - scrollerCls: Ext.baseCSSPrefix + 'box-scroller', + getSizeCalculation: function() { + var me = this, + owner = me.getPanel(), + width = 1, + height = 1, + view, tbl; + + if (!me.vertical) { + // 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(); - /** - * @cfg {String} beforeScrollerCls - * CSS class added to the left scroller element if enableScroll is used - */ + if (Ext.isIEQuirks) { + width--; + } + } else { + view = owner.down('tableview:not([lockableInjected])'); + if (!view || !view.el) { + return false; + } + tbl = view.el.child('table', true); + if (!tbl) { + return false; + } - /** - * @cfg {String} afterScrollerCls - * CSS class added to the right scroller element if enableScroll is used - */ - - constructor: function(layout, config) { - this.layout = layout; - Ext.apply(this, config || {}); - - this.addEvents( - /** - * @event scroll - * @param {Ext.layout.container.boxOverflow.Scroller} scroller The layout scroller - * @param {Number} newPosition The new position of the scroller - * @param {Boolean/Object} animate If animating or not. If true, it will be a animation configuration, else it will be false - */ - 'scroll' - ); - }, - - initCSSClasses: function() { - var me = this, - layout = me.layout; - - if (!me.CSSinitialized) { - me.beforeCtCls = me.beforeCtCls || Ext.baseCSSPrefix + 'box-scroller-' + layout.parallelBefore; - me.afterCtCls = me.afterCtCls || Ext.baseCSSPrefix + 'box-scroller-' + layout.parallelAfter; - me.beforeScrollerCls = me.beforeScrollerCls || Ext.baseCSSPrefix + layout.owner.getXType() + '-scroll-' + layout.parallelBefore; - me.afterScrollerCls = me.afterScrollerCls || Ext.baseCSSPrefix + layout.owner.getXType() + '-scroll-' + layout.parallelAfter; - me.CSSinitializes = true; + // needs to also account for header and scroller (if still in picture) + // should calculate from headerCt. + height = tbl.offsetHeight; + } + if (isNaN(width)) { + width = 1; + } + if (isNaN(height)) { + height = 1; } + return { + width: width, + height: height + }; }, - handleOverflow: function(calculations, targetSize) { + invalidate: function(firstPass) { var me = this, - layout = me.layout, - methodName = 'get' + layout.parallelPrefixCap, - newSize = {}; - - me.initCSSClasses(); - me.callParent(arguments); - this.createInnerElements(); - this.showScrollers(); - newSize[layout.perpendicularPrefix] = targetSize[layout.perpendicularPrefix]; - newSize[layout.parallelPrefix] = targetSize[layout.parallelPrefix] - (me.beforeCt[methodName]() + me.afterCt[methodName]()); - return { targetSize: newSize }; - }, + stretchEl = me.stretchEl; - /** - * @private - * Creates the beforeCt and afterCt elements if they have not already been created - */ - createInnerElements: function() { - var me = this, - target = me.layout.getRenderTarget(); - - //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of - //special items such as scrollers or dropdown menu triggers - if (!me.beforeCt) { - target.addCls(Ext.baseCSSPrefix + me.layout.direction + '-box-overflow-body'); - me.beforeCt = target.insertSibling({cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.beforeCtCls}, 'before'); - me.afterCt = target.insertSibling({cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.afterCtCls}, 'after'); - me.createWheelListener(); + if (!stretchEl || !me.ownerCt) { + return; } - }, - /** - * @private - * Sets up an listener to scroll on the layout's innerCt mousewheel event - */ - createWheelListener: function() { - this.layout.innerCt.on({ - scope : this, - mousewheel: function(e) { - e.stopEvent(); + var size = me.getSizeCalculation(), + scrollEl = me.scrollEl, + elDom = scrollEl.dom, + reservedSpace = me.reservedSpace, + pos, + extra = 5; - this.scrollBy(e.getWheelDelta() * this.wheelIncrement * -1, false); - } - }); - }, + if (size) { + stretchEl.setSize(size); - /** - * @private - */ - clearOverflow: function() { - this.hideScrollers(); - }, + size = me.el.getSize(true); - /** - * @private - * Shows the scroller elements in the beforeCt and afterCt. Creates the scrollers first if they are not already - * present. - */ - showScrollers: function() { - this.createScrollers(); - this.beforeScroller.show(); - this.afterScroller.show(); - this.updateScrollButtons(); - - this.layout.owner.addClsWithUI('scroller'); - }, + if (me.vertical) { + size.width += extra; + size.height -= reservedSpace; + pos = 'left'; + } else { + size.width -= reservedSpace; + size.height += extra; + pos = 'top'; + } - /** - * @private - * Hides the scroller elements in the beforeCt and afterCt - */ - hideScrollers: function() { - if (this.beforeScroller != undefined) { - this.beforeScroller.hide(); - this.afterScroller.hide(); - - this.layout.owner.removeClsWithUI('scroller'); - } - }, + scrollEl.setSize(size); + elDom.style[pos] = (-extra) + 'px'; - /** - * @private - * Creates the clickable scroller elements and places them into the beforeCt and afterCt - */ - createScrollers: function() { - if (!this.beforeScroller && !this.afterScroller) { - var before = this.beforeCt.createChild({ - cls: Ext.String.format("{0} {1} ", this.scrollerCls, this.beforeScrollerCls) - }); - - var after = this.afterCt.createChild({ - cls: Ext.String.format("{0} {1}", this.scrollerCls, this.afterScrollerCls) - }); - - before.addClsOnOver(this.beforeScrollerCls + '-hover'); - after.addClsOnOver(this.afterScrollerCls + '-hover'); - - before.setVisibilityMode(Ext.core.Element.DISPLAY); - after.setVisibilityMode(Ext.core.Element.DISPLAY); - - this.beforeRepeater = Ext.create('Ext.util.ClickRepeater', before, { - interval: this.scrollRepeatInterval, - handler : this.scrollLeft, - scope : this - }); - - this.afterRepeater = Ext.create('Ext.util.ClickRepeater', after, { - interval: this.scrollRepeatInterval, - handler : this.scrollRight, - scope : this - }); - - /** - * @property beforeScroller - * @type Ext.core.Element - * The left scroller element. Only created when needed. - */ - this.beforeScroller = before; - - /** - * @property afterScroller - * @type Ext.core.Element - * The left scroller element. Only created when needed. - */ - this.afterScroller = after; + // BrowserBug: IE7 + // This makes the scroller enabled, when initially rendering. + elDom.scrollTop = elDom.scrollTop; } }, - /** - * @private - */ - destroy: function() { - Ext.destroy(this.beforeRepeater, this.afterRepeater, this.beforeScroller, this.afterScroller, this.beforeCt, this.afterCt); + afterComponentLayout: function() { + this.callParent(arguments); + this.invalidate(); }, - /** - * @private - * Scrolls left or right by the number of pixels specified - * @param {Number} delta Number of pixels to scroll to the right by. Use a negative number to scroll left - */ - scrollBy: function(delta, animate) { - this.scrollTo(this.getScrollPosition() + delta, animate); - }, + restoreScrollPos: function () { + var me = this, + el = this.scrollEl, + elDom = el && el.dom; - /** - * @private - * @return {Object} Object passed to scrollTo when scrolling - */ - getScrollAnim: function() { - return { - duration: this.scrollDuration, - callback: this.updateScrollButtons, - scope : this - }; + if (me._scrollPos !== null && elDom) { + elDom[me.scrollProp] = me._scrollPos; + me._scrollPos = null; + } }, - /** - * @private - * Enables or disables each scroller button based on the current scroll position - */ - updateScrollButtons: function() { - if (this.beforeScroller == undefined || this.afterScroller == undefined) { - return; + setReservedSpace: function (reservedSpace) { + var me = this; + if (me.reservedSpace !== reservedSpace) { + me.reservedSpace = reservedSpace; + me.invalidate(); } - - var beforeMeth = this.atExtremeBefore() ? 'addCls' : 'removeCls', - afterMeth = this.atExtremeAfter() ? 'addCls' : 'removeCls', - beforeCls = this.beforeScrollerCls + '-disabled', - afterCls = this.afterScrollerCls + '-disabled'; - - this.beforeScroller[beforeMeth](beforeCls); - this.afterScroller[afterMeth](afterCls); - this.scrolling = false; }, - /** - * @private - * Returns true if the innerCt scroll is already at its left-most point - * @return {Boolean} True if already at furthest left point - */ - atExtremeBefore: function() { - return this.getScrollPosition() === 0; - }, + saveScrollPos: function () { + var me = this, + el = this.scrollEl, + elDom = el && el.dom; - /** - * @private - * Scrolls to the left by the configured amount - */ - scrollLeft: function() { - this.scrollBy(-this.scrollIncrement, false); + me._scrollPos = elDom ? elDom[me.scrollProp] : null; }, - /** - * @private - * Scrolls to the right by the configured amount + /** + * Sets the scrollTop and constrains the value between 0 and max. + * @param {Number} scrollTop + * @return {Number} The resulting scrollTop value after being constrained */ - scrollRight: function() { - this.scrollBy(this.scrollIncrement, false); - }, + setScrollTop: function(scrollTop) { + var el = this.scrollEl, + elDom = el && el.dom; - /** - * Returns the current scroll position of the innerCt element - * @return {Number} The current scroll position - */ - getScrollPosition: function(){ - var layout = this.layout; - return parseInt(layout.innerCt.dom['scroll' + layout.parallelBeforeCap], 10) || 0; + if (elDom) { + return elDom.scrollTop = Ext.Number.constrain(scrollTop, 0, elDom.scrollHeight - elDom.clientHeight); + } }, - /** - * @private - * Returns the maximum value we can scrollTo - * @return {Number} The max scroll value + /** + * Sets the scrollLeft and constrains the value between 0 and max. + * @param {Number} scrollLeft + * @return {Number} The resulting scrollLeft value after being constrained */ - getMaxScrollPosition: function() { - var layout = this.layout; - return layout.innerCt.dom['scroll' + layout.parallelPrefixCap] - this.layout.innerCt['get' + layout.parallelPrefixCap](); - }, + setScrollLeft: function(scrollLeft) { + var el = this.scrollEl, + elDom = el && el.dom; - /** - * @private - * Returns true if the innerCt scroll is already at its right-most point - * @return {Boolean} True if already at furthest right point - */ - atExtremeAfter: function() { - return this.getScrollPosition() >= this.getMaxScrollPosition(); + if (elDom) { + return elDom.scrollLeft = Ext.Number.constrain(scrollLeft, 0, elDom.scrollWidth - elDom.clientWidth); + } }, - /** - * @private - * Scrolls to the given position. Performs bounds checking. - * @param {Number} position The position to scroll to. This is constrained. - * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll + /** + * Scroll by deltaY + * @param {Number} delta + * @return {Number} The resulting scrollTop value */ - scrollTo: function(position, animate) { - var me = this, - layout = me.layout, - oldPosition = me.getScrollPosition(), - newPosition = Ext.Number.constrain(position, 0, me.getMaxScrollPosition()); - - if (newPosition != oldPosition && !me.scrolling) { - if (animate == undefined) { - animate = me.animateScroll; - } + scrollByDeltaY: function(delta) { + var el = this.scrollEl, + elDom = el && el.dom; - layout.innerCt.scrollTo(layout.parallelBefore, newPosition, animate ? me.getScrollAnim() : false); - if (animate) { - me.scrolling = true; - } else { - me.scrolling = false; - me.updateScrollButtons(); - } - - me.fireEvent('scroll', me, newPosition, animate ? me.getScrollAnim() : false); + if (elDom) { + return this.setScrollTop(elDom.scrollTop + delta); } }, - /** - * Scrolls to the given component. - * @param {String|Number|Ext.Component} item The item to scroll to. Can be a numerical index, component id - * or a reference to the component itself. - * @param {Boolean} animate True to animate the scrolling + /** + * Scroll by deltaX + * @param {Number} delta + * @return {Number} The resulting scrollLeft value */ - scrollToItem: function(item, animate) { - var me = this, - layout = me.layout, - visibility, - box, - newPos; - - item = me.getItem(item); - if (item != undefined) { - visibility = this.getItemVisibility(item); - if (!visibility.fullyVisible) { - box = item.getBox(true, true); - newPos = box[layout.parallelPosition]; - if (visibility.hiddenEnd) { - newPos -= (this.layout.innerCt['get' + layout.parallelPrefixCap]() - box[layout.parallelPrefix]); - } - this.scrollTo(newPos, animate); - } + scrollByDeltaX: function(delta) { + var el = this.scrollEl, + elDom = el && el.dom; + + if (elDom) { + return this.setScrollLeft(elDom.scrollLeft + delta); } }, - /** - * @private - * For a given item in the container, return an object with information on whether the item is visible - * with the current innerCt scroll value. - * @param {Ext.Component} item The item - * @return {Object} Values for fullyVisible, hiddenStart and hiddenEnd + + /** + * Scroll to the top. */ - getItemVisibility: function(item) { - var me = this, - box = me.getItem(item).getBox(true, true), - layout = me.layout, - itemStart = box[layout.parallelPosition], - itemEnd = itemStart + box[layout.parallelPrefix], - scrollStart = me.getScrollPosition(), - scrollEnd = scrollStart + layout.innerCt['get' + layout.parallelPrefixCap](); + scrollToTop : function(){ + this.setScrollTop(0); + }, - return { - hiddenStart : itemStart < scrollStart, - hiddenEnd : itemEnd > scrollEnd, - fullyVisible: itemStart > scrollStart && itemEnd < scrollEnd - }; + // 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; } -});+}); + +