Skip to content

Instantly share code, notes, and snippets.

@Kaleidea
Last active November 10, 2021 07:43
Show Gist options
  • Save Kaleidea/6643f6b9733f4756dfc96a2d20dfef31 to your computer and use it in GitHub Desktop.
Save Kaleidea/6643f6b9733f4756dfc96a2d20dfef31 to your computer and use it in GitHub Desktop.
<search> element with <form> functionality - draft implementation patch for Chromium Blink
From 01acb284c72128f7681a502757165048fe29bb7d Mon Sep 17 00:00:00 2001
From: Kaleidea
Subject: [PATCH 1/2] [wip-draft] Add <search> element as an alias for <form>: `interfaceName=HTMLFormElement`
<search> has the same functionality as <form> at this stage.
html_tag_names.json5:
- generates HTMLFormElement constructor wrapper for HTMLElementFactory::createHTMLElement()
HTMLFormElement::create():
- add `const QualifiedName& tag_name` parameter to distinguish between <form> and <search>.
replace_selection_command.cc::IsProhibitedParagraphChild(),
DocumentAllNameCollection::ElementMatches(),
html_collection.cc::NameShouldBeVisibleInDocumentAll(),
HTMLStackItem::IsSpecialNode():
- add <search>
document_statistics_collector.cc::CollectFeatures(),
HTMLTreeBuilder,
AXNodeObject::determineAccessibilityRoleUtil():
- add <search> besides <form>
---
.../renderer/core/dom/document_statistics_collector.cc | 3 ++-
.../core/editing/commands/replace_selection_command.cc | 1 +
.../renderer/core/html/document_all_name_collection.cc | 1 +
.../blink/renderer/core/html/forms/html_form_element.cc | 4 ++--
.../blink/renderer/core/html/forms/html_form_element.h | 2 +-
third_party/blink/renderer/core/html/html_collection.cc | 1 +
.../blink/renderer/core/html/html_tag_names.json5 | 5 +++++
.../blink/renderer/core/html/parser/html_stack_item.h | 1 +
.../blink/renderer/core/html/parser/html_tree_builder.cc | 9 ++++++---
.../renderer/modules/accessibility/ax_node_object.cc | 3 +++
10 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/third_party/blink/renderer/core/dom/document_statistics_collector.cc b/third_party/blink/renderer/core/dom/document_statistics_collector.cc
index 0c15543566..e96f9ab940 100644
--- a/third_party/blink/renderer/core/dom/document_statistics_collector.cc
+++ b/third_party/blink/renderer/core/dom/document_statistics_collector.cc
@@ -121,7 +121,8 @@ void CollectFeatures(Element& root,
features.element_count++;
if (element.HasTagName(html_names::kATag)) {
features.anchor_count++;
- } else if (element.HasTagName(html_names::kFormTag)) {
+ } else if (element.HasTagName(html_names::kFormTag) ||
+ element.HasTagName(html_names::kSearchTag)) {
features.form_count++;
} else if (element.HasTagName(html_names::kInputTag)) {
const auto& input = To<HTMLInputElement>(element);
diff --git a/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc b/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc
index 3c0090fcd3..58b734904e 100644
--- a/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc
+++ b/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc
@@ -703,6 +703,7 @@ static bool IsProhibitedParagraphChild(const AtomicString& name) {
html_names::kPTag.LocalName(),
html_names::kPlaintextTag.LocalName(),
html_names::kPreTag.LocalName(),
+ html_names::kSearchTag.LocalName(),
html_names::kSectionTag.LocalName(),
html_names::kSummaryTag.LocalName(),
html_names::kTableTag.LocalName(),
diff --git a/third_party/blink/renderer/core/html/document_all_name_collection.cc b/third_party/blink/renderer/core/html/document_all_name_collection.cc
index 195714c7a7..207b121640 100644
--- a/third_party/blink/renderer/core/html/document_all_name_collection.cc
+++ b/third_party/blink/renderer/core/html/document_all_name_collection.cc
@@ -33,6 +33,7 @@ bool DocumentAllNameCollection::ElementMatches(const Element& element) const {
element.HasTagName(html_names::kMapTag) ||
element.HasTagName(html_names::kMetaTag) ||
element.HasTagName(html_names::kObjectTag) ||
+ element.HasTagName(html_names::kSearchTag) ||
element.HasTagName(html_names::kSelectTag) ||
element.HasTagName(html_names::kTextareaTag)) {
if (element.GetNameAttribute() == name_)
diff --git a/third_party/blink/renderer/core/html/forms/html_form_element.cc b/third_party/blink/renderer/core/html/forms/html_form_element.cc
index 95e322da5a..379d039eee 100644
--- a/third_party/blink/renderer/core/html/forms/html_form_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_form_element.cc
@@ -90,8 +90,8 @@ bool HasFormInBetween(const Node* root, const Node* descendant) {
} // namespace
-HTMLFormElement::HTMLFormElement(Document& document)
- : HTMLElement(html_names::kFormTag, document),
+HTMLFormElement::HTMLFormElement(const QualifiedName& tag_name, Document& document)
+ : HTMLElement(tag_name, document),
listed_elements_are_dirty_(false),
listed_elements_including_shadow_trees_are_dirty_(false),
image_elements_are_dirty_(false),
diff --git a/third_party/blink/renderer/core/html/forms/html_form_element.h b/third_party/blink/renderer/core/html/forms/html_form_element.h
index 0c149bbd0d..8f7a27c9dd 100644
--- a/third_party/blink/renderer/core/html/forms/html_form_element.h
+++ b/third_party/blink/renderer/core/html/forms/html_form_element.h
@@ -44,7 +44,7 @@ class CORE_EXPORT HTMLFormElement final : public HTMLElement {
DEFINE_WRAPPERTYPEINFO();
public:
- explicit HTMLFormElement(Document&);
+ explicit HTMLFormElement(const QualifiedName& tag_name, Document&);
~HTMLFormElement() override;
void Trace(Visitor*) const override;
diff --git a/third_party/blink/renderer/core/html/html_collection.cc b/third_party/blink/renderer/core/html/html_collection.cc
index d839a92aa4..6ecd9f4da1 100644
--- a/third_party/blink/renderer/core/html/html_collection.cc
+++ b/third_party/blink/renderer/core/html/html_collection.cc
@@ -345,6 +345,7 @@ static inline bool NameShouldBeVisibleInDocumentAll(
element.HasTagName(html_names::kMapTag) ||
element.HasTagName(html_names::kMetaTag) ||
element.HasTagName(html_names::kObjectTag) ||
+ element.HasTagName(html_names::kSearchTag) ||
element.HasTagName(html_names::kSelectTag) ||
element.HasTagName(html_names::kTextareaTag);
}
diff --git a/third_party/blink/renderer/core/html/html_tag_names.json5 b/third_party/blink/renderer/core/html/html_tag_names.json5
index 8961b0a80a..ed8eaf96f4 100644
--- a/third_party/blink/renderer/core/html/html_tag_names.json5
+++ b/third_party/blink/renderer/core/html/html_tag_names.json5
@@ -416,6 +416,11 @@
name: "script",
constructorNeedsCreateElementFlags: true,
},
+ {
+ name: "search",
+ interfaceName: "HTMLFormElement",
+ interfaceHeaderDir: "third_party/blink/renderer/core/html/forms",
+ },
{
name: "section",
interfaceName: "HTMLElement",
diff --git a/third_party/blink/renderer/core/html/parser/html_stack_item.h b/third_party/blink/renderer/core/html/parser/html_stack_item.h
index 9fcf4500e5..8fca84b1bf 100644
--- a/third_party/blink/renderer/core/html/parser/html_stack_item.h
+++ b/third_party/blink/renderer/core/html/parser/html_stack_item.h
@@ -191,6 +191,7 @@ class HTMLStackItem final : public GarbageCollected<HTMLStackItem> {
tag_name == html_names::kPlaintextTag ||
tag_name == html_names::kPreTag ||
tag_name == html_names::kScriptTag ||
+ tag_name == html_names::kSearchTag ||
tag_name == html_names::kSectionTag ||
tag_name == html_names::kSelectTag ||
tag_name == html_names::kStyleTag ||
diff --git a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
index e4293630c1..46fc8e2f40 100644
--- a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
+++ b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
@@ -662,7 +662,8 @@ void HTMLTreeBuilder::ProcessStartTagForInBody(AtomicHTMLToken* token) {
frameset_ok_ = false;
return;
}
- if (token->GetName() == html_names::kFormTag) {
+ if (token->GetName() == html_names::kFormTag ||
+ token->GetName() == html_names::kSearchTag) {
if (tree_.IsFormElementPointerNonNull() && !IsParsingTemplateContents()) {
ParseError(token);
UseCounter::Count(tree_.CurrentNode()->GetDocument(),
@@ -1111,7 +1112,8 @@ void HTMLTreeBuilder::ProcessStartTagForInTable(AtomicHTMLToken* token) {
}
// Fall through to "anything else" case.
}
- if (token->GetName() == html_names::kFormTag) {
+ if (token->GetName() == html_names::kFormTag||
+ token->GetName() == html_names::kSearchTag) {
ParseError(token);
if (tree_.IsFormElementPointerNonNull() && !IsParsingTemplateContents())
return;
@@ -1900,7 +1902,8 @@ void HTMLTreeBuilder::ProcessEndTagForInBody(AtomicHTMLToken* token) {
tree_.OpenElements()->PopUntilPopped(token->GetName());
return;
}
- if (token->GetName() == html_names::kFormTag &&
+ if ((token->GetName() == html_names::kFormTag ||
+ token->GetName() == html_names::kSearchTag) &&
!IsParsingTemplateContents()) {
Element* node = tree_.TakeForm();
if (!node || !tree_.OpenElements()->InScope(node)) {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index ab85a9e82d..8166b3f660 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -1160,6 +1160,9 @@ ax::mojom::blink::Role AXNodeObject::NativeRoleIgnoringAria() const {
}
if (IsA<HTMLFormElement>(*GetNode())) {
+ if (GetNode()->HasTagName(html_names::kSearchTag))
+ return ax::mojom::blink::Role::kSearch;
+
// Only treat <form> as role="form" when it has an accessible name, which
// can only occur when the name is assigned by the author via aria-label,
// aria-labelledby, or title. Otherwise, treat as a <section>.
--
From 3d003a7f2bbf7daa450695176cc48cf016db11d4 Mon Sep 17 00:00:00 2001
From: Kaleidea
Subject: [PATCH 2/2] [wip-draft] Disable <search> element submitImplicitly()
and requestSubmit() when `action` attribute is unset
is_search_form_ == element tag is `search`
is_submit_implicitly_enabled_ == `action` attribute is set or element tag is `form`
---
.../blink/renderer/core/html/forms/html_form_element.cc | 9 +++++++++
.../blink/renderer/core/html/forms/html_form_element.h | 4 ++++
2 files changed, 13 insertions(+)
diff --git a/third_party/blink/renderer/core/html/forms/html_form_element.cc b/third_party/blink/renderer/core/html/forms/html_form_element.cc
index 379d039eee..0cf3cbc5af 100644
--- a/third_party/blink/renderer/core/html/forms/html_form_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_form_element.cc
@@ -92,6 +92,8 @@ bool HasFormInBetween(const Node* root, const Node* descendant) {
HTMLFormElement::HTMLFormElement(const QualifiedName& tag_name, Document& document)
: HTMLElement(tag_name, document),
+ is_search_form_(HasTagName(html_names::kSearchTag)),
+ is_submit_implicitly_enabled_(!is_search_form_),
listed_elements_are_dirty_(false),
listed_elements_including_shadow_trees_are_dirty_(false),
image_elements_are_dirty_(false),
@@ -204,6 +206,8 @@ HTMLElement* HTMLFormElement::item(unsigned index) {
void HTMLFormElement::SubmitImplicitly(const Event& event,
bool from_implicit_submission_trigger) {
+ if (is_search_form_ && !is_submit_implicitly_enabled_)
+ return;
int submission_trigger_count = 0;
bool seen_default_button = false;
for (ListedElement* element : ListedElements()) {
@@ -364,6 +368,9 @@ void HTMLFormElement::requestSubmit(ExceptionState& exception_state) {
// https://html.spec.whatwg.org/multipage/forms.html#dom-form-requestsubmit
void HTMLFormElement::requestSubmit(HTMLElement* submitter,
ExceptionState& exception_state) {
+ // requestSubmit() is enabled if `action` is set or this is a `<form>` element, not `<search>`.
+ if (is_search_form_ && !is_submit_implicitly_enabled_)
+ return;
HTMLFormControlElement* control = nullptr;
// 1. If submitter was given, then:
if (submitter) {
@@ -618,6 +625,8 @@ void HTMLFormElement::ParseAttribute(
const QualifiedName& name = params.name;
if (name == html_names::kActionAttr) {
attributes_.ParseAction(params.new_value);
+ // submitImplicitly() is enabled if `action` is set or this is a `<form>` element, not `<search>`.
+ is_submit_implicitly_enabled_ = !value.IsNull() || !is_search_form_;
LogUpdateAttributeIfIsolatedWorldAndInDocument("form", params);
// If we're not upgrading insecure requests, and the new action attribute is
diff --git a/third_party/blink/renderer/core/html/forms/html_form_element.h b/third_party/blink/renderer/core/html/forms/html_form_element.h
index 8f7a27c9dd..244a525249 100644
--- a/third_party/blink/renderer/core/html/forms/html_form_element.h
+++ b/third_party/blink/renderer/core/html/forms/html_form_element.h
@@ -179,6 +179,10 @@ class CORE_EXPORT HTMLFormElement final : public HTMLElement {
bool in_user_js_submit_event_ = false;
bool is_constructing_entry_list_ = false;
+ bool is_search_form_ : 1;
+ bool is_submit_implicitly_enabled_ : 1;
+ // Alt name: is_implicit_submission_enabled_
+
bool listed_elements_are_dirty_ : 1;
bool listed_elements_including_shadow_trees_are_dirty_ : 1;
bool image_elements_are_dirty_ : 1;
--
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment