зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1684792, open form validation popup anchored at screen coordinate as datetime picker and select do so that it is positioned correctly in out of process iframes, r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D100803
This commit is contained in:
Родитель
e01e74c71e
Коммит
094e640230
|
@ -154,30 +154,16 @@ class FormValidationChild extends JSWindowActorChild {
|
|||
|
||||
panelData.message = this._validationMessage;
|
||||
|
||||
// Note, this is relative to the browser and needs to be translated
|
||||
// in chrome.
|
||||
panelData.contentRect = BrowserUtils.getElementBoundingRect(aElement);
|
||||
panelData.screenRect = BrowserUtils.getElementBoundingScreenRect(aElement);
|
||||
|
||||
// We want to show the popup at the middle of checkbox and radio buttons
|
||||
// and where the content begin for the other elements.
|
||||
let offset = 0;
|
||||
|
||||
if (
|
||||
aElement.tagName == "INPUT" &&
|
||||
(aElement.type == "radio" || aElement.type == "checkbox")
|
||||
) {
|
||||
panelData.position = "bottomcenter topleft";
|
||||
} else {
|
||||
let win = aElement.ownerGlobal;
|
||||
let style = win.getComputedStyle(aElement);
|
||||
if (style.direction == "rtl") {
|
||||
offset =
|
||||
parseInt(style.paddingRight) + parseInt(style.borderRightWidth);
|
||||
} else {
|
||||
offset = parseInt(style.paddingLeft) + parseInt(style.borderLeftWidth);
|
||||
}
|
||||
let zoomFactor = this.contentWindow.windowUtils.fullZoom;
|
||||
panelData.offset = Math.round(offset * zoomFactor);
|
||||
panelData.position = "after_start";
|
||||
}
|
||||
this.sendAsyncMessage("FormValidation:ShowPopup", panelData);
|
||||
|
|
|
@ -96,9 +96,7 @@ class FormValidationParent extends JSWindowActorParent {
|
|||
*
|
||||
* @aPanelData - Object that contains popup information
|
||||
* aPanelData stucture detail:
|
||||
* contentRect - the bounding client rect of the target element. If
|
||||
* content is remote, this is relative to the browser, otherwise its
|
||||
* relative to the window.
|
||||
* screenRect - the screen rect of the target element.
|
||||
* position - popup positional string constants.
|
||||
* message - the form element validation message text.
|
||||
*/
|
||||
|
@ -112,10 +110,6 @@ class FormValidationParent extends JSWindowActorParent {
|
|||
|
||||
let tabBrowser = window.gBrowser;
|
||||
this._anchor = tabBrowser.selectedBrowser.popupAnchor;
|
||||
this._anchor.style.left = aPanelData.contentRect.left + "px";
|
||||
this._anchor.style.top = aPanelData.contentRect.top + "px";
|
||||
this._anchor.style.width = aPanelData.contentRect.width + "px";
|
||||
this._anchor.style.height = aPanelData.contentRect.height + "px";
|
||||
this._anchor.hidden = false;
|
||||
|
||||
// Display the panel if it isn't already visible.
|
||||
|
@ -129,7 +123,16 @@ class FormValidationParent extends JSWindowActorParent {
|
|||
tabBrowser.selectedBrowser.addEventListener("TextZoomChange", this);
|
||||
|
||||
// Open the popup
|
||||
this._panel.openPopup(this._anchor, aPanelData.position, 0, 0, false);
|
||||
let rect = aPanelData.screenRect;
|
||||
this._panel.openPopupAtScreenRect(
|
||||
aPanelData.position,
|
||||
rect.left,
|
||||
rect.top,
|
||||
rect.width,
|
||||
rect.height,
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,11 +43,22 @@ ok(
|
|||
"The browser should have a popup to show when a form is invalid"
|
||||
);
|
||||
|
||||
function checkPopupShow() {
|
||||
function isWithinHalfPixel(a, b) {
|
||||
return Math.abs(a - b) <= 0.5;
|
||||
}
|
||||
|
||||
function checkPopupShow(anchorRect) {
|
||||
ok(
|
||||
gInvalidFormPopup.state == "showing" || gInvalidFormPopup.state == "open",
|
||||
"[Test " + testId + "] The invalid form popup should be shown"
|
||||
);
|
||||
// Just check the vertical position, as the horizontal position of an
|
||||
// arrow panel will be offset.
|
||||
is(
|
||||
isWithinHalfPixel(gInvalidFormPopup.screenY),
|
||||
isWithinHalfPixel(anchorRect.bottom),
|
||||
"popup top"
|
||||
);
|
||||
}
|
||||
|
||||
function checkPopupHide() {
|
||||
|
@ -95,9 +106,13 @@ async function openNewTab(uri, background) {
|
|||
return browser;
|
||||
}
|
||||
|
||||
async function clickChildElement(browser) {
|
||||
await SpecialPowers.spawn(browser, [], async function() {
|
||||
content.document.getElementById("s").click();
|
||||
function clickChildElement(browser) {
|
||||
return SpecialPowers.spawn(browser, [], async function() {
|
||||
let element = content.document.getElementById("s");
|
||||
element.click();
|
||||
return {
|
||||
bottom: content.mozInnerScreenY + element.getBoundingClientRect().bottom,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -171,10 +186,11 @@ add_task(async function() {
|
|||
gInvalidFormPopup,
|
||||
"popupshown"
|
||||
);
|
||||
await clickChildElement(browser);
|
||||
let anchorRect = await clickChildElement(browser);
|
||||
await popupShownPromise;
|
||||
|
||||
checkPopupShow();
|
||||
checkPopupShow(anchorRect);
|
||||
|
||||
await checkChildFocus(
|
||||
browser,
|
||||
gInvalidFormPopup.firstElementChild.textContent
|
||||
|
@ -199,10 +215,10 @@ add_task(async function() {
|
|||
gInvalidFormPopup,
|
||||
"popupshown"
|
||||
);
|
||||
await clickChildElement(browser);
|
||||
let anchorRect = await clickChildElement(browser);
|
||||
await popupShownPromise;
|
||||
|
||||
checkPopupShow();
|
||||
checkPopupShow(anchorRect);
|
||||
await checkChildFocus(
|
||||
browser,
|
||||
gInvalidFormPopup.firstElementChild.textContent
|
||||
|
@ -227,10 +243,10 @@ add_task(async function() {
|
|||
gInvalidFormPopup,
|
||||
"popupshown"
|
||||
);
|
||||
await clickChildElement(browser);
|
||||
let anchorRect = await clickChildElement(browser);
|
||||
await popupShownPromise;
|
||||
|
||||
checkPopupShow();
|
||||
checkPopupShow(anchorRect);
|
||||
await checkChildFocus(
|
||||
browser,
|
||||
gInvalidFormPopup.firstElementChild.textContent
|
||||
|
@ -262,10 +278,10 @@ add_task(async function() {
|
|||
gInvalidFormPopup,
|
||||
"popupshown"
|
||||
);
|
||||
await clickChildElement(browser);
|
||||
let anchorRect = await clickChildElement(browser);
|
||||
await popupShownPromise;
|
||||
|
||||
checkPopupShow();
|
||||
checkPopupShow(anchorRect);
|
||||
await checkChildFocus(
|
||||
browser,
|
||||
gInvalidFormPopup.firstElementChild.textContent
|
||||
|
@ -274,7 +290,7 @@ add_task(async function() {
|
|||
await new Promise((resolve, reject) => {
|
||||
EventUtils.sendString("a");
|
||||
executeSoon(function() {
|
||||
checkPopupShow();
|
||||
checkPopupShow(anchorRect);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
@ -298,10 +314,10 @@ add_task(async function() {
|
|||
gInvalidFormPopup,
|
||||
"popupshown"
|
||||
);
|
||||
await clickChildElement(browser);
|
||||
let anchorRect = await clickChildElement(browser);
|
||||
await popupShownPromise;
|
||||
|
||||
checkPopupShow();
|
||||
checkPopupShow(anchorRect);
|
||||
await checkChildFocus(
|
||||
browser,
|
||||
gInvalidFormPopup.firstElementChild.textContent
|
||||
|
@ -332,10 +348,10 @@ add_task(async function() {
|
|||
gInvalidFormPopup,
|
||||
"popupshown"
|
||||
);
|
||||
await clickChildElement(browser);
|
||||
let anchorRect = await clickChildElement(browser);
|
||||
await popupShownPromise;
|
||||
|
||||
checkPopupShow();
|
||||
checkPopupShow(anchorRect);
|
||||
await checkChildFocus(
|
||||
browser,
|
||||
gInvalidFormPopup.firstElementChild.textContent
|
||||
|
@ -366,10 +382,10 @@ add_task(async function() {
|
|||
gInvalidFormPopup,
|
||||
"popupshown"
|
||||
);
|
||||
await clickChildElement(browser1);
|
||||
let anchorRect = await clickChildElement(browser1);
|
||||
await popupShownPromise;
|
||||
|
||||
checkPopupShow();
|
||||
checkPopupShow(anchorRect);
|
||||
await checkChildFocus(
|
||||
browser1,
|
||||
gInvalidFormPopup.firstElementChild.textContent
|
||||
|
@ -403,10 +419,10 @@ add_task(async function() {
|
|||
gInvalidFormPopup,
|
||||
"popupshown"
|
||||
);
|
||||
await clickChildElement(browser);
|
||||
let anchorRect = await clickChildElement(browser);
|
||||
await popupShownPromise;
|
||||
|
||||
checkPopupShow();
|
||||
checkPopupShow(anchorRect);
|
||||
await checkChildFocus(
|
||||
browser,
|
||||
gInvalidFormPopup.firstElementChild.textContent
|
||||
|
@ -486,10 +502,10 @@ add_task(async function() {
|
|||
gInvalidFormPopup,
|
||||
"popupshown"
|
||||
);
|
||||
await clickChildElement(browser);
|
||||
let anchorRect = await clickChildElement(browser);
|
||||
await popupShownPromise;
|
||||
|
||||
checkPopupShow();
|
||||
checkPopupShow(anchorRect);
|
||||
await checkChildFocus(
|
||||
browser,
|
||||
gInvalidFormPopup.firstElementChild.textContent
|
||||
|
|
|
@ -30,7 +30,7 @@ add_task(async function test_iframe() {
|
|||
});
|
||||
await popupShownPromise;
|
||||
|
||||
await SpecialPowers.spawn(browser, [], async function() {
|
||||
let anchorBottom = await SpecialPowers.spawn(browser, [], async function() {
|
||||
let childdoc = content.document.getElementsByTagName("iframe")[0]
|
||||
.contentDocument;
|
||||
Assert.equal(
|
||||
|
@ -38,8 +38,22 @@ add_task(async function test_iframe() {
|
|||
childdoc.getElementById("i"),
|
||||
"First invalid element should be focused"
|
||||
);
|
||||
return (
|
||||
childdoc.defaultView.mozInnerScreenY +
|
||||
childdoc.getElementById("i").getBoundingClientRect().bottom
|
||||
);
|
||||
});
|
||||
|
||||
function isWithinHalfPixel(a, b) {
|
||||
return Math.abs(a - b) <= 0.5;
|
||||
}
|
||||
|
||||
is(
|
||||
isWithinHalfPixel(gInvalidFormPopup.screenY),
|
||||
isWithinHalfPixel(anchorBottom),
|
||||
"popup top"
|
||||
);
|
||||
|
||||
ok(
|
||||
gInvalidFormPopup.state == "showing" || gInvalidFormPopup.state == "open",
|
||||
"The invalid form popup should be shown"
|
||||
|
|
Загрузка…
Ссылка в новой задаче