mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Implement form-associated custom elements and their ElementInternals (#31980)
* FACEs work, setFormValue test is awful so now has _mozilla backup * 1. Impl Validatable in ElementInternals instead of HTMLElement. 2. Reuse the code in Validatable trait. 3. The form associated custom element is not a customized built-in element. * add some comments * support readonly attribute and complete barred from constraint validation * Addressed the code review comments * Updated the legacy-layout results * Fixed the WPT failures in ElementInternals-validation.html * Addressed the code review comments * Review suggestions * Fixed silly mistakes and update the test result outside elementinternals * update the test results --------- Co-authored-by: Patrick Shaughnessy <pshaughn@comcast.net> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
2eb959a159
commit
4e4a4c0a28
67 changed files with 1641 additions and 619 deletions
|
@ -14,6 +14,7 @@ use crate::dom::bindings::codegen::Bindings::HTMLFieldSetElementBinding::HTMLFie
|
|||
use crate::dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
|
||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::customelementregistry::CallbackReaction;
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::element::{AttributeMutation, Element};
|
||||
use crate::dom::htmlcollection::{CollectionFilter, HTMLCollection};
|
||||
|
@ -24,6 +25,7 @@ use crate::dom::node::{window_from_node, Node, ShadowIncluding};
|
|||
use crate::dom::validation::Validatable;
|
||||
use crate::dom::validitystate::ValidityState;
|
||||
use crate::dom::virtualmethods::VirtualMethods;
|
||||
use crate::script_thread::ScriptThread;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct HTMLFieldSetElement {
|
||||
|
@ -71,14 +73,7 @@ impl HTMLFieldSetElement {
|
|||
.upcast::<Node>()
|
||||
.traverse_preorder(ShadowIncluding::No)
|
||||
.flat_map(DomRoot::downcast::<Element>)
|
||||
.any(|element| {
|
||||
if let Some(validatable) = element.as_maybe_validatable() {
|
||||
validatable.is_instance_validatable() &&
|
||||
!validatable.validity_state().invalid_flags().is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
.any(|element| element.is_invalid(false));
|
||||
|
||||
self.upcast::<Element>()
|
||||
.set_state(ElementState::VALID, !has_invalid_child);
|
||||
|
@ -169,9 +164,9 @@ impl VirtualMethods for HTMLFieldSetElement {
|
|||
AttributeMutation::Removed => false,
|
||||
};
|
||||
let node = self.upcast::<Node>();
|
||||
let el = self.upcast::<Element>();
|
||||
el.set_disabled_state(disabled_state);
|
||||
el.set_enabled_state(!disabled_state);
|
||||
let element = self.upcast::<Element>();
|
||||
element.set_disabled_state(disabled_state);
|
||||
element.set_enabled_state(!disabled_state);
|
||||
let mut found_legend = false;
|
||||
let children = node.children().filter(|node| {
|
||||
if found_legend {
|
||||
|
@ -186,37 +181,64 @@ impl VirtualMethods for HTMLFieldSetElement {
|
|||
let fields = children.flat_map(|child| {
|
||||
child
|
||||
.traverse_preorder(ShadowIncluding::No)
|
||||
.filter(|descendant| {
|
||||
matches!(
|
||||
descendant.type_id(),
|
||||
NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||
HTMLElementTypeId::HTMLButtonElement,
|
||||
)) | NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||
HTMLElementTypeId::HTMLInputElement,
|
||||
)) | NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||
HTMLElementTypeId::HTMLSelectElement,
|
||||
)) | NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||
HTMLElementTypeId::HTMLTextAreaElement,
|
||||
))
|
||||
)
|
||||
.filter(|descendant| match descendant.type_id() {
|
||||
NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||
HTMLElementTypeId::HTMLButtonElement |
|
||||
HTMLElementTypeId::HTMLInputElement |
|
||||
HTMLElementTypeId::HTMLSelectElement |
|
||||
HTMLElementTypeId::HTMLTextAreaElement,
|
||||
)) => true,
|
||||
NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||
HTMLElementTypeId::HTMLElement,
|
||||
)) => descendant
|
||||
.downcast::<HTMLElement>()
|
||||
.unwrap()
|
||||
.is_form_associated_custom_element(),
|
||||
_ => false,
|
||||
})
|
||||
});
|
||||
if disabled_state {
|
||||
for field in fields {
|
||||
let el = field.downcast::<Element>().unwrap();
|
||||
el.set_disabled_state(true);
|
||||
el.set_enabled_state(false);
|
||||
el.update_sequentially_focusable_status();
|
||||
let element = field.downcast::<Element>().unwrap();
|
||||
if element.enabled_state() {
|
||||
element.set_disabled_state(true);
|
||||
element.set_enabled_state(false);
|
||||
if element
|
||||
.downcast::<HTMLElement>()
|
||||
.map_or(false, |h| h.is_form_associated_custom_element())
|
||||
{
|
||||
ScriptThread::enqueue_callback_reaction(
|
||||
element,
|
||||
CallbackReaction::FormDisabled(true),
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
element.update_sequentially_focusable_status();
|
||||
}
|
||||
} else {
|
||||
for field in fields {
|
||||
let el = field.downcast::<Element>().unwrap();
|
||||
el.check_disabled_attribute();
|
||||
el.check_ancestors_disabled_state_for_form_control();
|
||||
el.update_sequentially_focusable_status();
|
||||
let element = field.downcast::<Element>().unwrap();
|
||||
if element.disabled_state() {
|
||||
element.check_disabled_attribute();
|
||||
element.check_ancestors_disabled_state_for_form_control();
|
||||
// Fire callback only if this has actually enabled the custom element
|
||||
if element.enabled_state() &&
|
||||
element
|
||||
.downcast::<HTMLElement>()
|
||||
.map_or(false, |h| h.is_form_associated_custom_element())
|
||||
{
|
||||
ScriptThread::enqueue_callback_reaction(
|
||||
element,
|
||||
CallbackReaction::FormDisabled(false),
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
element.update_sequentially_focusable_status();
|
||||
}
|
||||
}
|
||||
el.update_sequentially_focusable_status();
|
||||
element.update_sequentially_focusable_status();
|
||||
},
|
||||
local_name!("form") => {
|
||||
self.form_attribute_mutated(mutation);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue