Blame | Last modification | View Log | RSS feed
if(!dojo._hasResource['dojox.grid._grid.scroller']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.dojo._hasResource['dojox.grid._grid.scroller'] = true;dojo.provide('dojox.grid._grid.scroller');dojo.declare('dojox.grid.scroller.base', null, {// summary:// virtual scrollbox, abstract class// Content must in /rows/// Rows are managed in contiguous sets called /pages/// There are a fixed # of rows per page// The minimum rendered unit is a pageconstructor: function(){this.pageHeights = [];this.stack = [];},// specifiedrowCount: 0, // total number of rows to managedefaultRowHeight: 10, // default height of a rowkeepRows: 100, // maximum number of rows that should exist at one timecontentNode: null, // node to contain pagesscrollboxNode: null, // node that controls scrolling// calculateddefaultPageHeight: 0, // default height of a pagekeepPages: 10, // maximum number of pages that should exists at one timepageCount: 0,windowHeight: 0,firstVisibleRow: 0,lastVisibleRow: 0,// privatepage: 0,pageTop: 0,// initinit: function(inRowCount, inKeepRows, inRowsPerPage){switch(arguments.length){case 3: this.rowsPerPage = inRowsPerPage;case 2: this.keepRows = inKeepRows;case 1: this.rowCount = inRowCount;}this.defaultPageHeight = this.defaultRowHeight * this.rowsPerPage;//this.defaultPageHeight = this.defaultRowHeight * Math.min(this.rowsPerPage, this.rowCount);this.pageCount = Math.ceil(this.rowCount / this.rowsPerPage);this.keepPages = Math.max(Math.ceil(this.keepRows / this.rowsPerPage), 2);this.invalidate();if(this.scrollboxNode){this.scrollboxNode.scrollTop = 0;this.scroll(0);this.scrollboxNode.onscroll = dojo.hitch(this, 'onscroll');}},// updatinginvalidate: function(){this.invalidateNodes();this.pageHeights = [];this.height = (this.pageCount ? (this.pageCount - 1)* this.defaultPageHeight + this.calcLastPageHeight() : 0);this.resize();},updateRowCount: function(inRowCount){this.invalidateNodes();this.rowCount = inRowCount;// update page count, adjust document heightoldPageCount = this.pageCount;this.pageCount = Math.ceil(this.rowCount / this.rowsPerPage);if(this.pageCount < oldPageCount){for(var i=oldPageCount-1; i>=this.pageCount; i--){this.height -= this.getPageHeight(i);delete this.pageHeights[i]}}else if(this.pageCount > oldPageCount){this.height += this.defaultPageHeight * (this.pageCount - oldPageCount - 1) + this.calcLastPageHeight();}this.resize();},// abstract interfacepageExists: function(inPageIndex){},measurePage: function(inPageIndex){},positionPage: function(inPageIndex, inPos){},repositionPages: function(inPageIndex){},installPage: function(inPageIndex){},preparePage: function(inPageIndex, inPos, inReuseNode){},renderPage: function(inPageIndex){},removePage: function(inPageIndex){},pacify: function(inShouldPacify){},// pacificationpacifying: false,pacifyTicks: 200,setPacifying: function(inPacifying){if(this.pacifying != inPacifying){this.pacifying = inPacifying;this.pacify(this.pacifying);}},startPacify: function(){this.startPacifyTicks = new Date().getTime();},doPacify: function(){var result = (new Date().getTime() - this.startPacifyTicks) > this.pacifyTicks;this.setPacifying(true);this.startPacify();return result;},endPacify: function(){this.setPacifying(false);},// default sizing implementationresize: function(){if(this.scrollboxNode){this.windowHeight = this.scrollboxNode.clientHeight;}dojox.grid.setStyleHeightPx(this.contentNode, this.height);},calcLastPageHeight: function(){if(!this.pageCount){return 0;}var lastPage = this.pageCount - 1;var lastPageHeight = ((this.rowCount % this.rowsPerPage)||(this.rowsPerPage)) * this.defaultRowHeight;this.pageHeights[lastPage] = lastPageHeight;return lastPageHeight;},updateContentHeight: function(inDh){this.height += inDh;this.resize();},updatePageHeight: function(inPageIndex){if(this.pageExists(inPageIndex)){var oh = this.getPageHeight(inPageIndex);var h = (this.measurePage(inPageIndex))||(oh);this.pageHeights[inPageIndex] = h;if((h)&&(oh != h)){this.updateContentHeight(h - oh)this.repositionPages(inPageIndex);}}},rowHeightChanged: function(inRowIndex){this.updatePageHeight(Math.floor(inRowIndex / this.rowsPerPage));},// scroller coreinvalidateNodes: function(){while(this.stack.length){this.destroyPage(this.popPage());}},createPageNode: function(){var p = document.createElement('div');p.style.position = 'absolute';//p.style.width = '100%';p.style.left = '0';return p;},getPageHeight: function(inPageIndex){var ph = this.pageHeights[inPageIndex];return (ph !== undefined ? ph : this.defaultPageHeight);},// FIXME: this is not a stack, it's a FIFO listpushPage: function(inPageIndex){return this.stack.push(inPageIndex);},popPage: function(){return this.stack.shift();},findPage: function(inTop){var i = 0, h = 0;for(var ph = 0; i<this.pageCount; i++, h += ph){ph = this.getPageHeight(i);if(h + ph >= inTop){break;}}this.page = i;this.pageTop = h;},buildPage: function(inPageIndex, inReuseNode, inPos){this.preparePage(inPageIndex, inReuseNode);this.positionPage(inPageIndex, inPos);// order of operations is key belowthis.installPage(inPageIndex);this.renderPage(inPageIndex);// order of operations is key abovethis.pushPage(inPageIndex);},needPage: function(inPageIndex, inPos){var h = this.getPageHeight(inPageIndex), oh = h;if(!this.pageExists(inPageIndex)){this.buildPage(inPageIndex, (this.keepPages)&&(this.stack.length >= this.keepPages), inPos);h = this.measurePage(inPageIndex) || h;this.pageHeights[inPageIndex] = h;if(h && (oh != h)){this.updateContentHeight(h - oh)}}else{this.positionPage(inPageIndex, inPos);}return h;},onscroll: function(){this.scroll(this.scrollboxNode.scrollTop);},scroll: function(inTop){this.startPacify();this.findPage(inTop);var h = this.height;var b = this.getScrollBottom(inTop);for(var p=this.page, y=this.pageTop; (p<this.pageCount)&&((b<0)||(y<b)); p++){y += this.needPage(p, y);}this.firstVisibleRow = this.getFirstVisibleRow(this.page, this.pageTop, inTop);this.lastVisibleRow = this.getLastVisibleRow(p - 1, y, b);// indicates some page size has been updatedif(h != this.height){this.repositionPages(p-1);}this.endPacify();},getScrollBottom: function(inTop){return (this.windowHeight >= 0 ? inTop + this.windowHeight : -1);},// eventsprocessNodeEvent: function(e, inNode){var t = e.target;while(t && (t != inNode) && t.parentNode && (t.parentNode.parentNode != inNode)){t = t.parentNode;}if(!t || !t.parentNode || (t.parentNode.parentNode != inNode)){return false;}var page = t.parentNode;e.topRowIndex = page.pageIndex * this.rowsPerPage;e.rowIndex = e.topRowIndex + dojox.grid.indexInParent(t);e.rowTarget = t;return true;},processEvent: function(e){return this.processNodeEvent(e, this.contentNode);},dummy: 0});dojo.declare('dojox.grid.scroller', dojox.grid.scroller.base, {// summary:// virtual scroller class, makes no assumption about shape of items being scrolledconstructor: function(){this.pageNodes = [];},// virtual rendering interfacerenderRow: function(inRowIndex, inPageNode){},removeRow: function(inRowIndex){},// page node operationsgetDefaultNodes: function(){return this.pageNodes;},getDefaultPageNode: function(inPageIndex){return this.getDefaultNodes()[inPageIndex];},positionPageNode: function(inNode, inPos){inNode.style.top = inPos + 'px';},getPageNodePosition: function(inNode){return inNode.offsetTop;},repositionPageNodes: function(inPageIndex, inNodes){var last = 0;for(var i=0; i<this.stack.length; i++){last = Math.max(this.stack[i], last);}//var n = inNodes[inPageIndex];var y = (n ? this.getPageNodePosition(n) + this.getPageHeight(inPageIndex) : 0);//console.log('detected height change, repositioning from #%d (%d) @ %d ', inPageIndex + 1, last, y, this.pageHeights[0]);//for(var p=inPageIndex+1; p<=last; p++){n = inNodes[p];if(n){//console.log('#%d @ %d', inPageIndex, y, this.getPageNodePosition(n));if(this.getPageNodePosition(n) == y){return;}//console.log('placing page %d at %d', p, y);this.positionPage(p, y);}y += this.getPageHeight(p);}},invalidatePageNode: function(inPageIndex, inNodes){var p = inNodes[inPageIndex];if(p){delete inNodes[inPageIndex];this.removePage(inPageIndex, p);dojox.grid.cleanNode(p);p.innerHTML = '';}return p;},preparePageNode: function(inPageIndex, inReusePageIndex, inNodes){var p = (inReusePageIndex === null ? this.createPageNode() : this.invalidatePageNode(inReusePageIndex, inNodes));p.pageIndex = inPageIndex;p.id = 'page-' + inPageIndex;inNodes[inPageIndex] = p;},// implementation for page managerpageExists: function(inPageIndex){return Boolean(this.getDefaultPageNode(inPageIndex));},measurePage: function(inPageIndex){return this.getDefaultPageNode(inPageIndex).offsetHeight;},positionPage: function(inPageIndex, inPos){this.positionPageNode(this.getDefaultPageNode(inPageIndex), inPos);},repositionPages: function(inPageIndex){this.repositionPageNodes(inPageIndex, this.getDefaultNodes());},preparePage: function(inPageIndex, inReuseNode){this.preparePageNode(inPageIndex, (inReuseNode ? this.popPage() : null), this.getDefaultNodes());},installPage: function(inPageIndex){this.contentNode.appendChild(this.getDefaultPageNode(inPageIndex));},destroyPage: function(inPageIndex){var p = this.invalidatePageNode(inPageIndex, this.getDefaultNodes());dojox.grid.removeNode(p);},// rendering implementationrenderPage: function(inPageIndex){var node = this.pageNodes[inPageIndex];for(var i=0, j=inPageIndex*this.rowsPerPage; (i<this.rowsPerPage)&&(j<this.rowCount); i++, j++){this.renderRow(j, node);}},removePage: function(inPageIndex){for(var i=0, j=inPageIndex*this.rowsPerPage; i<this.rowsPerPage; i++, j++){this.removeRow(j);}},// scroll controlgetPageRow: function(inPage){return inPage * this.rowsPerPage;},getLastPageRow: function(inPage){return Math.min(this.rowCount, this.getPageRow(inPage + 1)) - 1;},getFirstVisibleRowNodes: function(inPage, inPageTop, inScrollTop, inNodes){var row = this.getPageRow(inPage);var rows = dojox.grid.divkids(inNodes[inPage]);for(var i=0,l=rows.length; i<l && inPageTop<inScrollTop; i++, row++){inPageTop += rows[i].offsetHeight;}return (row ? row - 1 : row);},getFirstVisibleRow: function(inPage, inPageTop, inScrollTop){if(!this.pageExists(inPage)){return 0;}return this.getFirstVisibleRowNodes(inPage, inPageTop, inScrollTop, this.getDefaultNodes());},getLastVisibleRowNodes: function(inPage, inBottom, inScrollBottom, inNodes){var row = this.getLastPageRow(inPage);var rows = dojox.grid.divkids(inNodes[inPage]);for(var i=rows.length-1; i>=0 && inBottom>inScrollBottom; i--, row--){inBottom -= rows[i].offsetHeight;}return row + 1;},getLastVisibleRow: function(inPage, inBottom, inScrollBottom){if(!this.pageExists(inPage)){return 0;}return this.getLastVisibleRowNodes(inPage, inBottom, inScrollBottom, this.getDefaultNodes());},findTopRowForNodes: function(inScrollTop, inNodes){var rows = dojox.grid.divkids(inNodes[this.page]);for(var i=0,l=rows.length,t=this.pageTop,h; i<l; i++){h = rows[i].offsetHeight;t += h;if(t >= inScrollTop){this.offset = h - (t - inScrollTop);return i + this.page * this.rowsPerPage;}}return -1;},findScrollTopForNodes: function(inRow, inNodes){var rowPage = Math.floor(inRow / this.rowsPerPage);var t = 0;for(var i=0; i<rowPage; i++){t += this.getPageHeight(i);}this.pageTop = t;this.needPage(rowPage, this.pageTop);var rows = dojox.grid.divkids(inNodes[rowPage]);var r = inRow - this.rowsPerPage * rowPage;for(var i=0,l=rows.length; i<l && i<r; i++){t += rows[i].offsetHeight;}return t;},findTopRow: function(inScrollTop){return this.findTopRowForNodes(inScrollTop, this.getDefaultNodes());},findScrollTop: function(inRow){return this.findScrollTopForNodes(inRow, this.getDefaultNodes());},dummy: 0});dojo.declare('dojox.grid.scroller.columns', dojox.grid.scroller, {// summary:// Virtual scroller class that scrolls list of columns. Owned by grid and used internally// for virtual scrolling.constructor: function(inContentNodes){this.setContentNodes(inContentNodes);},// nodessetContentNodes: function(inNodes){this.contentNodes = inNodes;this.colCount = (this.contentNodes ? this.contentNodes.length : 0);this.pageNodes = [];for(var i=0; i<this.colCount; i++){this.pageNodes[i] = [];}},getDefaultNodes: function(){return this.pageNodes[0] || [];},scroll: function(inTop) {if(this.colCount){dojox.grid.scroller.prototype.scroll.call(this, inTop);}},// resizeresize: function(){if(this.scrollboxNode){this.windowHeight = this.scrollboxNode.clientHeight;}for(var i=0; i<this.colCount; i++){dojox.grid.setStyleHeightPx(this.contentNodes[i], this.height);}},// implementation for page managerpositionPage: function(inPageIndex, inPos){for(var i=0; i<this.colCount; i++){this.positionPageNode(this.pageNodes[i][inPageIndex], inPos);}},preparePage: function(inPageIndex, inReuseNode){var p = (inReuseNode ? this.popPage() : null);for(var i=0; i<this.colCount; i++){this.preparePageNode(inPageIndex, p, this.pageNodes[i]);}},installPage: function(inPageIndex){for(var i=0; i<this.colCount; i++){this.contentNodes[i].appendChild(this.pageNodes[i][inPageIndex]);}},destroyPage: function(inPageIndex){for(var i=0; i<this.colCount; i++){dojox.grid.removeNode(this.invalidatePageNode(inPageIndex, this.pageNodes[i]));}},// rendering implementationrenderPage: function(inPageIndex){var nodes = [];for(var i=0; i<this.colCount; i++){nodes[i] = this.pageNodes[i][inPageIndex];}//this.renderRows(inPageIndex*this.rowsPerPage, this.rowsPerPage, nodes);for(var i=0, j=inPageIndex*this.rowsPerPage; (i<this.rowsPerPage)&&(j<this.rowCount); i++, j++){this.renderRow(j, nodes);}}});}