Commit 8df10e67 authored by Mason Freed's avatar Mason Freed Committed by Commit Bot

Fix forms.elements.namedItem for Form Associated Custom Elements

Prior to this CL, if there were multiple form associated custom elements
with the same "name" attribute, the document.forms.elements.namedItem()
API would not contain the custom elements.

Fixed: 1124818
Change-Id: I5f97fbddc6ef9d03432edde7a643c3e01df70e56
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2398953
Commit-Queue: Kent Tamura <tkent@chromium.org>
Reviewed-by: default avatarKent Tamura <tkent@chromium.org>
Auto-Submit: Mason Freed <masonfreed@chromium.org>
Cr-Commit-Position: refs/heads/master@{#806515}
parent 96d76ad2
......@@ -3384,6 +3384,10 @@ ElementInternals& Element::EnsureElementInternals() {
return EnsureElementRareData().EnsureElementInternals(To<HTMLElement>(*this));
}
const ElementInternals* Element::GetElementInternals() const {
return HasRareData() ? GetElementRareData()->GetElementInternals() : nullptr;
}
ShadowRoot* Element::createShadowRoot(ExceptionState& exception_state) {
DCHECK(RuntimeEnabledFeatures::ShadowDOMV0Enabled(GetExecutionContext()));
if (ShadowRoot* root = GetShadowRoot()) {
......
......@@ -828,6 +828,7 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
void SetDidAttachInternals();
bool DidAttachInternals() const;
ElementInternals& EnsureElementInternals();
const ElementInternals* GetElementInternals() const;
bool ContainsFullScreenElement() const {
return HasElementFlag(ElementFlags::kContainsFullScreenElement);
......
......@@ -144,6 +144,9 @@ class ElementRareData : public NodeRareData {
void SetDidAttachInternals() { did_attach_internals_ = true; }
bool DidAttachInternals() const { return did_attach_internals_; }
ElementInternals& EnsureElementInternals(HTMLElement& target);
const ElementInternals* GetElementInternals() const {
return element_internals_;
}
void SetStyleShouldForceLegacyLayout(bool force) {
style_should_force_legacy_layout_ = force;
......
......@@ -27,6 +27,7 @@
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/node_rare_data.h"
#include "third_party/blink/renderer/core/html/custom/element_internals.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/html_image_element.h"
......@@ -92,20 +93,6 @@ bool RadioNodeList::MatchesByIdOrName(const Element& test_element) const {
test_element.GetNameAttribute() == name_;
}
bool RadioNodeList::CheckElementMatchesRadioNodeListFilter(
const Element& test_element) const {
DCHECK(!ShouldOnlyMatchImgElements());
DCHECK(IsA<HTMLObjectElement>(test_element) ||
test_element.IsFormControlElement());
if (IsA<HTMLFormElement>(ownerNode())) {
auto* form_element = To<HTMLElement>(test_element).formOwner();
if (!form_element || form_element != ownerNode())
return false;
}
return MatchesByIdOrName(test_element);
}
bool RadioNodeList::ElementMatches(const Element& element) const {
if (ShouldOnlyMatchImgElements()) {
auto* html_image_element = DynamicTo<HTMLImageElement>(element);
......@@ -117,16 +104,27 @@ bool RadioNodeList::ElementMatches(const Element& element) const {
return MatchesByIdOrName(element);
}
if (!IsA<HTMLObjectElement>(element) && !element.IsFormControlElement())
auto* html_element = DynamicTo<HTMLElement>(element);
bool is_form_associated =
html_element && html_element->IsFormAssociatedCustomElement();
if (!IsA<HTMLObjectElement>(element) && !element.IsFormControlElement() &&
!is_form_associated) {
return false;
}
auto* html_input_element = DynamicTo<HTMLInputElement>(&element);
if (html_input_element &&
html_input_element->type() == input_type_names::kImage)
html_input_element->type() == input_type_names::kImage) {
return false;
}
if (IsA<HTMLFormElement>(ownerNode())) {
auto* form_element = html_element->formOwner();
if (!form_element || form_element != ownerNode())
return false;
}
return CheckElementMatchesRadioNodeListFilter(element);
return MatchesByIdOrName(element);
}
} // namespace blink
......@@ -45,8 +45,6 @@ class RadioNodeList final : public LiveNodeList {
void setValue(const String&);
private:
bool CheckElementMatchesRadioNodeListFilter(const Element&) const;
bool MatchesByIdOrName(const Element&) const;
bool ShouldOnlyMatchImgElements() const {
return GetType() == kRadioImgNodeListType;
......
......@@ -1077,6 +1077,12 @@ void HTMLElement::setDir(const AtomicString& value) {
setAttribute(html_names::kDirAttr, value);
}
HTMLFormElement* HTMLElement::formOwner() const {
if (const auto* internals = GetElementInternals())
return internals->Form();
return nullptr;
}
HTMLFormElement* HTMLElement::FindFormAncestor() const {
return Traversal<HTMLFormElement>::FirstAncestor(*this);
}
......
......@@ -100,7 +100,7 @@ class CORE_EXPORT HTMLElement : public Element {
bool ShouldSerializeEndTag() const;
virtual HTMLFormElement* formOwner() const { return nullptr; }
virtual HTMLFormElement* formOwner() const;
HTMLFormElement* FindFormAncestor() const;
......
<!DOCTYPE html>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
customElements.define('custom-input', class extends HTMLElement {
static get formAssociated() {return true;}
});
</script>
<form>
<custom-input id="custom-1" name="alone"></custom-input>
<custom-input id="custom-2" name="group"></custom-input>
<custom-input id="custom-3" name="group"></custom-input>
</form>
<script>
test(() => {
const formElements = document.forms[0].elements;
assert_equals(formElements['invalid'],undefined);
assert_equals(formElements['alone'],document.getElementById('custom-1'),'Single input should be returned as-is');
assert_true(formElements['group'] instanceof RadioNodeList,'Repeated names should result in RadioNodeList');
const expected = [document.getElementById('custom-2'),
document.getElementById('custom-3')];
assert_array_equals(formElements['group'],expected,'Repeated names should be contained in RadioNodeList, in tree order');
}, 'Form associated custom elements should work with document.forms.elements.namedItem()');
</script>
</body>
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment