Skip to content

Commit

Permalink
Bug 1871424 - Make input checkbox/radio in link element work again; r…
Browse files Browse the repository at this point in the history
…=vhilla,dom-core,smaug

The root cause of issue is that the link elements have not yet adopted the
activation behavior defined in the specification. The appropriate  behavior/model
for links is still under discussion, whatwg/html#1576.
For now, we aim for making it consistent with other browsers.

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

UltraBlame original commit: ae7ff06eabe7226e2998739a03a0fb63d8e182b7
  • Loading branch information
marco-c committed Feb 1, 2024
1 parent be99c45 commit 28aedc7
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 18 deletions.
25 changes: 19 additions & 6 deletions dom/html/HTMLInputElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4025,12 +4025,25 @@ nsresult HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {



if ((aVisitor.mItemFlags & NS_OUTER_ACTIVATE_EVENT) &&
(mType == FormControlType::InputReset ||
mType == FormControlType::InputSubmit ||
mType == FormControlType::InputImage) &&
mForm) {
aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;



if (aVisitor.mItemFlags & NS_OUTER_ACTIVATE_EVENT) {
switch (mType) {
case FormControlType::InputReset:
case FormControlType::InputSubmit:
case FormControlType::InputImage:
if (mForm) {
aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
}
break;
case FormControlType::InputCheckbox:
case FormControlType::InputRadio:
aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
break;
default:
break;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,6 @@
[When clicking child <LABEL><INPUT type=checkbox></INPUT><SPAN></SPAN></LABEL> of parent <FORM><INPUT type=reset></INPUT></FORM>, only child should be activated.]
expected: FAIL

[When clicking child <INPUT type=checkbox></INPUT> of parent <A></A>, only child should be activated.]
expected: FAIL

[When clicking child <INPUT type=checkbox></INPUT> of parent <AREA></AREA>, only child should be activated.]
expected: FAIL

[When clicking child <INPUT type=radio></INPUT> of parent <A></A>, only child should be activated.]
expected: FAIL

[When clicking child <INPUT type=radio></INPUT> of parent <AREA></AREA>, only child should be activated.]
expected: FAIL

[When clicking child <LABEL><INPUT type=checkbox></INPUT><SPAN></SPAN></LABEL> of parent <FORM><BUTTON type=submit></BUTTON></FORM>, only child should be activated.]
expected: FAIL

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Activation behavior of input</title>
<link rel="help" href="https://dom.spec.whatwg.org/#eventtarget-activation-behavior">
<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch">
<link rel="help" href="https://html.spec.whatwg.org/#the-input-element">
<link rel="help" href="https://github.com/whatwg/html/issues/1568">
<link rel="help" href="https://github.com/whatwg/html/issues/1576">
<link rel="help" href="https://github.com/whatwg/html/issues/10032">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>

<div id=test_container>
<a href="javascript:activated(document.querySelector('a'))" class="target"></a>
<area href="javascript:activated(document.querySelector('area'))" class="target">
</div>

<script>
let activations = [];
function activated(e) {
activations.push(e);
}

function testActivation(inputType, hasFormOwner, followTheParentLink) {
const elements = document.getElementsByClassName("target");
for (const anchor of elements) {
promise_test(async t => {
const input = document.createElement("input");
input.type = inputType;
input.oninput = function (e) {
activated(this);
};

if (hasFormOwner) {
const form = document.createElement("form");
form.onsubmit = function (e) {
activated(this.firstElementChild);
e.preventDefault();
return false;
};
form.onreset = function (e) {
activated(this.firstElementChild);
};
form.appendChild(input);
anchor.appendChild(form);
t.add_cleanup(function() {
form.remove();
activations = [];
});
} else {
anchor.appendChild(input);
t.add_cleanup(function() {
input.remove();
activations = [];
});
}

input.click();

// This is for a/area where JavaScript is executed in a queued task.
await new Promise(resolve => {
t.step_timeout(() => {
t.step_timeout(() => {
// All browser doesn't follow the spec for input button, see
// https://github.com/whatwg/html/issues/1576.
assert_array_equals(activations, [followTheParentLink ? anchor : input]);
if (inputType == "checkbox" || inputType == "radio") {
assert_equals(input.checked, true, "check input.checked");
}
resolve();
}, 0);
}, 0);
});
}, `Click child input ${inputType} ${hasFormOwner ? "with" : "without"} form owner ` +
`of parent ${anchor.tagName}, activation target should be ${followTheParentLink ? anchor.tagName : "input"}`);
}
}

// Click input types without form owner should not follow the parent link.
const TypesWithoutFormOwnerNotFollowParentLink = ["checkbox", "radio"];
for (const type of TypesWithoutFormOwnerNotFollowParentLink) {
testActivation(type, false /* hasFormOwner */, false /* followTheParentLink */);
}

// Click input types without form owner should follow the parent link.
const TypesWithoutFormOwnerFollowParentLink = ["button", "reset", "submit"];
for (const type of TypesWithoutFormOwnerFollowParentLink) {
testActivation(type, false /* hasFormOwner */, true /* followTheParentLink */);
}

// Click input types with form owner should not follow the parent link.
const TypesWithFormOwnerNotFollowParentLink = ["submit", "reset", "checkbox", "radio"];
for (const type of TypesWithFormOwnerNotFollowParentLink) {
testActivation(type, true /* hasFormOwner */, false /* followTheParentLink */);
}

// Click input types with form owner should follow the parent link.
const TypesWithFormOwnerFollowParentLink = ["button"];
for (const type of TypesWithFormOwnerFollowParentLink) {
testActivation(type, true /* hasFormOwner */, true /* followTheParentLink */);
}
</script>

0 comments on commit 28aedc7

Please sign in to comment.