mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 1322947 - Add support of cancel dialog modal with escape key r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D74937
This commit is contained in:
parent
72693e39fa
commit
727ca5589e
@ -117,6 +117,7 @@
|
||||
#include "mozilla/dom/HTMLAllCollection.h"
|
||||
#include "mozilla/dom/HTMLMetaElement.h"
|
||||
#include "mozilla/dom/HTMLSharedElement.h"
|
||||
#include "mozilla/dom/HTMLDialogElement.h"
|
||||
#include "mozilla/dom/MutationObservers.h"
|
||||
#include "mozilla/dom/Navigator.h"
|
||||
#include "mozilla/dom/Performance.h"
|
||||
@ -12956,6 +12957,18 @@ void Document::SetFullscreenRoot(Document* aRoot) {
|
||||
mFullscreenRoot = do_GetWeakReference(aRoot);
|
||||
}
|
||||
|
||||
void Document::TryCancelDialog() {
|
||||
// Check if the document is blocked by modal dialog
|
||||
for (const nsWeakPtr& weakPtr : Reversed(mTopLayer)) {
|
||||
nsCOMPtr<Element> element(do_QueryReferent(weakPtr));
|
||||
if (HTMLDialogElement* dialog =
|
||||
HTMLDialogElement::FromNodeOrNull(element)) {
|
||||
dialog->QueueCancelDialog();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<Promise> Document::ExitFullscreen(ErrorResult& aRv) {
|
||||
UniquePtr<FullscreenExit> exit = FullscreenExit::Create(this, aRv);
|
||||
RefPtr<Promise> promise = exit->GetPromise();
|
||||
|
@ -1880,6 +1880,9 @@ class Document : public nsINode,
|
||||
// flag.
|
||||
bool SetFullscreenElement(Element* aElement);
|
||||
|
||||
// Cancel the dialog element if the document is blocked by the dialog
|
||||
void TryCancelDialog();
|
||||
|
||||
/**
|
||||
* Called when a frame in a child process has entered fullscreen or when a
|
||||
* fullscreen frame in a child process changes to another origin.
|
||||
|
@ -167,6 +167,31 @@ void HTMLDialogElement::FocusDialog() {
|
||||
}
|
||||
}
|
||||
|
||||
void HTMLDialogElement::QueueCancelDialog() {
|
||||
// queues an element task on the user interaction task source
|
||||
OwnerDoc()
|
||||
->EventTargetFor(TaskCategory::UI)
|
||||
->Dispatch(NewRunnableMethod("HTMLDialogElement::RunCancelDialogSteps",
|
||||
this,
|
||||
&HTMLDialogElement::RunCancelDialogSteps));
|
||||
}
|
||||
|
||||
void HTMLDialogElement::RunCancelDialogSteps() {
|
||||
// 1) Let close be the result of firing an event named cancel at dialog, with
|
||||
// the cancelable attribute initialized to true.
|
||||
bool defaultAction = true;
|
||||
nsContentUtils::DispatchTrustedEvent(
|
||||
OwnerDoc(), this, NS_LITERAL_STRING("cancel"), CanBubble::eNo,
|
||||
Cancelable::eYes, &defaultAction);
|
||||
|
||||
// 2) If close is true and dialog has an open attribute, then close the dialog
|
||||
// with no return value.
|
||||
if (defaultAction) {
|
||||
Optional<nsAString> retValue;
|
||||
Close(retValue);
|
||||
}
|
||||
}
|
||||
|
||||
JSObject* HTMLDialogElement::WrapNode(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) {
|
||||
return HTMLDialogElement_Binding::Wrap(aCx, this, aGivenProto);
|
||||
|
@ -44,6 +44,8 @@ class HTMLDialogElement final : public nsGenericHTMLElement {
|
||||
void ShowModal(ErrorResult& aError);
|
||||
|
||||
bool IsInTopLayer() const;
|
||||
void QueueCancelDialog();
|
||||
void RunCancelDialogSteps();
|
||||
|
||||
nsString mReturnValue;
|
||||
|
||||
|
@ -10,6 +10,7 @@ with Files("**"):
|
||||
DIRS += ['input']
|
||||
|
||||
MOCHITEST_MANIFESTS += [
|
||||
'test/dialog/mochitest.ini',
|
||||
'test/forms/mochitest.ini',
|
||||
'test/mochitest.ini',
|
||||
]
|
||||
|
7
dom/html/test/dialog/mochitest.ini
Normal file
7
dom/html/test/dialog/mochitest.ini
Normal file
@ -0,0 +1,7 @@
|
||||
[DEFAULT]
|
||||
prefs =
|
||||
dom.dialog_element.enabled=true
|
||||
[test_cancelDialogByEscape.html]
|
||||
[test_dialog_cancel_events.html]
|
||||
[test_dialog_cancel_preventDefault.html]
|
||||
[test_dialog_keydown_preventDefault.html]
|
64
dom/html/test/dialog/test_cancelDialogByEscape.html
Normal file
64
dom/html/test/dialog/test_cancelDialogByEscape.html
Normal file
@ -0,0 +1,64 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1322947
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1322947</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body onload="SimpleTest.waitForFocus(runTest)">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1322947"> Test dialog modal is closed by escape key</a>
|
||||
<p id="display"></p>
|
||||
<dialog id="dialog">
|
||||
<p>Hello World</p>
|
||||
</dialog>
|
||||
|
||||
<dialog id="dialogWithAutofocus">
|
||||
<input autofocus/>
|
||||
</dialog>
|
||||
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
/* Make sure we still cancel the dialog even if the input element is focused */
|
||||
function runTestCancelWhenInputFocused() {
|
||||
const dialog = document.getElementById("dialogWithAutofocus");
|
||||
const input = document.querySelector("input");
|
||||
|
||||
dialog.addEventListener("close", function() {
|
||||
ok(dialog.close, "dialog with input autofocused is closed");
|
||||
done();
|
||||
});
|
||||
dialog.showModal();
|
||||
ok(input == document.activeElement, "input element should be focused");
|
||||
|
||||
synthesizeKey("VK_ESCAPE", {}, window);
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
const dialog = document.getElementById("dialog");
|
||||
|
||||
dialog.addEventListener("close", function() {
|
||||
ok(dialog.close, "dialog closed");
|
||||
setTimeout(function(){
|
||||
runTestCancelWhenInputFocused();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
dialog.showModal();
|
||||
synthesizeKey("VK_ESCAPE", {}, window);
|
||||
}
|
||||
|
||||
function done() {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
57
dom/html/test/dialog/test_dialog_cancel_events.html
Normal file
57
dom/html/test/dialog/test_dialog_cancel_events.html
Normal file
@ -0,0 +1,57 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1322947
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1322947</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body onload="runTest()">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1322947">Test cancel event
|
||||
is fired when the dialog is closed by user interaction</a>
|
||||
<p id="display"></p>
|
||||
<dialog>
|
||||
<p>Hello World</p>
|
||||
</dialog>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var hasCancelEventFired = false;
|
||||
var hasCloseEventFired = false;
|
||||
|
||||
function runTest() {
|
||||
const dialog = document.querySelector("dialog");
|
||||
|
||||
dialog.addEventListener("cancel", function(event) {
|
||||
ok(true, "cancel event is fired");
|
||||
ok(event.cancelable, "cancel event should be cancelable");
|
||||
ok(!hasCancelEventFired, "cancel event should only be fired once");
|
||||
ok(!hasCloseEventFired, "close event should be fired after cancel event");
|
||||
hasCancelEventFired = true;
|
||||
});
|
||||
|
||||
dialog.addEventListener("close", function() {
|
||||
ok(true, "close event is fired");
|
||||
ok(!hasCloseEventFired, "close event should only be fired once");
|
||||
ok(hasCancelEventFired, "cancel event should be fired before close event");
|
||||
hasCloseEventFired = true;
|
||||
done();
|
||||
});
|
||||
|
||||
dialog.showModal();
|
||||
synthesizeKey("VK_ESCAPE", {}, window);
|
||||
}
|
||||
|
||||
function done() {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
56
dom/html/test/dialog/test_dialog_cancel_preventDefault.html
Normal file
56
dom/html/test/dialog/test_dialog_cancel_preventDefault.html
Normal file
@ -0,0 +1,56 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1322947
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1322947</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body onload="SimpleTest.waitForFocus(runTest)">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1322947">Test cancel event with preventDefault on cancel event for dialog element</a>
|
||||
<p id="display"></p>
|
||||
<dialog>
|
||||
<p>Hello World</p>
|
||||
</dialog>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var hasCancelEventFired = false;
|
||||
|
||||
function runTest() {
|
||||
const dialog = document.querySelector("dialog");
|
||||
|
||||
const verify = () => {
|
||||
ok(hasCancelEventFired, "cancel is fired");
|
||||
done();
|
||||
}
|
||||
|
||||
dialog.addEventListener("cancel", function(event) {
|
||||
hasCancelEventFired = true;
|
||||
event.preventDefault();
|
||||
setTimeout(function() {
|
||||
verify();
|
||||
}, 0)
|
||||
});
|
||||
|
||||
dialog.addEventListener("close", function() {
|
||||
ok(false, "close event should not be fired");
|
||||
});
|
||||
|
||||
dialog.showModal();
|
||||
synthesizeKey("VK_ESCAPE", {}, window);
|
||||
}
|
||||
|
||||
function done() {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
56
dom/html/test/dialog/test_dialog_keydown_preventDefault.html
Normal file
56
dom/html/test/dialog/test_dialog_keydown_preventDefault.html
Normal file
@ -0,0 +1,56 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1322947
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1322947</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body onload="SimpleTest.waitForFocus(runTest)">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1322947">Test cancel event with preventDefault on keydown event for dialog element</a>
|
||||
<p id="display"></p>
|
||||
<dialog>
|
||||
<p>Hello World</p>
|
||||
</dialog>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var hasCancelEventFired = false;
|
||||
|
||||
function runTest() {
|
||||
const dialog = document.querySelector("dialog");
|
||||
|
||||
const verify = () => {
|
||||
ok(!hasCancelEventFired, "cancel should not be fired");
|
||||
ok(hasKeydownEventFired, "document level keydown event should be fired");
|
||||
done();
|
||||
}
|
||||
|
||||
dialog.addEventListener("cancel", function(event) {
|
||||
hasCancelEventFired = true;
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", function(event) {
|
||||
hasKeydownEventFired = true;
|
||||
event.preventDefault();
|
||||
setTimeout(function() {
|
||||
verify();
|
||||
}, 0);
|
||||
});
|
||||
dialog.showModal();
|
||||
synthesizeKey("VK_ESCAPE", {}, window);
|
||||
}
|
||||
|
||||
function done() {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -8194,6 +8194,12 @@ void PresShell::EventHandler::FinalizeHandlingEvent(WidgetEvent* aEvent) {
|
||||
aEvent->mFlags.mDefaultPreventedByChrome) {
|
||||
mPresShell->mIsLastChromeOnlyEscapeKeyConsumed = true;
|
||||
}
|
||||
if (aEvent->mMessage == eKeyDown &&
|
||||
!aEvent->mFlags.mDefaultPrevented) {
|
||||
if (Document* doc = GetDocument()) {
|
||||
doc->TryCancelDialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (aEvent->mMessage == eKeyDown) {
|
||||
|
Loading…
Reference in New Issue
Block a user