org.dojo.dojox.grid._grid.scroller.js Maven / Gradle / Ivy
The newest version!
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 page
constructor: function(){
this.pageHeights = [];
this.stack = [];
},
// specified
rowCount: 0, // total number of rows to manage
defaultRowHeight: 10, // default height of a row
keepRows: 100, // maximum number of rows that should exist at one time
contentNode: null, // node to contain pages
scrollboxNode: null, // node that controls scrolling
// calculated
defaultPageHeight: 0, // default height of a page
keepPages: 10, // maximum number of pages that should exists at one time
pageCount: 0,
windowHeight: 0,
firstVisibleRow: 0,
lastVisibleRow: 0,
// private
page: 0,
pageTop: 0,
// init
init: 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');
}
},
// updating
invalidate: 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 height
oldPageCount = 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 interface
pageExists: 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){
},
// pacification
pacifying: 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 implementation
resize: 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 core
invalidateNodes: 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 list
pushPage: 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= 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 below
this.installPage(inPageIndex);
this.renderPage(inPageIndex);
// order of operations is key above
this.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= 0 ? inTop + this.windowHeight : -1);
},
// events
processNodeEvent: 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 scrolled
constructor: function(){
this.pageNodes = [];
},
// virtual rendering interface
renderRow: function(inRowIndex, inPageNode){
},
removeRow: function(inRowIndex){
},
// page node operations
getDefaultNodes: 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=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= 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