зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
2cce1ce974
Коммит
ceee0ec744
|
@ -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>
|
||||
|
Загрузка…
Ссылка в новой задаче