Bug 1524893 - Prevent Label and Summary elements from handling click event if clicking on interactive html content. r=smaug

This patch fix label element when
1. clicking on an interactive content in the shadow tree, or
2. clicking on non-interactive content in the shadow tree, but the
   shadow root's parent is interactive.

The fix for summary element is similar to label element.

Differential Revision: https://phabricator.services.mozilla.com/D18791

--HG--
rename : dom/html/test/forms/test_interactive_content_in_label.html => dom/html/test/forms/test_interactive_content_in_summary.html
extra : moz-landing-system : lando
This commit is contained in:
Ting-Yu Lin 2019-02-07 23:23:45 +00:00
Родитель 2cce1ce974
Коммит ceee0ec744
7 изменённых файлов: 146 добавлений и 14 удалений

Просмотреть файл

@ -5033,6 +5033,19 @@ bool nsContentUtils::IsInSameAnonymousTree(const nsINode* aNode,
return aNode->AsContent()->GetBindingParent() == aContent->GetBindingParent();
}
/* static */
bool nsContentUtils::IsInInteractiveHTMLContent(const Element* aElement,
const Element* aStop) {
const Element* element = aElement;
while (element && element != aStop) {
if (element->IsInteractiveHTMLContent(true)) {
return true;
}
element = element->GetFlattenedTreeParentElement();
}
return false;
}
/* static */
void nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling) {
IMEStateManager::OnInstalledMenuKeyboardListener(aInstalling);

Просмотреть файл

@ -1001,6 +1001,15 @@ class nsContentUtils {
static bool IsInSameAnonymousTree(const nsINode* aNode,
const nsIContent* aContent);
/*
* Traverse the parent chain from aElement up to aStop, and return true if
* there's an interactive html content; false otherwise.
*
* Note: This crosses shadow boundaries but not document boundaries.
*/
static bool IsInInteractiveHTMLContent(const Element* aElement,
const Element* aStop);
/**
* Return the nsIXPConnect service.
*/

Просмотреть файл

@ -61,18 +61,6 @@ void HTMLLabelElement::Focus(ErrorResult& aError) {
}
}
static bool InInteractiveHTMLContent(nsIContent* aContent, nsIContent* aStop) {
nsIContent* content = aContent;
while (content && content != aStop) {
if (content->IsElement() &&
content->AsElement()->IsInteractiveHTMLContent(true)) {
return true;
}
content = content->GetParent();
}
return false;
}
nsresult HTMLLabelElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
if (mHandlingEvent ||
@ -85,8 +73,9 @@ nsresult HTMLLabelElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
return NS_OK;
}
nsCOMPtr<nsIContent> target = do_QueryInterface(aVisitor.mEvent->mTarget);
if (InInteractiveHTMLContent(target, this)) {
nsCOMPtr<Element> target = do_QueryInterface(
aVisitor.mEvent->GetOriginalDOMEventTarget());
if (nsContentUtils::IsInInteractiveHTMLContent(target, this)) {
return NS_OK;
}

Просмотреть файл

@ -39,6 +39,11 @@ nsresult HTMLSummaryElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
}
WidgetEvent* const event = aVisitor.mEvent;
nsCOMPtr<Element> target =
do_QueryInterface(event->GetOriginalDOMEventTarget());
if (nsContentUtils::IsInInteractiveHTMLContent(target, this)) {
return NS_OK;
}
if (event->HasMouseEventMessage()) {
WidgetMouseEvent* mouseEvent = event->AsMouseEvent();

Просмотреть файл

@ -78,6 +78,7 @@ skip-if = os == "android" && debug # bug 1397615
[test_input_untrusted_key_events.html]
[test_input_url.html]
[test_interactive_content_in_label.html]
[test_interactive_content_in_summary.html]
[test_label_control_attribute.html]
[test_label_input_controls.html]
[test_max_attribute.html]

Просмотреть файл

@ -33,6 +33,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=229925
<textarea class="yes" cols="1" rows="1"></textarea>
<video class="yes" controls></video>
<!-- Tests related to shadow tree. -->
<div id="root1"> <!-- content will be added by script below. --> </div>
<button><div id="root2"> <!-- content will be added by script below. --> </div></button>
<a class="no">a</a>
<audio class="no"></audio>
<img class="no" src="data:image/png,">
@ -56,6 +60,14 @@ var target = document.getElementById("target");
var yes_nodes = Array.from(document.getElementsByClassName("yes"));
var root1 = document.getElementById("root1");
root1.attachShadow({ mode: "open" }).innerHTML = "<button class=yes>button in shadow tree</button>";
var root2 = document.getElementById("root2");
root2.attachShadow({ mode: "open" }).innerHTML = "<div class=yes>text in shadow tree</div>";
var yes_nodes_in_shadow_tree =
Array.from(root1.shadowRoot.getElementsByClassName("yes")).concat(
Array.from(root2.shadowRoot.getElementsByClassName("yes")));
var no_nodes = Array.from(document.getElementsByClassName("no"));
var target_clicked = false;
@ -70,6 +82,12 @@ for (node of yes_nodes) {
is(target_clicked, false, "mouse click on interactive content " + node.nodeName + " shouldn't dispatch event to label target");
}
for (node of yes_nodes_in_shadow_tree) {
target_clicked = false;
node.click();
is(target_clicked, false, "mouse click on content in shadow tree " + node.nodeName + " shouldn't dispatch event to label target");
}
for (node of no_nodes) {
target_clicked = false;
node.click();

Просмотреть файл

@ -0,0 +1,97 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1524893
-->
<head>
<title>Test for Bug 1524893</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1524893">Mozilla Bug 1524893</a>
<details id="details">
<summary>
<a class="yes" href="#">a</a>
<audio class="yes" controls></audio>
<button class="yes">button</button>
<details class="yes">details</details>
<embed class="yes">embed</embed>
<iframe class="yes" src="data:text/plain," style="width: 16px; height: 16px;"></iframe>
<img class="yes" src="data:image/png," usemap="#map">
<input class="yes" type="text" size="4">
<keygen class="yes">
<label class="yes">label</label>
<object class="yes" usemap="#map">object</object>
<select class="yes"><option>select</option></select>
<textarea class="yes" cols="1" rows="1"></textarea>
<video class="yes" controls></video>
<!-- Tests related to shadow tree. -->
<div id="root1"> <!-- content will be added by script below. --> </div>
<button><div id="root2"> <!-- content will be added by script below. --> </div></button>
<a class="no">a</a>
<audio class="no"></audio>
<img class="no" src="data:image/png,">
<input class="no" type="hidden">
<object class="no">object</object>
<video class="no"></video>
<span class="no" tabindex="1">tabindex</span>
<audio class="no" tabindex="1"></audio>
<img class="no" src="data:image/png," tabindex="1">
<input class="no" type="hidden" tabindex="1">
<object class="no" tabindex="1">object</object>
<video class="no" tabindex="1"></video>
</summary>
<div>This is details</div>
</details>
<script class="testbody" type="text/javascript">
/** Test for Bug 1524893 **/
var details = document.getElementById("details");
var yes_nodes = Array.from(document.getElementsByClassName("yes"));
var root1 = document.getElementById("root1");
root1.attachShadow({ mode: "open" }).innerHTML = "<button class=yes>button in shadow tree</button>";
var root2 = document.getElementById("root2");
root2.attachShadow({ mode: "open" }).innerHTML = "<div class=yes>text in shadow tree</div>";
var yes_nodes_in_shadow_tree =
Array.from(root1.shadowRoot.getElementsByClassName("yes")).concat(
Array.from(root2.shadowRoot.getElementsByClassName("yes")));
var no_nodes = Array.from(document.getElementsByClassName("no"));
var node;
for (node of yes_nodes) {
details.removeAttribute('open');
node.click();
ok(!details.hasAttribute('open'),
"mouse click on interactive content " + node.nodeName + " shouldn't not open details");
}
for (node of yes_nodes_in_shadow_tree) {
details.removeAttribute('open');
node.click();
ok(!details.hasAttribute('open'),
"mouse click on content in shadow tree " + node.nodeName + " shouldn't open details");
}
for (node of no_nodes) {
details.removeAttribute('open');
node.click();
ok(details.hasAttribute('open'),
"mouse click on non interactive content " + node.nodeName + " should open details");
}
</script>
</pre>
</body>
</html>