mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 724585 - We need a way to scroll a page to center an element if the element is not visible; r=rcampbell
--HG-- extra : rebase_source : 1dd1770cc77eaeed188db07da8a8254475767296
This commit is contained in:
parent
07c3b32056
commit
c5d47eb42c
@ -128,6 +128,9 @@ InsideOutBoxView = {
|
||||
|
||||
var EXPORTED_SYMBOLS = ["InsideOutBox"];
|
||||
|
||||
const Cu = Components.utils;
|
||||
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
|
||||
|
||||
function InsideOutBox(aView, aBox)
|
||||
{
|
||||
this.view = aView;
|
||||
@ -212,7 +215,9 @@ InsideOutBox.prototype =
|
||||
if (makeBoxVisible) {
|
||||
this.openObjectBox(objectBox);
|
||||
if (scrollIntoView) {
|
||||
objectBox.scrollIntoView(true);
|
||||
// We want to center the label of the element, not the whole tag
|
||||
// (which includes all of its children, and is vertically huge).
|
||||
LayoutHelpers.scrollIntoViewIfNeeded(objectBox.firstElementChild);
|
||||
}
|
||||
}
|
||||
return objectBox;
|
||||
|
@ -186,8 +186,7 @@ LayoutHelpers = {
|
||||
* @param integer aY
|
||||
* @returns Node|null the element node found at the given coordinates.
|
||||
*/
|
||||
getElementFromPoint: function LH_elementFromPoint(aDocument, aX, aY)
|
||||
{
|
||||
getElementFromPoint: function LH_elementFromPoint(aDocument, aX, aY) {
|
||||
let node = aDocument.elementFromPoint(aX, aY);
|
||||
if (node && node.contentDocument) {
|
||||
if (node instanceof Ci.nsIDOMHTMLIFrameElement) {
|
||||
@ -214,4 +213,82 @@ LayoutHelpers = {
|
||||
}
|
||||
return node;
|
||||
},
|
||||
|
||||
/**
|
||||
* Scroll the document so that the element "elem" appears in the viewport.
|
||||
*
|
||||
* @param Element elem the element that needs to appear in the viewport.
|
||||
* @param bool centered true if you want it centered, false if you want it to
|
||||
* appear on the top of the viewport. It is true by default, and that is
|
||||
* usually what you want.
|
||||
*/
|
||||
scrollIntoViewIfNeeded:
|
||||
function LH_scrollIntoViewIfNeeded(elem, centered) {
|
||||
// We want to default to centering the element in the page,
|
||||
// so as to keep the context of the element.
|
||||
centered = centered === undefined? true: !!centered;
|
||||
|
||||
let win = elem.ownerDocument.defaultView;
|
||||
let clientRect = elem.getBoundingClientRect();
|
||||
|
||||
// The following are always from the {top, bottom, left, right}
|
||||
// of the viewport, to the {top, …} of the box.
|
||||
// Think of them as geometrical vectors, it helps.
|
||||
// The origin is at the top left.
|
||||
|
||||
let topToBottom = clientRect.bottom;
|
||||
let bottomToTop = clientRect.top - win.innerHeight;
|
||||
let leftToRight = clientRect.right;
|
||||
let rightToLeft = clientRect.left - win.innerWidth;
|
||||
let xAllowed = true; // We allow one translation on the x axis,
|
||||
let yAllowed = true; // and one on the y axis.
|
||||
|
||||
// Whatever `centered` is, the behavior is the same if the box is
|
||||
// (even partially) visible.
|
||||
|
||||
if ((topToBottom > 0 || !centered) && topToBottom <= elem.offsetHeight) {
|
||||
win.scrollBy(0, topToBottom - elem.offsetHeight);
|
||||
yAllowed = false;
|
||||
} else
|
||||
if ((bottomToTop < 0 || !centered) && bottomToTop >= -elem.offsetHeight) {
|
||||
win.scrollBy(0, bottomToTop + elem.offsetHeight);
|
||||
yAllowed = false;
|
||||
}
|
||||
|
||||
if ((leftToRight > 0 || !centered) && leftToRight <= elem.offsetWidth) {
|
||||
if (xAllowed) {
|
||||
win.scrollBy(leftToRight - elem.offsetWidth, 0);
|
||||
xAllowed = false;
|
||||
}
|
||||
} else
|
||||
if ((rightToLeft < 0 || !centered) && rightToLeft >= -elem.offsetWidth) {
|
||||
if (xAllowed) {
|
||||
win.scrollBy(rightToLeft + elem.offsetWidth, 0);
|
||||
xAllowed = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we want it centered, and the box is completely hidden,
|
||||
// then we center it explicitly.
|
||||
|
||||
if (centered) {
|
||||
|
||||
if (yAllowed && (topToBottom <= 0 || bottomToTop >= 0)) {
|
||||
win.scroll(win.scrollX,
|
||||
win.scrollY + clientRect.top
|
||||
- (win.innerHeight - elem.offsetHeight) / 2);
|
||||
}
|
||||
|
||||
if (xAllowed && (leftToRight <= 0 || rightToLeft <= 0)) {
|
||||
win.scroll(win.scrollX + clientRect.left
|
||||
- (win.innerWidth - elem.offsetWidth) / 2,
|
||||
win.scrollY);
|
||||
}
|
||||
}
|
||||
|
||||
if (win.parent !== win) {
|
||||
// We are inside an iframe.
|
||||
LH_scrollIntoViewIfNeeded(win.frameElement, centered);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -20,6 +20,7 @@ _BROWSER_TEST_FILES = \
|
||||
browser_toolbar_basic.js \
|
||||
browser_toolbar_tooltip.js \
|
||||
browser_toolbar_webconsole_errors_count.js \
|
||||
browser_layoutHelpers.js \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
||||
@ -27,6 +28,8 @@ _BROWSER_TEST_PAGES = \
|
||||
browser_templater_basic.html \
|
||||
browser_toolbar_basic.html \
|
||||
browser_toolbar_webconsole_errors_count.html \
|
||||
browser_layoutHelpers.html \
|
||||
browser_layoutHelpers_iframe.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_BROWSER_TEST_FILES)
|
||||
|
25
browser/devtools/shared/test/browser_layoutHelpers.html
Normal file
25
browser/devtools/shared/test/browser_layoutHelpers.html
Normal file
@ -0,0 +1,25 @@
|
||||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title> Layout Helpers </title>
|
||||
|
||||
<style>
|
||||
html {
|
||||
height: 300%;
|
||||
width: 300%;
|
||||
}
|
||||
div#some {
|
||||
position: absolute;
|
||||
background: black;
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
}
|
||||
iframe {
|
||||
position: absolute;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id=some></div>
|
||||
<iframe id=frame src='./browser_layoutHelpers_iframe.html'></iframe>
|
99
browser/devtools/shared/test/browser_layoutHelpers.js
Normal file
99
browser/devtools/shared/test/browser_layoutHelpers.js
Normal file
@ -0,0 +1,99 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that scrollIntoViewIfNeeded works properly.
|
||||
|
||||
let imported = {};
|
||||
Components.utils.import("resource:///modules/devtools/LayoutHelpers.jsm",
|
||||
imported);
|
||||
registerCleanupFunction(function () {
|
||||
imported = {};
|
||||
});
|
||||
|
||||
let LayoutHelpers = imported.LayoutHelpers;
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/shared/test/browser_layoutHelpers.html";
|
||||
|
||||
function test() {
|
||||
addTab(TEST_URI, function(browser, tab) {
|
||||
info("Starting browser_layoutHelpers.js");
|
||||
let doc = browser.contentDocument;
|
||||
runTest(doc.defaultView, doc.getElementById('some'));
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
function runTest(win, some) {
|
||||
some.style.top = win.innerHeight + 'px';
|
||||
some.style.left = win.innerWidth + 'px';
|
||||
// The tests start with a black 2x2 pixels square below bottom right.
|
||||
// Do not resize the window during the tests.
|
||||
|
||||
win.scroll(win.innerWidth / 2, win.innerHeight + 2); // Above the viewport.
|
||||
LayoutHelpers.scrollIntoViewIfNeeded(some);
|
||||
is(win.scrollY, Math.floor(win.innerHeight / 2) + 1,
|
||||
'Element completely hidden above should appear centered.');
|
||||
|
||||
win.scroll(win.innerWidth / 2, win.innerHeight + 1); // On the top edge.
|
||||
LayoutHelpers.scrollIntoViewIfNeeded(some);
|
||||
is(win.scrollY, win.innerHeight,
|
||||
'Element partially visible above should appear above.');
|
||||
|
||||
win.scroll(win.innerWidth / 2, 0); // Just below the viewport.
|
||||
LayoutHelpers.scrollIntoViewIfNeeded(some);
|
||||
is(win.scrollY, Math.floor(win.innerHeight / 2) + 1,
|
||||
'Element completely hidden below should appear centered.');
|
||||
|
||||
win.scroll(win.innerWidth / 2, 1); // On the bottom edge.
|
||||
LayoutHelpers.scrollIntoViewIfNeeded(some);
|
||||
is(win.scrollY, 2,
|
||||
'Element partially visible below should appear below.');
|
||||
|
||||
|
||||
win.scroll(win.innerWidth / 2, win.innerHeight + 2); // Above the viewport.
|
||||
LayoutHelpers.scrollIntoViewIfNeeded(some, false);
|
||||
is(win.scrollY, win.innerHeight,
|
||||
'Element completely hidden above should appear above ' +
|
||||
'if parameter is false.');
|
||||
|
||||
win.scroll(win.innerWidth / 2, win.innerHeight + 1); // On the top edge.
|
||||
LayoutHelpers.scrollIntoViewIfNeeded(some, false);
|
||||
is(win.scrollY, win.innerHeight,
|
||||
'Element partially visible above should appear above ' +
|
||||
'if parameter is false.');
|
||||
|
||||
win.scroll(win.innerWidth / 2, 0); // Below the viewport.
|
||||
LayoutHelpers.scrollIntoViewIfNeeded(some, false);
|
||||
is(win.scrollY, 2,
|
||||
'Element completely hidden below should appear below ' +
|
||||
'if parameter is false.');
|
||||
|
||||
win.scroll(win.innerWidth / 2, 1); // On the bottom edge.
|
||||
LayoutHelpers.scrollIntoViewIfNeeded(some, false);
|
||||
is(win.scrollY, 2,
|
||||
'Element partially visible below should appear below ' +
|
||||
'if parameter is false.');
|
||||
|
||||
// The case of iframes.
|
||||
win.scroll(0, 0);
|
||||
|
||||
let frame = win.document.getElementById('frame');
|
||||
let fwin = frame.contentWindow;
|
||||
|
||||
frame.style.top = win.innerHeight + 'px';
|
||||
frame.style.left = win.innerWidth + 'px';
|
||||
|
||||
fwin.addEventListener('load', function frameLoad() {
|
||||
let some = fwin.document.getElementById('some');
|
||||
LayoutHelpers.scrollIntoViewIfNeeded(some);
|
||||
is(win.scrollX, Math.floor(win.innerWidth / 2) + 20,
|
||||
'Scrolling from an iframe should center the iframe vertically.');
|
||||
is(win.scrollY, Math.floor(win.innerHeight / 2) + 20,
|
||||
'Scrolling from an iframe should center the iframe horizontally.');
|
||||
is(fwin.scrollX, Math.floor(fwin.innerWidth / 2) + 1,
|
||||
'Scrolling from an iframe should center the element vertically.');
|
||||
is(fwin.scrollY, Math.floor(fwin.innerHeight / 2) + 1,
|
||||
'Scrolling from an iframe should center the element horizontally.');
|
||||
}, false);
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title> Layout Helpers </title>
|
||||
|
||||
<style>
|
||||
html {
|
||||
height: 300%;
|
||||
width: 300%;
|
||||
}
|
||||
div#some {
|
||||
position: absolute;
|
||||
background: black;
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id=some></div>
|
||||
|
Loading…
Reference in New Issue
Block a user