- Author:
- David Nickerson <nickerso@users.sourceforge.net>
- Date:
- 2009-07-16 02:00:03+12:00
- Desc:
- the starting point for the HH tutorial example
- Permanent Source URI:
- https://models.fieldml.org/workspace/a1/rawfile/f6a8f90307388eb4b040ee3566b84d88b59247f7/dojo-presentation/js/dojo/dijit/_base/scroll.js
dojo.provide("dijit._base.scroll");
dijit.scrollIntoView = function(/* DomNode */node){
// summary
// Scroll the passed node into view, if it is not.
// don't rely on that node.scrollIntoView works just because the function is there
// it doesnt work in Konqueror or Opera even though the function is there and probably
// not safari either
// native scrollIntoView() causes FF3's whole window to scroll if there is no scroll bar
// on the immediate parent
// dont like browser sniffs implementations but sometimes you have to use it
// It's not enough just to scroll the menu node into view if
// node.scrollIntoView hides part of the parent's scrollbar,
// so just manage the parent scrollbar ourselves
node = dojo.byId(node);
var body = node.ownerDocument.body;
var html = body.parentNode;
if(dojo.isFF == 2 || node == body || node == html){ // FF2 is perfect, too bad FF3 is not
node.scrollIntoView(false); // short-circuit to native if possible
return;
}
var rtl = !dojo._isBodyLtr();
var strict = dojo.doc.compatMode != 'BackCompat'; // not the same as !dojo.isQuirks
var scrollRoot = (strict && !dojo.isSafari)? html : body;
function addPseudoAttrs(element){
var parent = element.parentNode;
var offsetParent = element.offsetParent;
if(offsetParent == null){ // process only 1 of BODY/HTML
element = scrollRoot;
offsetParent = html;
parent = null;
}
// all the V/H object members below are to reuse code for both directions
element._offsetParent = (offsetParent == body)? scrollRoot : offsetParent;
element._parent = (parent == body)? scrollRoot : parent;
element._start = { H:element.offsetLeft, V:element.offsetTop };
element._scroll = { H:element.scrollLeft, V:element.scrollTop };
element._renderedSize = { H: element.offsetWidth, V: element.offsetHeight };
var bp = dojo._getBorderExtents(element);
element._borderStart = { H:bp.l, V:bp.t };
element._borderSize = { H:bp.w, V:bp.h };
element._clientSize = (element._offsetParent == html && dojo.isSafari && strict)? { H:html.clientWidth, V:html.clientHeight } : { H:element.clientWidth, V:element.clientHeight };
element._scrollBarSize = { V: null, H: null };
for(var dir in element._scrollBarSize){ // for both x and y directions
var scrollBar = element._renderedSize[dir] - element._clientSize[dir] - element._borderSize[dir];
element._scrollBarSize[dir] = (element._clientSize[dir] > 0 && scrollBar >= 15 && scrollBar <= 17)? scrollBar : 0; // sanity check
}
element._isScrollable = { V: null, H: null };
for(dir in element._isScrollable){ // for both x and y directions
var otherDir = dir=="H"? "V" : "H";
element._isScrollable[dir] = element == scrollRoot || element._scroll[dir] || element._scrollBarSize[otherDir];
}
}
var parent = node;
while(parent != null){
addPseudoAttrs(parent);
var next = parent._parent;
if(next){
next._child = parent;
}
parent = next;
}
for(var dir in scrollRoot._renderedSize){ scrollRoot._renderedSize[dir] = Math.min(scrollRoot._clientSize[dir], scrollRoot._renderedSize[dir]); }
var element = node;
while(element != scrollRoot){
parent = element._parent;
if(parent.tagName == "TD"){
var table = parent._parent._parent._parent; // point to TABLE
if(table._offsetParent == element._offsetParent && parent._offsetParent != element._offsetParent){
parent = table; // child of TD has the same offsetParent as TABLE, so skip TD, TR, and TBODY (ie. verticalslider)
}
}
// check if this node and its parent share the same offsetParent
var startIsRelative = element == scrollRoot || (parent._offsetParent != element._offsetParent);
for(dir in element._start){ // for both x and y directions
var otherDir = dir=="H"? "V" : "H";
if(rtl && dir=="H" && (dojo.isSafari || dojo.isIE) && parent._clientSize.H > 0){ // scroll starts on the right
var delta = parent.scrollWidth - parent._clientSize.H;
if(delta > 0){ parent._scroll.H -= delta; } // match FF3 which has cool negative scrollLeft values
}
if(dojo.isIE && parent._offsetParent.tagName == "TABLE"){ // make it consistent with Safari and FF3 and exclude the starting TABLE border of TABLE children
parent._start[dir] -= parent._offsetParent._borderStart[dir];
parent._borderStart[dir] = parent._borderSize[dir] = 0;
}
if(parent._clientSize[dir] == 0){ // TABLE on Safari3/FF3, and TBODY on IE6/7
parent._renderedSize[dir] = parent._clientSize[dir] = parent._child._clientSize[dir];
if(rtl && dir=="H"){ parent._start[dir] -= parent._renderedSize[dir]; }
}else{
parent._renderedSize[dir] -= parent._borderSize[dir] + parent._scrollBarSize[dir];
}
parent._start[dir] += parent._borderStart[dir];
// underflow = visible gap between parent and this node taking scrolling into account
// if negative, part of the node is obscured by the parent's beginning and should be scrolled to become visible
var underflow = element._start[dir] - (startIsRelative? 0 : parent._start[dir]) - parent._scroll[dir];
// if positive, number of pixels obscured by the parent's end
var overflow = underflow + element._renderedSize[dir] - parent._renderedSize[dir];
var scrollAmount, scrollAttr = (dir=="H")? "scrollLeft" : "scrollTop";
// see if we should scroll forward or backward
var reverse = (dir=="H" && rtl); // flip everything
var underflowScroll = reverse? -overflow : underflow;
var overflowScroll = reverse? -underflow : overflow;
if(underflowScroll <= 0){
scrollAmount = underflowScroll;
}else if(overflowScroll <= 0){
scrollAmount = 0;
}else if(underflowScroll < overflowScroll){
scrollAmount = underflowScroll;
}else{
scrollAmount = overflowScroll;
}
var scrolledAmount = 0;
if(scrollAmount != 0){
var oldScroll = parent[scrollAttr];
parent[scrollAttr] += reverse? -scrollAmount : scrollAmount; // actually perform the scroll
scrolledAmount = parent[scrollAttr] - oldScroll; // in case the scroll failed
underflow -= scrolledAmount;
overflowScroll -= reverse? -scrolledAmount : scrolledAmount;
}
parent._renderedSize[dir] = element._renderedSize[dir] + parent._scrollBarSize[dir] -
// check for isScrollable since a nonscrolling parent could be smaller than the child but the child is fully visible
((parent._isScrollable[dir] && overflowScroll > 0)? overflowScroll : 0); // only show portion of the parent
parent._start[dir] += (underflow >= 0 || !parent._isScrollable[dir])? underflow : 0;
}
element = parent; // now see if the parent needs to be scrolled as well
}
};