зеркало из https://github.com/mozilla/gecko-dev.git
Bug 582459 - Reset the focused element when a frame loses document focus; r=mikedeboer,NeilDeakin,hsivonen,jaws
Resetting focus would also clear selection on editable element, so get current selected text before moving focus to findbar to make prefill-with-selection work if the content is loaded in chrome process. Differential Revision: https://phabricator.services.mozilla.com/D89557
This commit is contained in:
Родитель
4b4f627747
Коммит
0fd119dae0
|
@ -109,15 +109,15 @@ add_task(async function test_dialog_focus_trap() {
|
|||
ok(displayElChildSpan.tabIndex === -1, "The tabIndex value for elements with a hardcoded tabIndex attribute should be reset to '-1'.")
|
||||
ok(displayElChildSpan.dataset.oldTabIndex === "0", "Existing tabIndex values should be stored in `dataset.oldTabIndex`.")
|
||||
|
||||
const isActiveElemDialogOrHTML = (elemTagName) => {
|
||||
return (["HTML", "CONFIRMATION-DIALOG"].includes(elemTagName));
|
||||
const isActiveElemDialogOrHTMLorBODY = (elemTagName) => {
|
||||
return (["HTML", "BODY", "CONFIRMATION-DIALOG"].includes(elemTagName));
|
||||
}
|
||||
|
||||
let iterator = 0;
|
||||
while(iterator < 20) {
|
||||
sendKey("TAB");
|
||||
isnot(document.activeElement.id, "display-child", "The display-child element should not gain focus when the dialog is showing");
|
||||
is(isActiveElemDialogOrHTML(document.activeElement.tagName), true, "The confirmation-dialog should always have focus when the dialog is showing");
|
||||
ok(isActiveElemDialogOrHTMLorBODY(document.activeElement.tagName), "The confirmation-dialog should always have focus when the dialog is showing");
|
||||
iterator++;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1626,13 +1626,6 @@ void nsFocusManager::SetFocusInner(Element* aNewContent, int32_t aFlags,
|
|||
}
|
||||
// return if blurring fails or the focus changes during the blur
|
||||
if (focusedBrowsingContext) {
|
||||
// if the focus is being moved to another element in the same document,
|
||||
// or to a descendant, pass the existing window to Blur so that the
|
||||
// current node in the existing window is cleared. If moving to a
|
||||
// window elsewhere, we want to maintain the current node in the
|
||||
// window but still blur it.
|
||||
bool currentIsSameOrAncestor =
|
||||
IsSameOrAncestor(focusedBrowsingContext, newWindow);
|
||||
// find the common ancestor of the currently focused window and the new
|
||||
// window. The ancestor will need to have its currently focused node
|
||||
// cleared once the document has been blurred. Otherwise, we'll be in a
|
||||
|
@ -1650,11 +1643,28 @@ void nsFocusManager::SetFocusInner(Element* aNewContent, int32_t aFlags,
|
|||
commonAncestor = GetCommonAncestor(newWindow, focusedBrowsingContext);
|
||||
}
|
||||
|
||||
if (!Blur(
|
||||
currentIsSameOrAncestor ? focusedBrowsingContext.get() : nullptr,
|
||||
commonAncestor ? commonAncestor.get() : nullptr,
|
||||
focusMovesToDifferentBC, aAdjustWidget, aActionId,
|
||||
elementToFocus)) {
|
||||
bool needToClearFocusedElement = false;
|
||||
if (focusedBrowsingContext->IsChrome()) {
|
||||
// Always reset focused element if focus is currently in chrome window.
|
||||
needToClearFocusedElement = true;
|
||||
} else {
|
||||
// Only reset focused element if focus moves within the same top-level
|
||||
// content window.
|
||||
if (focusedBrowsingContext->Top() == browsingContextToFocus->Top()) {
|
||||
// XXX for the case that we try to focus an
|
||||
// already-focused-remote-frame, we would still send blur and focus
|
||||
// IPC to it, but they will not generate blur or focus event, we don't
|
||||
// want to reset activeElement on the remote frame.
|
||||
needToClearFocusedElement = (focusMovesToDifferentBC ||
|
||||
focusedBrowsingContext->IsInProcess());
|
||||
}
|
||||
}
|
||||
|
||||
if (!Blur(needToClearFocusedElement ? focusedBrowsingContext.get()
|
||||
: nullptr,
|
||||
commonAncestor ? commonAncestor.get() : nullptr,
|
||||
focusMovesToDifferentBC, aAdjustWidget, aActionId,
|
||||
elementToFocus)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -3545,11 +3555,12 @@ nsresult nsFocusManager::DetermineElementToMoveFocus(
|
|||
docShell->TabToTreeOwner(forward, forDocumentNavigation, &tookFocus);
|
||||
// If the tree owner took the focus, blur the current element.
|
||||
if (tookFocus) {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = docShell->GetWindow();
|
||||
if (window->GetFocusedElement() == mFocusedElement) {
|
||||
if (GetFocusedBrowsingContext() &&
|
||||
GetFocusedBrowsingContext()->IsInProcess()) {
|
||||
Blur(GetFocusedBrowsingContext(), nullptr, true, true,
|
||||
GenerateFocusActionId());
|
||||
} else {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = docShell->GetWindow();
|
||||
window->SetFocusedElement(nullptr);
|
||||
}
|
||||
return NS_OK;
|
||||
|
|
|
@ -59,7 +59,6 @@ skip-if = verify
|
|||
[test_bug448602.html]
|
||||
[test_bug450876.html]
|
||||
skip-if = verify
|
||||
fail-if = (xorigin && fission)
|
||||
[test_bug456273.html]
|
||||
[test_bug457672.html]
|
||||
skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
|
||||
|
|
|
@ -31,7 +31,7 @@ function doTest() {
|
|||
is(document.activeElement, document.getElementById('a'), "link should have focus");
|
||||
is(document.hasFocus(), true, "document should be focused");
|
||||
synthesizeKey("KEY_Tab");
|
||||
is(document.activeElement, document.getElementById('a'), "body element should be focused");
|
||||
is(document.activeElement, document.body, "body element should be focused");
|
||||
is(document.hasFocus(), false, "document should not be focused");
|
||||
|
||||
SimpleTest.finish();
|
||||
|
|
|
@ -1448,8 +1448,7 @@ function doFrameSwitchingTests()
|
|||
[framed.contentDocument, "blur", null, null, window, null],
|
||||
[framed.contentWindow, "blur", null, null, window, null],
|
||||
[frameb.contentDocument, "focus", null, frameb.contentWindow, window, frameb],
|
||||
[frameb.contentWindow, "focus", null, frameb.contentWindow, window, frameb],
|
||||
[inputb, "focus", inputb, frameb.contentWindow, window, frameb]];
|
||||
[frameb.contentWindow, "focus", null, frameb.contentWindow, window, frameb]];
|
||||
fm.focusedWindow = frameb.contentWindow;
|
||||
ok(gEventMatched && gExpectedEvents.length == 0, "frame switch using focusedWindow");
|
||||
|
||||
|
@ -1461,8 +1460,7 @@ function doFrameSwitchingTests()
|
|||
|
||||
// focus a sibling frame by setting focusedWindow when no element is focused in that frame
|
||||
gEventMatched = true;
|
||||
gExpectedEvents = [[inputb, "blur", null, frameb.contentWindow, window, frameb],
|
||||
[frameb.contentDocument, "blur", null, null, window, null],
|
||||
gExpectedEvents = [[frameb.contentDocument, "blur", null, null, window, null],
|
||||
[frameb.contentWindow, "blur", null, null, window, null],
|
||||
[framec.contentDocument, "focus", null, framec.contentWindow, window, framea],
|
||||
[framec.contentWindow, "focus", null, framec.contentWindow, window, framea]];
|
||||
|
|
|
@ -53,5 +53,5 @@ needs-focus == semitransparent-decoration-line.html semitransparent-decoration-l
|
|||
fuzzy-if(OSX,0-1,0-6) fuzzy-if(Android,0-188,0-39) needs-focus == writing-mode.html writing-mode-ref.html
|
||||
needs-focus == 1478604.html 1478604-ref.html
|
||||
|
||||
needs-focus != disabled-1.html disabled-1-notref.html
|
||||
needs-focus == disabled-1.html disabled-1-notref.html
|
||||
needs-focus != disabled-2.html disabled-2-notref.html
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>iframe activeElement after focusing out iframe</title>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script>
|
||||
function waitForEvent(target, event, checkFn) {
|
||||
return new Promise(resolve => {
|
||||
target.addEventListener(event, e => {
|
||||
if (checkFn && !checkFn(e)) {
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
}, { once: true });
|
||||
});
|
||||
}
|
||||
|
||||
function focusTopLevel(w) {
|
||||
w.postMessage("focus", "*");
|
||||
}
|
||||
|
||||
async function getLog(w) {
|
||||
let log = "";
|
||||
step_timeout(function() {
|
||||
w.postMessage("getlog", "*");
|
||||
}, 0);
|
||||
await waitForEvent(window, "message", (e) => {
|
||||
log = e.data;
|
||||
return true;
|
||||
});
|
||||
return log;
|
||||
}
|
||||
|
||||
async function runTest(t, url) {
|
||||
let w = window.open(url);
|
||||
t.add_cleanup(() => { w.close(); });
|
||||
await waitForEvent(window, "message", e => e.data === "ready");
|
||||
focusTopLevel(w);
|
||||
assert_equals(await getLog(w), 'outerlog:willfocusinput,windowfocus,didfocusinput,innerlog:willfocusinput,windowfocus,didfocusinput,activeElement:INPUT,windowblur,activeElement:BODY,');
|
||||
}
|
||||
|
||||
promise_test(async t => {
|
||||
await runTest(t, "support/iframe-activeelement-after-focusing-out-different-site-iframes-outer.sub.html");
|
||||
}, "Check iframe activeElement after focusing out different site iframe");
|
||||
|
||||
promise_test(async t => {
|
||||
await runTest(t, "support/iframe-activeelement-after-focusing-out-same-site-iframes-outer.html");
|
||||
}, "Check iframe activeElement after focusing out same site iframe");
|
||||
|
||||
</script>
|
|
@ -0,0 +1,34 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>iframe active element after focusing out different site iframes outer</title>
|
||||
<input></input></br>
|
||||
<iframe src="http://{{hosts[alt][www]}}:{{ports[http][0]}}/focus/support/iframe-activeelement-after-focusing-out-iframes-inner.html"></iframe>
|
||||
<script>
|
||||
let outerlog = "outerlog:";
|
||||
|
||||
let input = document.querySelector("input");
|
||||
let iframe = document.querySelector("iframe");
|
||||
window.onmessage = function(e) {
|
||||
if (e.data == "ready") {
|
||||
opener.postMessage("ready", "*");
|
||||
} else if (e.data == "focus") {
|
||||
outerlog += "willfocusinput,";
|
||||
input.focus();
|
||||
outerlog += "didfocusinput,";
|
||||
} else if (e.data == "getlog") {
|
||||
iframe.contentWindow.postMessage("getlog", "*");
|
||||
} else {
|
||||
opener.postMessage(outerlog + e.data, "*");
|
||||
}
|
||||
};
|
||||
|
||||
window.onload = function() {
|
||||
window.onfocus = function() {
|
||||
outerlog += "windowfocus,";
|
||||
};
|
||||
|
||||
window.onblur = function() {
|
||||
outerlog += "windowblur,";
|
||||
};
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>iframe active element inner document</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Inner</h1><br>
|
||||
<input></input>
|
||||
<script>
|
||||
let innerlog = "innerlog:";
|
||||
|
||||
window.onmessage = function(e) {
|
||||
if (e.data == "getlog") {
|
||||
parent.postMessage(innerlog, "*");
|
||||
}
|
||||
};
|
||||
|
||||
window.onfocus = function() {
|
||||
innerlog += "windowfocus,";
|
||||
};
|
||||
|
||||
window.onblur = function() {
|
||||
innerlog += "windowblur,";
|
||||
innerlog += "activeElement:" + document.activeElement.tagName + ",";
|
||||
};
|
||||
|
||||
let input = document.querySelector("input");
|
||||
window.onload = function() {
|
||||
innerlog += "willfocusinput,";
|
||||
input.focus();
|
||||
innerlog += "didfocusinput,";
|
||||
innerlog += "activeElement:" + document.activeElement.tagName + ",";
|
||||
parent.postMessage("ready", "*");
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,34 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>iframe active element after focusing out same site iframes outer</title>
|
||||
<input></input></br>
|
||||
<iframe src="iframe-activeelement-after-focusing-out-iframes-inner.html"></iframe>
|
||||
<script>
|
||||
let outerlog = "outerlog:";
|
||||
|
||||
let input = document.querySelector("input");
|
||||
let iframe = document.querySelector("iframe");
|
||||
window.onmessage = function(e) {
|
||||
if (e.data == "ready") {
|
||||
opener.postMessage("ready", "*");
|
||||
} else if (e.data == "focus") {
|
||||
outerlog += "willfocusinput,";
|
||||
input.focus();
|
||||
outerlog += "didfocusinput,";
|
||||
} else if (e.data == "getlog") {
|
||||
iframe.contentWindow.postMessage("getlog", "*");
|
||||
} else {
|
||||
opener.postMessage(outerlog + e.data, "*");
|
||||
}
|
||||
};
|
||||
|
||||
window.onload = function() {
|
||||
window.onfocus = function() {
|
||||
outerlog += "windowfocus,";
|
||||
};
|
||||
|
||||
window.onblur = function() {
|
||||
outerlog += "windowblur,";
|
||||
};
|
||||
};
|
||||
</script>
|
|
@ -25,6 +25,7 @@
|
|||
assert_true(e.isTrusted, "blur event is trusted");
|
||||
assert_false(e.bubbles, "blur event doesn't bubble");
|
||||
assert_false(e.cancelable, "blur event is not cancelable");
|
||||
assert_equals(document.activeElement, document.body);
|
||||
});
|
||||
|
||||
i1.focus();
|
||||
|
|
|
@ -1147,6 +1147,8 @@
|
|||
}
|
||||
|
||||
if (this.prefillWithSelection && userWantsPrefill) {
|
||||
this.browser.finder.getInitialSelection();
|
||||
|
||||
// NB: We have to focus this._findField here so tests that send
|
||||
// key events can open and close the find bar synchronously.
|
||||
this._findField.focus();
|
||||
|
@ -1157,7 +1159,6 @@
|
|||
// jumbled up queries.
|
||||
this._findField.select();
|
||||
|
||||
this.browser.finder.getInitialSelection();
|
||||
return startFindPromise;
|
||||
}
|
||||
|
||||
|
|
|
@ -374,8 +374,8 @@ Finder.prototype = {
|
|||
},
|
||||
|
||||
getInitialSelection() {
|
||||
let initialSelection = this.getActiveSelectionText().selectedText;
|
||||
this._getWindow().setTimeout(() => {
|
||||
let initialSelection = this.getActiveSelectionText().selectedText;
|
||||
for (let l of this._listeners) {
|
||||
try {
|
||||
l.onCurrentSelection(initialSelection, true);
|
||||
|
|
Загрузка…
Ссылка в новой задаче