[Pkg-javascript-commits] [dojo] 27/32: Fixes #16115. Backport [30493] to 1.6. Tweak test_scroll.html to correctly run deferred doh tests within a getTestCallback method. !strict

David Prévot taffit at moszumanska.debian.org
Thu Aug 21 17:39:09 UTC 2014


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to annotated tag 1.6.2
in repository dojo.

commit 60df0914910ad716f953ec94824352dd500e7741
Author: Douglas Hays <doughays at dojotoolkit.org>
Date:   Wed Jan 30 16:15:29 2013 +0000

    Fixes #16115.  Backport [30493] to 1.6. Tweak test_scroll.html to correctly run deferred doh tests within a getTestCallback method. !strict
    
    git-svn-id: http://svn.dojotoolkit.org/src/branches/1.6/dojo@30499 560b804f-0ae3-0310-86f3-f6aa0a117693
---
 tests/window/test_scroll.html | 985 ++++++++++++++++++++++++------------------
 window.js                     | 109 +++--
 2 files changed, 627 insertions(+), 467 deletions(-)

diff --git a/tests/window/test_scroll.html b/tests/window/test_scroll.html
index c5d8fc6..88a2763 100644
--- a/tests/window/test_scroll.html
+++ b/tests/window/test_scroll.html
@@ -2,7 +2,7 @@
                 "http://www.w3.org/TR/html4/strict.dtd">
 <html style="overflow-y:scroll;border:0px none;padding:0;margin:0;">
 <head>
-        <title>dojo.window.scrollIntoView Test</title>
+	<title>dojo.window.scrollIntoView Test</title>
 
 	<style type="text/css">
 		@import "../../resources/dojo.css";
@@ -10,26 +10,223 @@
 		FIELDSET IFRAME { width:100px; height:100px; }
 	</style>
 	<script type="text/javascript" src="../../dojo.js"
-		djConfig="isDebug: true"></script>
+		data-dojo-config="isDebug: true"></script>
 
 	<script type="text/javascript">
 		dojo.require("doh.runner");
 		dojo.require("dojo.window");
 
