X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/0494b8d9b9bb03ab6c22b34dae81261e3cd7e3e6..7a654f8d43fdb43d78b63d90528bed6e86b608cc:/src/grid/PagingScroller.js?ds=sidebyside diff --git a/src/grid/PagingScroller.js b/src/grid/PagingScroller.js new file mode 100644 index 00000000..9c322fc2 --- /dev/null +++ b/src/grid/PagingScroller.js @@ -0,0 +1,250 @@ +/** + * @class Ext.grid.PagingScroller + * @extends Ext.grid.Scroller + * + * @private + */ +Ext.define('Ext.grid.PagingScroller', { + extend: 'Ext.grid.Scroller', + alias: 'widget.paginggridscroller', + //renderTpl: null, + //tpl: [ + // '', + // '
', + // '
' + //], + /** + * @cfg {Number} percentageFromEdge This is a number above 0 and less than 1 which specifies + * at what percentage to begin fetching the next page. For example if the pageSize is 100 + * and the percentageFromEdge is the default of 0.35, the paging scroller will prefetch pages + * when scrolling up between records 0 and 34 and when scrolling down between records 65 and 99. + */ + percentageFromEdge: 0.35, + + /** + * @cfg {Number} scrollToLoadBuffer This is the time in milliseconds to buffer load requests + * when scrolling the PagingScrollbar. + */ + scrollToLoadBuffer: 200, + + activePrefetch: true, + + chunkSize: 50, + snapIncrement: 25, + + syncScroll: true, + + initComponent: function() { + var me = this, + ds = me.store; + + ds.on('guaranteedrange', this.onGuaranteedRange, this); + this.callParent(arguments); + }, + + + onGuaranteedRange: function(range, start, end) { + var me = this, + ds = me.store, + rs; + // this should never happen + if (range.length && me.visibleStart < range[0].index) { + return; + } + + ds.loadRecords(range); + + if (!me.firstLoad) { + if (me.rendered) { + me.invalidate(); + } else { + me.on('afterrender', this.invalidate, this, {single: true}); + } + me.firstLoad = true; + } else { + // adjust to visible + me.syncTo(); + } + }, + + syncTo: function() { + var me = this, + pnl = me.getPanel(), + store = pnl.store, + scrollerElDom = this.el.dom, + rowOffset = me.visibleStart - store.guaranteedStart, + scrollBy = rowOffset * me.rowHeight, + scrollHeight = scrollerElDom.scrollHeight, + clientHeight = scrollerElDom.clientHeight, + scrollTop = scrollerElDom.scrollTop, + useMaximum; + + // BrowserBug: clientHeight reports 0 in IE9 StrictMode + // Instead we are using offsetHeight and hardcoding borders + if (Ext.isIE9 && Ext.isStrict) { + clientHeight = scrollerElDom.offsetHeight + 2; + } + + // This should always be zero or greater than zero but staying + // safe and less than 0 we'll scroll to the bottom. + useMaximum = (scrollHeight - clientHeight - scrollTop <= 0); + this.setViewScrollTop(scrollBy, useMaximum); + }, + + getPageData : function(){ + var panel = this.getPanel(), + store = panel.store, + totalCount = store.getTotalCount(); + + return { + total : totalCount, + currentPage : store.currentPage, + pageCount: Math.ceil(totalCount / store.pageSize), + fromRecord: ((store.currentPage - 1) * store.pageSize) + 1, + toRecord: Math.min(store.currentPage * store.pageSize, totalCount) + }; + }, + + onElScroll: function(e, t) { + var me = this, + panel = me.getPanel(), + store = panel.store, + pageSize = store.pageSize, + guaranteedStart = store.guaranteedStart, + guaranteedEnd = store.guaranteedEnd, + totalCount = store.getTotalCount(), + numFromEdge = Math.ceil(me.percentageFromEdge * store.pageSize), + position = t.scrollTop, + visibleStart = Math.floor(position / me.rowHeight), + view = panel.down('tableview'), + viewEl = view.el, + visibleHeight = viewEl.getHeight(), + visibleAhead = Math.ceil(visibleHeight / me.rowHeight), + visibleEnd = visibleStart + visibleAhead, + prevPage = Math.floor(visibleStart / store.pageSize), + nextPage = Math.floor(visibleEnd / store.pageSize) + 2, + lastPage = Math.ceil(totalCount / store.pageSize), + //requestStart = visibleStart, + requestStart = Math.floor(visibleStart / me.snapIncrement) * me.snapIncrement, + requestEnd = requestStart + pageSize - 1, + activePrefetch = me.activePrefetch; + + me.visibleStart = visibleStart; + me.visibleEnd = visibleEnd; + + + me.syncScroll = true; + if (totalCount >= pageSize) { + // end of request was past what the total is, grab from the end back a pageSize + if (requestEnd > totalCount - 1) { + this.cancelLoad(); + if (store.rangeSatisfied(totalCount - pageSize, totalCount - 1)) { + me.syncScroll = true; + } + store.guaranteeRange(totalCount - pageSize, totalCount - 1); + // Out of range, need to reset the current data set + } else if (visibleStart < guaranteedStart || visibleEnd > guaranteedEnd) { + if (store.rangeSatisfied(requestStart, requestEnd)) { + this.cancelLoad(); + store.guaranteeRange(requestStart, requestEnd); + } else { + store.mask(); + me.attemptLoad(requestStart, requestEnd); + } + // dont sync the scroll view immediately, sync after the range has been guaranteed + me.syncScroll = false; + } else if (activePrefetch && visibleStart < (guaranteedStart + numFromEdge) && prevPage > 0) { + me.syncScroll = true; + store.prefetchPage(prevPage); + } else if (activePrefetch && visibleEnd > (guaranteedEnd - numFromEdge) && nextPage < lastPage) { + me.syncScroll = true; + store.prefetchPage(nextPage); + } + } + + + if (me.syncScroll) { + me.syncTo(); + } + }, + + getSizeCalculation: function() { + // Use the direct ownerCt here rather than the scrollerOwner + // because we are calculating widths/heights. + var owner = this.ownerCt, + view = owner.getView(), + store = this.store, + dock = this.dock, + elDom = this.el.dom, + width = 1, + height = 1; + + if (!this.rowHeight) { + this.rowHeight = view.el.down(view.getItemSelector()).getHeight(false, true); + } + + height = store.getTotalCount() * this.rowHeight; + + if (isNaN(width)) { + width = 1; + } + if (isNaN(height)) { + height = 1; + } + return { + width: width, + height: height + }; + }, + + attemptLoad: function(start, end) { + var me = this; + if (!me.loadTask) { + me.loadTask = Ext.create('Ext.util.DelayedTask', me.doAttemptLoad, me, []); + } + me.loadTask.delay(me.scrollToLoadBuffer, me.doAttemptLoad, me, [start, end]); + }, + + cancelLoad: function() { + if (this.loadTask) { + this.loadTask.cancel(); + } + }, + + doAttemptLoad: function(start, end) { + var store = this.getPanel().store; + store.guaranteeRange(start, end); + }, + + setViewScrollTop: function(scrollTop, useMax) { + var owner = this.getPanel(), + items = owner.query('tableview'), + i = 0, + len = items.length, + center, + centerEl, + calcScrollTop, + maxScrollTop, + scrollerElDom = this.el.dom; + + owner.virtualScrollTop = scrollTop; + + center = items[1] || items[0]; + centerEl = center.el.dom; + + maxScrollTop = ((owner.store.pageSize * this.rowHeight) - centerEl.clientHeight); + calcScrollTop = (scrollTop % ((owner.store.pageSize * this.rowHeight) + 1)); + if (useMax) { + calcScrollTop = maxScrollTop; + } + if (calcScrollTop > maxScrollTop) { + //Ext.Error.raise("Calculated scrollTop was larger than maxScrollTop"); + return; + // calcScrollTop = maxScrollTop; + } + for (; i < len; i++) { + items[i].el.dom.scrollTop = calcScrollTop; + } + } +}); +