-		var usingNative = !(dojo.isMoz || dojo.isIE || dojo.isWebKit || dojo.isOpera);
-		var loading = new doh.Deferred();
-		var count = 0;
+		// Global methods accessed by iframes
+		var count, loading;
+		function initIframeMethods(iframeWin, parentWin){
+			iframeWin.frameElement.findInput = function(){ return parentWin._findInput(iframeWin); };
+			iframeWin.frameElement.scrollMin = function(n){ parentWin._scroll(iframeWin,true,n); };
+			iframeWin.frameElement.scrollMax = function(n){ parentWin._scroll(iframeWin,false,n); };
+			iframeWin.frameElement.getBoundingRect = function(n){ return parentWin._getBoundingRect(iframeWin, n); };
+			iframeWin.frameElement.getVisibleSize = function(n){ return parentWin._getVisibleSize(iframeWin, n); };
+			iframeWin.frameElement.scrollIntoView = function(x,y,w,h){ parentWin._scrollIntoView(iframeWin,x,y,w,h); };
+			iframeWin.frameElement.onClick = function(e){ parentWin._onClick(iframeWin);return false; };
+		}
+
+		function _findInput(win){
+			return win.document.getElementById('it');
+		}
+
+		function _getBoundingRect(win, n){
+			var r = n.getBoundingClientRect();
+			return { left: r.left, right: r.right, top: r.top, bottom: r.bottom, w: Math.round(r.right - r.left), h: Math.round(r.bottom - r.top) };
+		}
+
+		function _scroll(win,isMin,n){
+			while(n && n.tagName){
+				n.scrollTop = isMin ? -9999 : 9999;
+				n.scrollLeft = isMin ? -9999 : 9999;
+				if(n.tagName == "BODY" && (n.scrollLeft || n.scrollTop)){
+					break; // skip HTML
+				}
+				n = n.parentNode;
+			}
+		}
+
+		var loaded = {};
+		function iframeLoaded(id){
+			if(!loaded[id]){	// ignore duplicate notifications
+				loaded[id] = true;
+				if(--count == 0){ loading.callback(true); }
+			}
+		}
+
 		dojo.addOnLoad(function(){
-			innerScrollBarSize = dojo.byId("nonscroll").clientWidth - dojo.byId("withscroll").clientWidth;
+			// More global methods accessed by iframes
+			_scrollIntoView = function(win,x,y,w,h){
+				var n = _findInput(win);
+				var pos;
+				if(typeof x == "number" && typeof y == "number"){
+					var p = dojo.withGlobal(win, 'position', dojo, [ n ]);
+					pos = { x: p.x + x, y: p.y + y, w: isNaN(w) ? 1 : w, h: isNaN(h) ? 1 : h };
+				}
+				dojo.withGlobal(win, 'scrollIntoView', dojo.window, [ n, pos ]);
+			};
+			_onClick = function(win){
+				_scrollIntoView(win);
+			};
+
+			_getVisibleSize = function(win,n){
+				var	html = win.document.documentElement,
+					body = win.document.body,
+					rect = n.getBoundingClientRect(),
+					width = Math.min(body.clientWidth || html.clientWidth, html.clientWidth || body.clientWidth),
+					height = Math.min(body.clientHeight || html.clientHeight, html.clientHeight || body.clientHeight),
+					pos = dojo.withGlobal(win, 'position', dojo, [ n ]);
+				// adjust width and height for IE nonsense
+				width += Math.round(rect.left - pos.x);
+				height += Math.round(rect.top - pos.y);
+				if(dojo.isIE){ width += outerScrollBarSize; } // IE10 bug
+				for(y = 0; y < height; y++){
+					for(x = 0; x < width; x++){
+						var pointElement = win.document.elementFromPoint(x,y);
+						if(pointElement == n){
+							// work around browser bugs
+							// Opera 12.12 says the element is showing beyond the browser edge
+							// IE 10 says`
+							for(var w = 1; (x+w) < width && win.document.elementFromPoint(x+w,y) == n; w++);
+							for(var h = 1; (y+h) < height && win.document.elementFromPoint(x,y+h) == n; h++);
+							return { w: w, h: h };
+						}
+					}
+				}
+				return { w: 0, h: 0 };
+			};
+			
+
+			// Below is the magic code that creates the iframes from the given template.
+			// This should be generalized for other files to include.
+
+			function getIframeSrc(id, content, doctype, rtl){
+				content = content.replace(/"/g/*balance"*/,"'").replace(/iframe.javascript/g,"text/javascript").replace(/<input\b/ig,"<INPUT disabled ");
+				var iframeSrc = 'javascript:"';
+				// find browser specific CSS attributes
+				if(dojo.isIE){
+					content = content.replace(/IE([A-Z]_)/g, "$1");
+				}else if(dojo.isWebKit){
+					content = content.replace(/WK([A-Z]_)/g, "$1");
+				}else if(dojo.isMozilla){
+					content = content.replace(/MZ([A-Z]_)/g, "$1");
+				}else if(dojo.isOpera){
+					content = content.replace(/OP([A-Z]_)/g, "$1");
+				}
+				// find DOCTYPE specific CSS attributes
+				if(doctype=="strict"){
+					iframeSrc += "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01//EN' 'http://www.w3.org/TR/html4/strict.dtd'>\n";
+					content = content.replace(/[A-Z0-9_]*(\b|_)[SZ]_[A-Z0-9_]*/g, "");
+				}else if(doctype=="loose"){
+					iframeSrc += "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0 Transitional//EN' 'http://www.w3.org/TR/html4/loose.dtd'>\n";
+					content = content.replace(/[A-Z0-9_]*(\b|_)[TZ]_[A-Z0-9_]*/g, "");
+				}else{
+					if(dojo.isWebKit){
+						iframeSrc += "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>\n"; // quirks: needed for WebKit's javascript: protocol
+					}
+					content = content.replace(/[A-Z0-9_]*(\b|_)[QZ]_[A-Z0-9_]*/g, "");
+				}
+				if(rtl){
+					content = content.replace(/[A-Z0-9_]*(\b|_)R_[A-Z0-9_]*/g, "");
+				}else{
+					content = content.replace(/[A-Z0-9_]*(\b|_)L_[A-Z0-9_]*/g, "");
+				}
+				content = content.replace(/\s*<(\/?)iframestyle>\s*/ig,"<$1"+"STYLE>");
+				var i = content.indexOf('<STYLE>');
+				var style = '';
+				if(i >= 0){
+					var j = content.indexOf('</STYLE>');
+					if(j >= 0){
+						style = content.substring(i+7, j);
+						content = content.substr(j+8);
+					}
+				}
+				iframeSrc +=
+				'<HTML dir='+(rtl?'rtl':'ltr')+'>'+
+				'<HEAD>'+
+					'<STYLE>'+
+						'* { border:0px solid white;padding:0px;margin:0px;font-style:normal;font-family:monospace;font-size:0px;line-height:normal; }\n'+
+						'INPUT { display:block;background-color:red;font-size:0px;line-height:0px;overflow:hidden;width:20px;height:20px; }\n'+
+						'UL { list-style-type: none;line-height:0px;width:45px;overflow:auto; }\n'+
+						'LI { list-style-type: none;line-height:20px;overflow:visible;max-width:20px;max-height:20px;height:20px;width:20px;float:left; }\n'+
+						'HR { width:120px;height:1px;visibility:hidden;display:block; }\n'+
+						style+
+					'<\/STYLE>'+
+				'<\/HEAD>'+
+				'<BODY BGCOLOR=#ffffff>'+
+					content+
+					'<SCRIPT type=text/javascript>'+
+						'win=frameElement.ownerDocument.defaultView||frameElement.document.parentWindow;'+
+						'win.initIframeMethods(window, win);'+
+						'win.iframeLoaded(\'' + id + "-" + doctype + "-" + (rtl ?'rtl':'ltr') + '\');'+
+						'document.body.onclick=frameElement.onClick;'+
+					'<\/SCRIPT>'+
+				'<\/BODY>'+
+				'<\/HTML>"';
+				return iframeSrc;
+			}
+
+			function makeIframe(id, className, style, content, doctype, rtl, srcNode){
+				var iframeSrc = getIframeSrc(id, content, doctype, rtl);
+				var container = document.createElement('fieldset');
+				var text = (doctype=="strict"? 'strict': (doctype=="loose"? 'loose' : 'quirks')) + (rtl? ' RTL' : '');
+				var color = (rtl? 'medium': '') + (doctype=="strict"? 'SpringGreen': (doctype=="loose"? 'Turquoise' : 'Aquamarine'));
+				var idSuffix = (doctype=="strict"? '_strict': (doctype=="loose"? '_loose': '_quirks')) + (rtl? '_rtl' : '');
+				dojo.style(container, "cssText", "display:inline;border:1px ridge gray;padding:0px;margin:0px;background-color:"+color+";text-align:"+(rtl?"right;":"left;"));
+				container.appendChild(document.createTextNode(text));
+				var iframe = document.createElement('iframe');
+				iframe.setAttribute('src', iframeSrc);
+				iframe.setAttribute('frameBorder', "0");
+				iframe.setAttribute('scrolling', "auto");
+				iframe.setAttribute('allowTransparency', "true");
+				iframe.setAttribute('id', id + idSuffix);
+				iframe.setAttribute('name', id + idSuffix);
+				iframe.className = className;
+				dojo.style(iframe, "cssText", "visibility:hidden;display:block;border:2px solid "+color+";background-color:transparent;margin:0px;padding:3px;"+style);
+				container.appendChild(iframe);
+				srcNode.appendChild(container);
+				var src = iframe.getAttribute("src");
+				if(!src || src.indexOf("javascript") == -1){
+					// set it again if it didn't stick the first time: esp. older Opera and WebKit
+					setTimeout(function(){ iframe.setAttribute('src', iframeSrc); }, 0);
+				}
+			}
+
+			var innerScrollBarSize = Math.ceil(dojo.byId("nonscroll").clientWidth - dojo.byId("withscroll").clientWidth);
 			console.debug('inner scrollbar size = ' + innerScrollBarSize);
-			outerScrollBarSize = (dojo.isIE >= 9) ? ((dojo.position(document.documentElement).w - document.documentElement.clientWidth) || innerScrollBarSize) : innerScrollBarSize;
+			var outerScrollBarSize = Math.ceil((dojo.isIE >= 9) ? ((dojo.position(document.documentElement).w - document.documentElement.clientWidth) || innerScrollBarSize) : innerScrollBarSize);
 			console.debug('outer scrollbar size = ' + outerScrollBarSize);
-		        doh.register("dojo.window.scroll",
-	                [
+
+			doh.register("dojo.window.scroll",[
 				{
-					name: "wait for iframes to load",
+					name: "create iframes and wait for them to load",
 					timeout: 20000,
 					runTest: function(){
+						loading = new doh.Deferred();
+						var testIframes = dojo.query('DIV[type="testIframe"]');
+						count = testIframes.length * 4;
+						console.log("count is " + count);
+						// have to do all the iframes at once so the iPad doesn't resize and cause problems
+						for(var i=0; i < testIframes.length; i++){
+							var srcNode = testIframes[i];
+							var content = srcNode.innerHTML || '';
+							var id = srcNode.id || "";
+							var style = srcNode.getAttribute('style') || "";
+							var className = srcNode.getAttribute('class') || srcNode.className || "";
+							if(typeof style == "object"){
+								style = style.cssText || "";
+							}
+							srcNode.innerHTML = "";
+							srcNode.removeAttribute('style');
+							srcNode.className = "";
+
+							makeIframe(id, className, style, content, "strict", false, srcNode);
+							makeIframe(id, className, style, content, "quirks", false, srcNode);
+							makeIframe(id, className, style, content, "loose", true, srcNode);
+							makeIframe(id, className, style, content, "quirks", true, srcNode);
+						}
 						return loading;
 					}
 				},
@@ -38,223 +235,331 @@
 					dojo.window.scrollIntoView(body);
 					doh.f(dojo.hasAttr(body,'_offsetParent'));
 					doh.f(dojo.hasAttr(body,'_parent'));
-				},
-				function test_8249(){
-					generateTest('8249_strict', '(0,-10)', '(0,+10)');
-					generateTest('8249_quirks', '(0,-10)', '(0,+10)');
-					generateTest('8249_loose_rtl', '(0,-10)', '(0,+10)');
-					generateTest('8249_quirks_rtl', '(0,-10)', '(0,+10)');
-				},
-				function test_8284(){
-					var minScroll, maxScroll, fudge=0;
-					if(dojo.isIE <= 8){
-						minScroll = maxScroll = 11;
-						if(dojo.isIE <= 6){
-							fudge = dojo.byId('8284_quirks').contentWindow.document.body.clientHeight-100; // needed for running inside DOH runner
-						}
-					}else{
-						minScroll = maxScroll = 10;
-					}
-					generateTestXY('8284_quirks', "0", -maxScroll+fudge, "0", minScroll-fudge);
-					generateTestXY('8284_quirks_rtl', "0", -maxScroll+fudge, "0", minScroll-fudge);
-					if(dojo.isIE == 8){
-						minScroll = maxScroll = 10;
-					}
-					generateTestXY('8284_strict', "0", -maxScroll, "0", minScroll);
-					generateTestXY('8284_loose_rtl', "0", -maxScroll, "0", minScroll);
-				},
-				function test_absContent(){
-					generateTestXY('absContent_strict', 0, -10, 0, 10);
-					generateTestXY('absContent_loose_rtl', 0, -10, 0, 10);
-					generateTestXY('absContent_quirks', 0, -10, 0, 10);
-					generateTestXY('absContent_quirks_rtl', 0, -10, 0, 10);
-				},
-				function test_fixedNode(){
-					if(!(dojo.isIE <= 6)){
-						generateTest('fixedNode_strict', "(-1,-1)", "(+1,+1)");
-						generateTest('fixedNode_loose_rtl', "(-1,-1)", "(+1,+1)");
-					}
-					if(!dojo.isIE){
-						generateTest('fixedNode_quirks', "(-1,-1)", "(+1,+1)");
-						generateTest('fixedNode_quirks_rtl', "(-1,-1)", "(+1,+1)");
-					}
-				},
-				function test_fixedScrollable(){
-					if(!(dojo.isIE <= 6)){
-						generateTest('fixedScrollable_strict', dojo.isIE == 7? "(0,-54)(0,-1)" : "(0,-39)(0,-1)", dojo.isIE == 7? "(0,+39)(0,+1)" : "(0,+38)(0,+1)");
-						generateTest('fixedScrollable_loose_rtl', dojo.isIE == 7? "(0,-54)(0,-1)" : "(0,-39)(0,-1)", dojo.isIE == 7? "(0,+39)(0,+1)" : "(0,+38)(0,+1)");
-					}
-					if(!dojo.isIE){
-						generateTest('fixedScrollable_quirks', "(0,-39)(0,-1)", "(0,+38)(0,+1)");
-						generateTest('fixedScrollable_quirks_rtl', "(0,-39)(0,-1)", "(0,+38)(0,+1)");
-					}
-				},
-				function test_7036_8665(){
-					var maxScroll = 39;
-					var minScroll = 38;
-					if(dojo.isIE <= 7){
-						maxScroll = 54;
-						minScroll = 39;
-					}
-					generateTest('7036_8665_strict', "(0,-"+maxScroll+")(0,-1)", "(0,+"+minScroll+")(0,+1)");
-					generateTest('7036_8665_loose_rtl', "(0,-"+maxScroll+")(0,-1)", "(0,+"+minScroll+")(0,+1)");
-					if(dojo.isIE == 8){
-						maxScroll = 54;
-						minScroll = 39;
-					}
-					generateTest('7036_8665_quirks', "(0,-"+maxScroll+")(0,-1)", "(0,+"+minScroll+")(0,+1)");
-					generateTest('7036_8665_quirks_rtl', "(0,-"+maxScroll+")(0,-1)", "(0,+"+minScroll+")(0,+1)");
-				},
-				function test_innerNoScrollBars(){
-					var scroll;
-					if(dojo.isIE <= 6){
-						scroll = 53;
-					}else if(dojo.isIE == 7){
-						scroll = 46;
-					}else{
-						scroll = 39;
-					}
-					generateTestXY('innerNoScrollBars_strict', scroll, -29, scroll, -29);
-					if(dojo.isIE <= 8){
-						scroll = -38;
-					}
-					generateTestXY('innerNoScrollBars_quirks', scroll, -29, scroll, -29);
-					if(dojo.isIE <= 6){
-						scroll = 53;
-					}else if(dojo.isIE == 7){
-						scroll = 46;
-					}else if(dojo.isIE >= 8 || dojo.isOpera){
-						scroll = "+0";
-					}else if(dojo.isWebKit){
-						scroll = "-0";
-					}else{
-						scroll = 39;
-					}
-					generateTestXY('innerNoScrollBars_loose_rtl', scroll, -29, scroll, -29);
-					if(dojo.isIE <= 8){
-						scroll = -38;
-					}
-					generateTestXY('innerNoScrollBars_quirks_rtl', scroll, -29, scroll, -29);
-				},
-				function test_noScrollBars(){
-					generateTest('noScrollBars_strict', "(0,0)", "(0,0)");
-					generateTest('noScrollBars_quirks', "(0,0)", "(0,0)");
-					generateTest('noScrollBars_loose_rtl', "(0,0)", "(0,0)");
-					generateTest('noScrollBars_quirks_rtl', "(0,0)", "(0,0)");
-				},
-				function test_table(){
-					var minScroll, maxScroll;
-					minScroll = "(0,+15)";
-					maxScroll = "(0,-15)";
-					generateTest('table_strict', maxScroll, minScroll);
-					generateTest('table_loose_rtl', maxScroll, minScroll);
-					if(dojo.isIE <= 6){
-						var fudge = dojo.byId('table_quirks').contentWindow.document.body.clientHeight-100; // needed for running inside DOH runner
-						maxScroll = "(0,-"+(15-fudge)+")";
-						minScroll = "(0,+"+(15-fudge)+")";
-					}
-					generateTest('table_quirks', maxScroll, minScroll);
-					generateTest('table_quirks_rtl', maxScroll, minScroll);
-				},
-				function test_innerScrollbars(){
-					var scroll = innerScrollBarSize - 5;
-					generateTestXY('innerScrollbars_strict', -scroll, -scroll, scroll, scroll);
-					generateTestXY('innerScrollbars_loose_rtl', -scroll, -scroll, dojo.isIE == 7 ? -25 : scroll, scroll);
-					generateTestXY('innerScrollbars_quirks', -scroll, -scroll, scroll, scroll);
-					generateTestXY('innerScrollbars_quirks_rtl', -scroll, -scroll, scroll, scroll);
-				},
-				function test_8542(){
-					var fudge = 0;
-					if(dojo.isIE <= 6){
-						fudge = dojo.byId('8542_quirks').contentWindow.document.body.clientHeight-100; // needed for running inside DOH runner
-					}
-					generateTest('8542_strict', "(0,-10)", "(0,+20)");
-					generateTest('8542_quirks', "(0,-"+(10-fudge)+")", "(0,+"+(20-fudge)+")");
-					generateTest('8542_loose_rtl', "(0,-10)", "(0,+20)");
-					generateTest('8542_quirks_rtl', "(0,-"+(10-fudge)+")", "(0,+"+(20-fudge)+")");
-				},
-				function test_tooBig(){
-					var fudge = 0;
-					if(dojo.isIE <= 6){
-						fudge = dojo.byId('tooBig_quirks').contentWindow.document.body.clientHeight-100+innerScrollBarSize; // needed for running inside DOH runner
-					}
-					var minScroll, maxScroll;
-					generateTestXY('tooBig_strict', outerScrollBarSize+10,outerScrollBarSize+20, 1,1);
-					generateTestXY('tooBig_quirks', outerScrollBarSize+10-fudge,outerScrollBarSize+20-fudge, 1,1);
-					if(dojo.isIE <= 7 || dojo.isMoz || dojo.isChrome){
-						maxScroll = -1;
-					}else if(dojo.isIE){
-						maxScroll = +20;
-					}else if(dojo.isOpera){
-						maxScroll = -90;
-					}else{
-						maxScroll = outerScrollBarSize+10;
-					}
-					if(dojo.isIE <= 7 || dojo.isMoz || dojo.isChrome){
-						minScroll = -20;
-					}else if(dojo.isOpera){
-						minScroll = 80 + outerScrollBarSize;
-					}else{
-						minScroll = 1;
-					}
-					generateTestXY('tooBig_loose_rtl', maxScroll,outerScrollBarSize+20, minScroll,1);
-					if(dojo.isIE >= 8){
-						maxScroll = -1;
-					}
-					if(dojo.isIE == 8){
-						minScroll = -20;
-					}
-					generateTestXY('tooBig_quirks_rtl', maxScroll,outerScrollBarSize+20-fudge, minScroll,1);
-				},
-				function test_htmlPadding(){
-					var fudge = 0;
-					if(dojo.isIE <= 6){
-						fudge = dojo.byId('tooBig_quirks').contentWindow.document.body.clientHeight-100+innerScrollBarSize; // needed for running inside DOH runner
-					}
-					var minScroll, maxScroll;
-					if(dojo.isIE <= 7){
-						maxScroll = minScroll = 84;
-					}else{
-						maxScroll = minScroll = 70;
-					}
-					generateTest('htmlPadding_strict', "(0,-"+maxScroll+")", "(0,+"+minScroll+")");
-					generateTest('htmlPadding_loose_rtl', "(0,-"+maxScroll+")", "(0,+"+minScroll+")");
-					if(dojo.isIE <= 8){
-						maxScroll = minScroll = 34;
-					}
-					generateTest('htmlPadding_quirks', "(0,-"+(maxScroll-fudge)+")", "(0,+"+(minScroll-fudge)+")");
-					generateTest('htmlPadding_quirks_rtl', "(0,-"+(maxScroll-fudge)+")", "(0,+"+(minScroll-fudge)+")");
 				}
 			]);
-		        doh.run();
+                        dojo.forEach([	'8249',
+					'8284',
+					'absContent',
+					'fixedNode',
+					'fixedScrollable',
+					'7036_8665',
+					'innerNoScrollBars',
+					'noScrollBars',
+					'table',
+					'innerScrollbars',
+					'8542',
+					'tooBig',
+					'htmlPadding' ],
+				function(test){
+                        		dojo.forEach([	"_strict", "_quirks", "_loose_rtl", "_quirks_rtl" ],
+						function(mode){
+							var	id = test+mode,
+								n, maxWidth, maxHeight, nodeWidth, nodeHeight, rAfterScroll, vAfterScroll, rBeforeScroll, vBeforeScroll;
+							doh.register(id, [
+							{
+								timeout: 4000,
+								name: "compare to native",
+								runTest: function(){ with(dojo.byId(id)){
+									n = findInput();
+									scrollMin(n);
+									var d = new doh.Deferred();
+									setTimeout(function(){
+										rBeforeScroll = getBoundingRect(n);
+										vBeforeScroll = getVisibleSize(n);
+										nodeWidth = rBeforeScroll.w;
+										nodeHeight = rBeforeScroll.h;
+										dojo.byId(id).style.visibility = 'visible';
+										n.scrollIntoView(true);
+										setTimeout(function(){
+											var vAfterNativeScroll = getVisibleSize(n);
+											scrollIntoView();
+											setTimeout(d.getTestCallback(function(){
+												vAfterScroll = getVisibleSize(n);
+												doh.t(vAfterScroll.w > 0, "min width " + vAfterScroll.w);
+												doh.t(vAfterScroll.h > 0, "min height " + vAfterScroll.h);
+												doh.t(vAfterScroll.w >= vAfterNativeScroll.w, "width compare " + vAfterNativeScroll.w + " to " + vAfterScroll.w);
+												doh.t(vAfterScroll.h >= vAfterNativeScroll.h, "height compare " + vAfterNativeScroll.h + " to " + vAfterScroll.h);
+												maxWidth = Math.max(vAfterNativeScroll.w, vAfterScroll.w);
+												maxHeight = Math.max(vAfterNativeScroll.h, vAfterScroll.h);
+											}), 0);
+										}, 0);
+									}, 0);
+									return d;
+								}}
+							},
+							{
+								timeout: 4000,
+								name: "min start horizontal",
+								runTest: function(){ with(dojo.byId(id)){
+									scrollMin(n);
+									var d = new doh.Deferred();
+									setTimeout(function(){
+										scrollIntoView(1,0);
+										setTimeout(function(){
+											rAfterScroll = getBoundingRect(n);
+											vAfterScroll = getVisibleSize(n);
+											if(rAfterScroll.left > rBeforeScroll.left){ // shifted right so all but leftmost pixel on first row is showing
+												scrollIntoView(0,0);
+												setTimeout(d.getTestCallback(function(){
+													doh.is(nodeWidth > maxWidth ? maxWidth : (maxWidth-1), vAfterScroll.w, "min: start: shift right partial width");
+													vAfterScroll = getVisibleSize(n);
+													doh.is(vAfterScroll.w, maxWidth, "min: start: shift right full width");
+												}), 0);
+											}else if(rAfterScroll.left < rBeforeScroll.left){ // shifted left so only 2 leftmost pixels on first row are showing
+												scrollIntoView(nodeWidth-1,0);
+												setTimeout(d.getTestCallback(function(){
+													doh.is(2, vAfterScroll.w, "min: start: shift left width");
+													vAfterScroll = getVisibleSize(n);
+													doh.is(vAfterScroll.w, maxWidth, "min: start: shift left full width");
+												}), 0);
+											}else{ // no horizontal scrolling
+												scrollIntoView(0,0,nodeWidth);
+												setTimeout(d.getTestCallback(function(){
+													vAfterScroll = getVisibleSize(n);
+													doh.is(maxWidth, vAfterScroll.w, "min: start: no shift full width");
+												}), 0);
+											}
+										}, 0);
+									}, 0);
+									return d;
+								}}
+							},
+							{
+								timeout: 2000,
+								name: "min start vertical",
+								runTest: function(){ with(dojo.byId(id)){
+									var d = new doh.Deferred();
+									if(rAfterScroll.top > rBeforeScroll.top){ // shifted down so all rows are showing
+										scrollIntoView(1,nodeHeight-1);
+										setTimeout(d.getTestCallback(function(){
+											doh.is(vAfterScroll.h, maxHeight, "min: start: shift down height");
+											vAfterScroll = getVisibleSize(n);
+											doh.is(vAfterScroll.h, maxHeight, "min: start: shift down full height");
+										}), 0);
+									}else if(rAfterScroll.top < rBeforeScroll.top){ // shifted up so only the first row is showing
+										scrollIntoView(0,nodeHeight-1);
+										setTimeout(d.getTestCallback(function(){
+											doh.is(1, vAfterScroll.h, "min: start: shift up height");
+											vAfterScroll = getVisibleSize(n);
+											doh.is(vAfterScroll.h, maxHeight, "min: start: shift up full height");
+										}), 0);
+									}else{ // no vertical scrolling
+										scrollIntoView(0,nodeHeight-1);
+										setTimeout(d.getTestCallback(function(){
+											vAfterScroll = getVisibleSize(n);
+											doh.is(vAfterScroll.h, maxHeight, "min: start: no shift full height");
+										}), 0);
+									}
+									return d;
+								}}
+							},
+							{
+								timeout: 4000,
+								name: "min end horizontal",
+								runTest: function(){ with(dojo.byId(id)){
+									scrollMin(n);
+									var d = new doh.Deferred();
+									setTimeout(function(){
+										scrollIntoView(nodeWidth-2,nodeHeight-1);
+										setTimeout(function(){
+											rAfterScroll = getBoundingRect(n);
+											vAfterScroll = getVisibleSize(n);
+											if(rAfterScroll.left < rBeforeScroll.left){ // shifted left so all but rightmost pixel on first row is showing
+												scrollIntoView(nodeWidth-1,nodeHeight-1);
+												setTimeout(d.getTestCallback(function(){
+													doh.is(nodeWidth > maxWidth ? maxWidth : (maxWidth-1), vAfterScroll.w, "min: end: shift left partial width");
+													vAfterScroll = getVisibleSize(n);
+													doh.is(vAfterScroll.w, maxWidth, "min: end: shift left full width");
+												}), 0);
+											}else if(rAfterScroll.left > rBeforeScroll.left){ // shifted right so only 2 rightmost pixels on first row are showing
+												scrollIntoView(0,nodeHeight-1);
+												setTimeout(d.getTestCallback(function(){
+													doh.is(2, vAfterScroll.w, "min: end: shift right width");
+													vAfterScroll = getVisibleSize(n);
+													doh.is(vAfterScroll.w, maxWidth, "min: end: shift right full width");
+												}), 0);
+											}else{ // no horizontal scrolling
+												scrollIntoView(0,nodeHeight-1,nodeWidth);
+												setTimeout(d.getTestCallback(function(){
+													vAfterScroll = getVisibleSize(n);
+													doh.is(vAfterScroll.w, maxWidth, "min: end: no shift full width");
+												}), 0);
+											}
+										}, 0);
+									}, 0);
+									return d;
+								}}
+							},
+							{
+								timeout: 2000,
+								name: "min end vertical",
+								runTest: function(){ with(dojo.byId(id)){
+									var d = new doh.Deferred();
+									if(rAfterScroll.top < rBeforeScroll.top){ // shifted up so all rows are showing
+										scrollIntoView(nodeWidth-1,0);
+										setTimeout(d.getTestCallback(function(){
+											doh.is(vAfterScroll.h, maxHeight, "min: end: shift up height");
+											vAfterScroll = getVisibleSize(n);
+											doh.is(vAfterScroll.h, maxHeight, "min: end: shift up full height");
+										}), 0);
+									}else if(rAfterScroll.top > rBeforeScroll.top){ // shifted down so only the last row is showing
+										scrollIntoView(0,0);
+										setTimeout(d.getTestCallback(function(){
+											doh.is(1, vAfterScroll.h, "min: end: shift down height");
+											vAfterScroll = getVisibleSize(n);
+											doh.is(vAfterScroll.h, maxHeight, "min: end: shift down full height");
+										}), 0);
+									}else{ // no vertical scrolling
+										scrollIntoView(0,nodeHeight-1);
+										setTimeout(d.getTestCallback(function(){
+											vAfterScroll = getVisibleSize(n);
+											doh.is(vAfterScroll.h, maxHeight, "min: end: no shift full height");
+										}), 0);
+									}
+									return d;
+								}}
+							},
+							{
+								timeout: 4000,
+								name: "max start horizontal",
+								runTest: function(){ with(dojo.byId(id)){
+									scrollMax(n);
+									var d = new doh.Deferred();
+									setTimeout(function(){
+										rBeforeScroll = getBoundingRect(n);
+										vBeforeScroll = getVisibleSize(n);
+										scrollIntoView(1,0);
+										setTimeout(function(){
+											rAfterScroll = getBoundingRect(n);
+											vAfterScroll = getVisibleSize(n);
+											if(rAfterScroll.left > rBeforeScroll.left){ // shifted right so all but leftmost pixel on first row is showing
+												scrollIntoView(0,0);
+												setTimeout(d.getTestCallback(function(){
+													doh.is(nodeWidth > maxWidth ? maxWidth : (maxWidth-1), vAfterScroll.w, "max: start: shift right partial width");
+													vAfterScroll = getVisibleSize(n);
+													doh.is(vAfterScroll.w, maxWidth, "max: start: shift right full width");
+												}), 0);
+											}else if(rAfterScroll.left < rBeforeScroll.left){ // shifted left so only 2 leftmost pixels on first row are showing
+												scrollIntoView(nodeWidth-1,0);
+												setTimeout(d.getTestCallback(function(){
+													doh.is(2, vAfterScroll.w, "max: start: shift left width");
+													vAfterScroll = getVisibleSize(n);
+													doh.is(vAfterScroll.w, maxWidth, "max: start: shift left full width");
+												}), 0);
+											}else{ // no horizontal scrolling
+												scrollIntoView(0,0,nodeWidth);
+												setTimeout(d.getTestCallback(function(){
+													vAfterScroll = getVisibleSize(n);
+													doh.is(vAfterScroll.w, maxWidth, "max: start: no shift full width");
+												}), 0);
+											}
+										}, 0);
+									}, 0);
+									return d;
+								}}
+							},
+							{
+								timeout: 2000,
+								name: "max start vertical",
+								runTest: function(){ with(dojo.byId(id)){
+									var d = new doh.Deferred();
+									if(rAfterScroll.top > rBeforeScroll.top){ // shifted down so all rows are showing
+										scrollIntoView(1,nodeHeight-1);
+										setTimeout(d.getTestCallback(function(){
+											doh.is(vAfterScroll.h, maxHeight, "max: start: shift down height");
+											vAfterScroll = getVisibleSize(n);
+											doh.is(vAfterScroll.h, maxHeight, "max: start: shift down full height");
+										}), 0);
+									}else if(rAfterScroll.top < rBeforeScroll.top){ // shifted up so only the first row is showing
+										scrollIntoView(0,nodeHeight-1);
+										setTimeout(d.getTestCallback(function(){
+											doh.is(1, vAfterScroll.h, "max: start: shift up height");
+											vAfterScroll = getVisibleSize(n);
+											doh.is(vAfterScroll.h, maxHeight, "max: start: shift up full height");
+										}), 0);
+									}else{ // no vertical scrolling
+										scrollIntoView(0,nodeHeight-1);
+										setTimeout(d.getTestCallback(function(){
+											vAfterScroll = getVisibleSize(n);
+											doh.is(vAfterScroll.h, maxHeight, "max: start: no shift full height");
+										}), 0);
+									}
+									return d;
+								}}
+							},
+							{
+								timeout: 4000,
+								name: "max end horizontal",
+								runTest: function(){ with(dojo.byId(id)){
+									scrollMax(n);
+									var d = new doh.Deferred();
+									setTimeout(function(){
+										scrollIntoView(nodeWidth-2,nodeHeight-1);
+										setTimeout(function(){
+											rAfterScroll = getBoundingRect(n);
+											vAfterScroll = getVisibleSize(n);
+											if(rAfterScroll.left < rBeforeScroll.left){ // shifted left so all but rightmost pixel on first row is showing
+												scrollIntoView(nodeWidth-1,nodeHeight-1);
+												setTimeout(d.getTestCallback(function(){
+													doh.is(nodeWidth > maxWidth ? maxWidth : (maxWidth-1), vAfterScroll.w, "max: end: shift left partial width");
+													vAfterScroll = getVisibleSize(n);
+													doh.is(vAfterScroll.w, maxWidth, "max: end: shift left full width");
+												}), 0);
+											}else if(rAfterScroll.left > rBeforeScroll.left){ // shifted right so only 2 rightmost pixels on first row are showing
+												scrollIntoView(0,nodeHeight-1);
+												setTimeout(d.getTestCallback(function(){
+													doh.is(2, vAfterScroll.w, "max: end: shift right width");
+													vAfterScroll = getVisibleSize(n);
+													doh.is(vAfterScroll.w, maxWidth, "max: end: shift right full width");
+												}), 0);
+											}else{ // no horizontal scrolling
+												scrollIntoView(0,nodeHeight-1,nodeWidth);
+												setTimeout(d.getTestCallback(function(){
+													vAfterScroll = getVisibleSize(n);
+													doh.is(vAfterScroll.w, maxWidth, "max: end: no shift full width");
+												}), 0);
+											}
+										}, 0);
+									}, 0);
+									return d;
+								}}
+							},
+							{
+								timeout: 2000,
+								name: "max end vertical",
+								runTest: function(){ with(dojo.byId(id)){
+									var d = new doh.Deferred();
+									if(rAfterScroll.top < rBeforeScroll.top){ // shifted up so all rows are showing
+										scrollIntoView(nodeWidth-1,0);
+										setTimeout(d.getTestCallback(function(){
+											doh.is(vAfterScroll.h, maxHeight, "max: end: shift up height");
+											vAfterScroll = getVisibleSize(n);
+											doh.is(vAfterScroll.h, maxHeight, "max: end: shift up full height");
+										}), 0);
+									}else if(rAfterScroll.top > rBeforeScroll.top){ // shifted down so only the last row is showing
+										scrollIntoView(0,0);
+										setTimeout(d.getTestCallback(function(){
+											doh.is(1, vAfterScroll.h, "max: end: shift down height");
+											vAfterScroll = getVisibleSize(n);
+											doh.is(vAfterScroll.h, maxHeight, "max: end: shift down full height");
+										}), 0);
+									}else{ // no vertical scrolling
+										scrollIntoView(0,0);
+										setTimeout(d.getTestCallback(function(){
+											vAfterScroll = getVisibleSize(n);
+											doh.is(vAfterScroll.h, maxHeight, "max: end: no shift full height");
+										}), 0);
+									}
+									return d;
+								}}
+							}]);
+						}
+					);
+				} 
+			);
+
+			doh.run();
 		});
-		function generateTest(id, maxVal, minVal){
-			var compare = usingNative? "isNot" : "is";
-			with(dojo.byId(id)){
-				scrollMin();
-				scrollMax();
-				scrollIntoView();
-				var maxActualScroll = getScroll();
-				var maxExpectedScroll = usingNative? "(-1,-1)" : maxVal;
-				scrollIntoView(); // make sure the value sticks
-				var repMaxActualScroll = getScroll();
-				scrollMin();
-				scrollIntoView();
-				var minActualScroll = getScroll();
-				var minExpectedScroll = usingNative? "(+1,+1)" : minVal;
-				dojo.byId(id).style.visibility = 'visible';
-				doh[compare](maxExpectedScroll, maxActualScroll, id+" max failed");
-				doh[compare](maxExpectedScroll, repMaxActualScroll, id+" repeat max failed");
-				doh[compare](minExpectedScroll, minActualScroll, id+" min failed");
-			}
-		}
-		function generateTestXY(id, maxScrollX, maxScrollY, minScrollX, minScrollY){
-			if(typeof maxScrollX == "number" && maxScrollX > 0){ maxScrollX = "+" + maxScrollX; }
-			if(typeof maxScrollY == "number" && maxScrollY > 0){ maxScrollY = "+" + maxScrollY; }
-			if(typeof minScrollX == "number" && minScrollX > 0){ minScrollX = "+" + minScrollX; }
-			if(typeof minScrollY == "number" && minScrollY > 0){ minScrollY = "+" + minScrollY; }
-			generateTest(id, "("+maxScrollX+","+maxScrollY+")", "("+minScrollX+","+minScrollY+")");
-		}
 	</script>
 </head>
 <body>
@@ -268,17 +573,19 @@
 <fieldset>
 <label for="8249">Scrollable parent != offsetParent:</label>
 <div type="testIframe" id="8249">
-	<iframestyle>INPUT { float:left; }</iframestyle>
-	<div style="border-width:13px;"
-		><ul style="height:70px;"
-			><li><input style="background-color:white;"></li
-			><li><input style="background-color:white;"></li
-			><li><input style="background-color:white;"></li
-			><li><input id=it></li
-			><li><input style="background-color:white;"></li
-			><li><input style="background-color:white;"></li
-			><li><input style="background-color:white;"></li
-		></ul
+	<iframestyle>INPUT { float:left; }
+		HTML, BODY { overflow: hidden; }
+	</iframestyle>
+	<div style="height:61px;width:50px;overflow-y:scroll;margin:11px 20px"
+		><p style="display:inline;"
+		><li><input style="visibility:hidden;"></li
+		><li><input style="visibility:hidden;"></li
+		><li><input style="visibility:hidden;"></li
+		><li><input id=it></li
+		><li><input style="visibility:hidden;"></li
+		><li><input style="visibility:hidden;"></li
+		><li><input style="visibility:hidden;"></li
+		></p
 	></div>
 </div>
 </fieldset>
@@ -311,10 +618,10 @@
 <fieldset>
 <label for="fixedScrollable">Fixed-positioned scrollable content:</label>
 <div type="testIframe" id="fixedScrollable">
-	<iframestyle>HTML { overflow-x:hidden !important; /*IE6*/ }
-		INPUT { height:20px; MZT_MZQ_WKT_WKQ_IEQ_OPQ_OPT_height:28px; width:20px; MZT_MZQ_WKT_WKQ_IEQ_OPQ_OPT_width:28px; }</iframestyle>
-	<div style="height:120px;width:70px;overflow-y:scroll;position:fixed;margin:-10px 0px 0px 0px;">
-		<input id=it style="margin:120px 0px;border:1px solid red;padding:3px;">
+	<iframestyle>HTML { overflow:hidden !important; /*IE6*/ }
+		INPUT { height:20px; width:20px; }</iframestyle>
+	<div style="height:100px;width:70px;overflow-y:scroll;position:fixed;top:0px;left:0;">
+		<input id=it style="margin:120px 0px;">
 		<hr style="width:10px;">
 	</div>
 	<hr style="height:200px;width:20px;"/>
@@ -323,9 +630,9 @@
 <fieldset>
 <label for="7036_8665">Double scrollbars with absolute positioned content:</label>
 <div type="testIframe" id="7036_8665">
-	<iframestyle>INPUT { height:20px; MZT_MZQ_WKT_WKQ_IEQ_OPQ_OPT_height:28px; width:20px; MZT_MZQ_WKT_WKQ_IEQ_OPQ_OPT_width:28px; }</iframestyle>
+	<iframestyle>INPUT { height:28px; width:28px; }</iframestyle>
 	<div style="height:70px;width:70px;overflow-y:scroll;position:absolute;top:26px;left:5px;"
-		><input id=it style="margin:80px 0px 80px 0px;border:1px solid red;padding:3px;"
+		><input id=it style="margin:80px 0px 80px 0px;"
 		><hr style="width:10px;"
 	></div>
 	<div style="height:26px;width:10px;position:absolute;top:96px;left:10px;"></div>
@@ -339,9 +646,9 @@
 	><div style="overflow:hidden; width:20px;height:20px;"
 		><fieldset style="width:59px;overflow:visible;"
 			><input style="background-color:green;height:15px;float:left;"
-			><nobr style="margin:7px;padding:3px;border:5px solid pink;overflow:visible;display:block;width:90px;float:left;"
+			><nobr style="margin:7px;padding:3px;border:5px solid black;overflow:visible;display:block;width:90px;float:left;"
 				><input style="background-color:black;display:inline;width:24px;height:24px;float:left;"
-				><input id=it style="background-color:red;display:inline;float:left;"
+				><input id=it style="display:inline;float:left;"
 				><input style="background-color:blue;display:inline;width:16px;height:16px;float:left;"
 			></nobr
 			><input style="background-color:cyan;height:10px;float:left;"
@@ -378,9 +685,9 @@
 		TABLE { OPR_float:left; }
 	</iframestyle>
 	<div style="overflow:scroll;height:80px;width:80px;"
-		><fieldset
-			><table cellspacing="25" cellpadding="0" border="0"
-				><tr><td><input id=it style="width:50px;height:50px;float:left;"></td></tr
+		><fieldset style="visibility:hidden;"
+			><table cellspacing="65" cellpadding="0" border="0"
+				><tr><td><input id=it style="width:50px;height:50px;clear:both;float:left;visibility:visible;"></td></tr
 			></table
 		></fieldset
 	></div>
@@ -419,191 +726,5 @@
 </div>
 </fieldset>
 <br>
-<!--	Below is the magic code that creates the iframes from the given template.
-	This should be generalized for other files to include. -->
-<script>
-	function _findInput(win){
-		return win.document.getElementById('it');
-	}
-	function _scrollMin(win){
-		var n = _findInput(win);
-		while(n && n.tagName){
-			n.scrollTop = -9999;
-			n.scrollLeft = -9999;
-			n._scrollMinY = n.scrollTop;
-			n._scrollMinX = n.scrollLeft;
-			n.scrollTop++;
-			if(((n._scrollMaxX||0)-n._scrollMinX) == innerScrollBarSize && (n.scrollWidth <= n.clientWidth || n.scrollWidth <= n.offsetWidth)){ // ignore fake scrolls
-			}else if((n._scrollMaxX||0) > n._scrollMinX){
-				n.scrollLeft++;
-			}
-			if(n.tagName == "BODY" && (n.scrollLeft || n.scrollTop)){ break; }
-			n = n.parentNode;
-		}
-	}
-	function _scrollMax(win){
-		var n = _findInput(win);
-		while(n && n.tagName){
-			n.scrollTop = 9999;
-			n.scrollLeft = 9999;
-			n._scrollMaxY = n.scrollTop;
-			n._scrollMaxX = n.scrollLeft;
-			n.scrollTop--;
-			if((n._scrollMaxX-(n._scrollMinX||0)) == innerScrollBarSize && (n.scrollWidth <= n.clientWidth || n.scrollWidth <= n.offsetWidth)){
-				n._scrollMaxX = n.scrollLeft = (n._scrollMinX || 0); // ignore fake scrolls
-			}else{
-				n.scrollLeft--;
-			}
-			if(n.tagName == "BODY" && (n.scrollLeft || n.scrollTop || n._scrollMaxY || n._scrollMaxX)){
-				break; // skip HTML
-			}
-			n = n.parentNode;
-		}
-	}
-	function _getScroll(win){
-		var n = _findInput(win), scroll = '';
-		while(n && n.tagName){
-			var left = n.scrollLeft - n._scrollMinX,
-			top = n.scrollTop - n._scrollMinY,
-			right = n._scrollMaxX - n.scrollLeft,
-			bottom = n._scrollMaxY - n.scrollTop;
-			if(left || top || n._scrollMinX || n._scrollMaxX || n._scrollMinY || n._scrollMaxY){
-				scroll += '('+(left<=right?((left==right?'':'+')+left):(right<0 ? '0' : ('-'+right)))+','+(top<=bottom?((top==bottom?'':'+')+top):(bottom<0 ? '0' : ('-'+bottom)))+')';
-			}
-			n = n.parentNode;
-		}
-		return scroll || '(0,0)';
-	}
-	function _scrollIntoView(win){
-		var n = _findInput(win);
-		dojo.withGlobal(win, 'scrollIntoView', dojo.window, [n]);
-	}
-	function _onClick(win){
-		_scrollIntoView(win);
-		alert(_getScroll(win));
-	}
-	function iframeLoaded(){
-		if(--count == 0){ loading.callback(true); }
-	}
-	function initIframeMethods(iframeWin, parentWin){
-		iframeWin.frameElement.findInput = function(){ return parentWin._findInput(iframeWin) };
-		iframeWin.frameElement.scrollMin = function(){ parentWin._scrollMin(iframeWin) };
-		iframeWin.frameElement.scrollMax = function(){ parentWin._scrollMax(iframeWin) };
-		iframeWin.frameElement.getScroll = function(){ return parentWin._getScroll(iframeWin) };
-		iframeWin.frameElement.scrollIntoView = function(){ parentWin._scrollIntoView(iframeWin) };
-		iframeWin.frameElement.onClick = function(){ parentWin._onClick(iframeWin) };
-	}
-	function getIframeSrc(content, doctype, rtl){
-		content = content.replace(/"/g/*balance"*/,"'").replace(/iframe.javascript/g,"text/javascript").replace(/<input\b/ig,"<INPUT readOnly ");
-		var iframeSrc = 'javascript:"';
-		// find browser specific CSS attributes
-		if(dojo.isIE){
-			content = content.replace(/IE([A-Z]_)/g, "$1");
-		}else if(dojo.isWebKit){
-			content = content.replace(/WK([A-Z]_)/g, "$1");
-		}else if(dojo.isMoz){
-			content = content.replace(/MZ([A-Z]_)/g, "$1");
-		}else if(dojo.isOpera){
-			content = content.replace(/OP([A-Z]_)/g, "$1");
-		}
-		// find DOCTYPE specific CSS attributes
-		if(doctype=="strict"){
-			iframeSrc += "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01//EN' 'http://www.w3.org/TR/html4/strict.dtd'>\n";
-			content = content.replace(/[A-Z0-9_]*(\b|_)[SZ]_[A-Z0-9_]*/g, "");
-		}else if(doctype=="loose"){
-			iframeSrc += "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0 Transitional//EN' 'http://www.w3.org/TR/html4/loose.dtd'>\n";
-			content = content.replace(/[A-Z0-9_]*(\b|_)[TZ]_[A-Z0-9_]*/g, "");
-		}else{
-			if(dojo.isWebKit){
-				iframeSrc += "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>\n"; // quirks: needed for WebKit's javascript: protocol
-			}
-			content = content.replace(/[A-Z0-9_]*(\b|_)[QZ]_[A-Z0-9_]*/g, "");
-		}
-		if(rtl){
-			content = content.replace(/[A-Z0-9_]*(\b|_)R_[A-Z0-9_]*/g, "");
-		}else{
-			content = content.replace(/[A-Z0-9_]*(\b|_)L_[A-Z0-9_]*/g, "");
-		}
-		content = content.replace(/\s*<(\/?)iframestyle>\s*/ig,"<$1"+"STYLE>");
-		var i = content.indexOf('<STYLE>');
-		var style = '';
-		if(i >= 0){
-			var j = content.indexOf('</STYLE>');
-			if(j >= 0){
-				style = content.substring(i+7, j);
-				content = content.substr(j+8);
-			}
-		}
-		iframeSrc +=
-		'<HTML dir='+(rtl?'rtl':'ltr')+'>'+
-		'<HEAD>'+
-			'<STYLE>'+
-				'* { border:0px solid white;padding:0px;margin:0px;font-style:normal;font-family:monospace;font-size:0px;line-height:normal; }\n'+
-				'INPUT { display:block;background-color:#ff0000;font-size:0px;line-height:0px;overflow:hidden;width:20px;height:20px; }\n'+
-				'UL { list-style-type: none;line-height:0px;width:45px;overflow:auto; }\n'+
-				'LI { list-style-type: none;line-height:20px;overflow:visible;max-width:20px;max-height:20px;height:20px;width:20px;float:left; }\n'+
-				'HR { width:120px;height:1px;visibility:hidden;display:block; }\n'+
-				style+
-			'<\/STYLE>'+
-		'<\/HEAD>'+
-		'<BODY BGCOLOR=#ffffff>'+
-			content+
-			'<SCRIPT type=text/javascript>'+
-				'win=frameElement.ownerDocument.defaultView||frameElement.document.parentWindow;'+
-				'win.initIframeMethods(window, win);'+
-				'win.iframeLoaded();'+
-				'document.body.onclick=frameElement.onClick;'+
-			'<\/SCRIPT>'+
-		'<\/BODY>'+
-		'<\/HTML>"';
-		return iframeSrc;
-	}
-
-	function makeIframe(doctype, rtl){
-		var iframeSrc = getIframeSrc(content, doctype, rtl);
-		var container = document.createElement('fieldset');
-		var text = (doctype=="strict"? 'strict': (doctype=="loose"? 'loose' : 'quirks')) + (rtl? ' RTL' : '');
-		var color = (rtl? 'medium': '') + (doctype=="strict"? 'SpringGreen': (doctype=="loose"? 'Turquoise' : 'Aquamarine'));
-		var idSuffix = (doctype=="strict"? '_strict': (doctype=="loose"? '_loose': '_quirks')) + (rtl? '_rtl' : '');
-		dojo.style(container, "cssText", "display:inline;border:1px ridge gray;padding:0px;margin:0px;background-color:"+color+";text-align:"+(rtl?"right;":"left;"));
-		container.appendChild(document.createTextNode(text));
-		var iframe = document.createElement('iframe');
-		iframe.setAttribute('src', iframeSrc);
-		iframe.setAttribute('frameBorder', "0");
-		iframe.setAttribute('scrolling', "auto");
-		iframe.setAttribute('allowTransparency', "true");
-		iframe.setAttribute('id', id + idSuffix);
-		iframe.setAttribute('name', id + idSuffix);
-		iframe.className = className;
-		dojo.style(iframe, "cssText", "visibility:hidden;display:block;border:2px solid "+color+";background-color:transparent;margin:0px;padding:3px;"+style);
-		container.appendChild(iframe);
-		srcNode.appendChild(container);
-		var src = iframe.getAttribute("src");
-		if(!src || src.indexOf("javascript") == -1){
-			// set it again if it didn't stick the first time: esp. older Opera and WebKit
-			setTimeout(function(){ iframe.setAttribute('src', iframeSrc); }, 0);
-		}
-	}
-	var testIframes = dojo.query('DIV[type="testIframe"]');
-	count = testIframes.length * 4;
-	for(var i=0; i < testIframes.length; i++){
-		var srcNode = testIframes[i];
-		var content = srcNode.innerHTML || '';
-		var id = srcNode.id || "";
-		var style = srcNode.getAttribute('style') || "";
-		var className = srcNode.getAttribute('class') || srcNode.className || "";
-		if(typeof style == "object"){
-			style = style.cssText || "";
-		}
-		srcNode.innerHTML = "";
-		srcNode.removeAttribute('style');
-		srcNode.className = "";
-
-		makeIframe("strict", false);
-		makeIframe("quirks", false);
-		makeIframe("loose", true);
-		makeIframe("quirks", true);
-	}
-</script>
 </body>
 </html>
diff --git a/window.js b/window.js
index f891eaf..9b8b2be 100644
--- a/window.js
+++ b/window.js
@@ -38,54 +38,88 @@ dojo.window.get = function(doc){
 
 dojo.window.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
 	// summary:
-	//		Scroll the passed node into view, if it is not already.
-	
-	// don't rely on node.scrollIntoView working just because the function is there
+	//		Scroll the passed node into view using minimal movement, if it is not already.
+
+	// Don't rely on node.scrollIntoView working just because the function is there since
+	// it forces the node to the page's bottom or top (and left or right in IE) without consideration for the minimal movement.
+	// WebKit's node.scrollIntoViewIfNeeded doesn't work either for inner scrollbars in right-to-left mode
+	// and when there's a fixed position scrollable element
+
+	node = dojo.byId(node);
+	var body, doc = node.ownerDocument || dojo.doc;
+
+	// has() functions but without has() support
+	if(!("rtl_adjust_position_for_verticalScrollBar" in dojo.window)){
+		body = dojo.body();
+		var	scrollable = dojo.create('div', {
+				style: {overflow:'scroll', overflowX:'visible', direction:'rtl', visibility:'hidden', position:'absolute', left:'0', top:'0', width:'64px', height:'64px'}
+			}, body, "last"),
+			div = dojo.create('div', {
+				style: {overflow:'hidden', direction:'ltr'}
+			}, scrollable, "last");
+		dojo.window.rtl_adjust_position_for_verticalScrollBar = dojo.position(div).x != 0;
+		scrollable.removeChild(div);
+		body.removeChild(scrollable);
+	}
+
+	if(!("position_fixed_support" in dojo.window)){
+		// IE6, IE7+quirks, and some older mobile browsers don't support position:fixed
+		body = dojo.body();
+		var	outer = dojo.create('span', {
+				style: {visibility:'hidden', position:'fixed', left:'1px', top:'1px'}
+			}, body, "last"),
+			inner = dojo.create('span', {
+				style: {position:'fixed', left:'0', top:'0'}
+			}, outer, "last");
+		dojo.window.position_fixed_support = dojo.position(inner).x != dojo.position(outer).x;
+		outer.removeChild(inner);
+		body.removeChild(outer);
+	}
 
 	try{ // catch unexpected/unrecreatable errors (#7808) since we can recover using a semi-acceptable native method
-		node = dojo.byId(node);
-		var doc = node.ownerDocument || dojo.doc,
-			body = doc.body || dojo.body(),
-			html = doc.documentElement || body.parentNode,
-			isIE = dojo.isIE, isWK = dojo.isWebKit;
+		body = doc.body || doc.getElementsByTagName("body")[0];
+		var	html = doc.documentElement || body.parentNode,
+			isIE = dojo.isIE,
+			isWK = dojo.isWebKit;
 		// if an untested browser, then use the native method
-		if((!(dojo.isMoz || isIE || isWK || dojo.isOpera) || node == body || node == html) && (typeof node.scrollIntoView != "undefined")){
+		if(node == body || node == html){ return; }
+		if(!(dojo.isMozilla || isIE || isWK || dojo.isOpera) && ("scrollIntoView" in node)){
 			node.scrollIntoView(false); // short-circuit to native if possible
 			return;
 		}
-		var backCompat = doc.compatMode == 'BackCompat',
-			clientAreaRoot = (isIE >= 9 && "frameElement" in node.ownerDocument.parentWindow)
-				? ((html.clientHeight > 0 && html.clientWidth > 0 && (body.clientHeight == 0 || body.clientWidth == 0 || body.clientHeight > html.clientHeight || body.clientWidth > html.clientWidth)) ? html : body)
-				: (backCompat ? body : html),
-			scrollRoot = isWK ? body : clientAreaRoot,
-			rootWidth = clientAreaRoot.clientWidth,
-			rootHeight = clientAreaRoot.clientHeight,
-			rtl = !dojo._isBodyLtr(),
+		var	backCompat = doc.compatMode == 'BackCompat',
+			rootWidth = Math.min(body.clientWidth || html.clientWidth, html.clientWidth || body.clientWidth),
+			rootHeight = Math.min(body.clientHeight || html.clientHeight, html.clientHeight || body.clientHeight),
+			scrollRoot = (isWK || backCompat) ? body : html,
 			nodePos = pos || dojo.position(node),
 			el = node.parentNode,
 			isFixed = function(el){
-				return ((isIE <= 6 || (isIE && backCompat))? false : (dojo.style(el, 'position').toLowerCase() == "fixed"));
+				return (isIE <= 6 || (isIE == 7 && backCompat))
+					? false
+					: (dojo.window.position_fixed_support && (dojo.style(el, 'position').toLowerCase() == "fixed"));
 			};
 		if(isFixed(node)){ return; } // nothing to do
-
 		while(el){
 			if(el == body){ el = scrollRoot; }
-			var elPos = dojo.position(el),
-				fixedPos = isFixed(el);
-	
+			var	elPos = dojo.position(el),
+				fixedPos = isFixed(el),
+				rtl = dojo.getComputedStyle(el).direction.toLowerCase() == "rtl";
+
 			if(el == scrollRoot){
 				elPos.w = rootWidth; elPos.h = rootHeight;
 				if(scrollRoot == html && isIE && rtl){ elPos.x += scrollRoot.offsetWidth-elPos.w; } // IE workaround where scrollbar causes negative x
-				if(elPos.x < 0 || !isIE){ elPos.x = 0; } // IE can have values > 0
-				if(elPos.y < 0 || !isIE){ elPos.y = 0; }
+				if(elPos.x < 0 || !isIE || isIE >= 9){ elPos.x = 0; } // older IE can have values > 0
+				if(elPos.y < 0 || !isIE || isIE >= 9){ elPos.y = 0; }
 			}else{
 				var pb = dojo._getPadBorderExtents(el);
 				elPos.w -= pb.w; elPos.h -= pb.h; elPos.x += pb.l; elPos.y += pb.t;
 				var clientSize = el.clientWidth,
 					scrollBarSize = elPos.w - clientSize;
 				if(clientSize > 0 && scrollBarSize > 0){
+					if(rtl && dojo.window.rtl_adjust_position_for_verticalScrollBar){
+						elPos.x += scrollBarSize;
+					}
 					elPos.w = clientSize;
-					elPos.x += (rtl && (isIE || el.clientLeft > pb.l/*Chrome*/)) ? scrollBarSize : 0;
 				}
 				clientSize = el.clientHeight;
 				scrollBarSize = elPos.h - clientSize;
@@ -108,21 +142,26 @@ dojo.window.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
 				}
 			}
 			// calculate overflow in all 4 directions
-			var l = nodePos.x - elPos.x, // beyond left: < 0
-				t = nodePos.y - Math.max(elPos.y, 0), // beyond top: < 0
+			var	l = nodePos.x - elPos.x, // beyond left: < 0
+//						t = nodePos.y - Math.max(elPos.y, 0), // beyond top: < 0
+				t = nodePos.y - elPos.y, // beyond top: < 0
 				r = l + nodePos.w - elPos.w, // beyond right: > 0
 				bot = t + nodePos.h - elPos.h; // beyond bottom: > 0
-			if(r * l > 0){
-				var s = Math[l < 0? "max" : "min"](l, r);
+			var s, old;
+			if(r * l > 0 && (!!el.scrollLeft || el == scrollRoot || el.scrollWidth > el.offsetHeight)){
+				s = Math[l < 0? "max" : "min"](l, r);
 				if(rtl && ((isIE == 8 && !backCompat) || isIE >= 9)){ s = -s; }
-				nodePos.x += el.scrollLeft;
+				old = el.scrollLeft;
 				el.scrollLeft += s;
-				nodePos.x -= el.scrollLeft;
+				s = el.scrollLeft - old;
+				nodePos.x -= s;
 			}
-			if(bot * t > 0){
-				nodePos.y += el.scrollTop;
-				el.scrollTop += Math[t < 0? "max" : "min"](t, bot);
-				nodePos.y -= el.scrollTop;
+			if(bot * t > 0 && (!!el.scrollTop || el == scrollRoot || el.scrollHeight > el.offsetHeight)){
+				s = Math.ceil(Math[t < 0? "max" : "min"](t, bot));
+				old = el.scrollTop;
+				el.scrollTop += s;
+				s = el.scrollTop - old;
+				nodePos.y -= s;
 			}
 			el = (el != scrollRoot) && !fixedPos && el.parentNode;
 		}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/dojo.git



More information about the Pkg-javascript-commits mailing list