Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement form-associated custom elements and their ElementInternals #31980

Merged
merged 11 commits into from Apr 11, 2024

Conversation

cathiechen
Copy link
Contributor

@cathiechen cathiechen commented Apr 2, 2024

Form-associated elements are now working.

Remaining test failures in custom-elements/form-associated/ are:

  • Allow setting default accessibility semantics for custom elements whatwg/html#4658 hasn't made it into the standard yet, and ElementInternals-accessibility is all about that functionality.
  • ElementInternals-setFormValue hits many race conditions with our iframe order of operations. Isolating just the "submit this form with these custom elements, look at the query" part, the payload of each test actually does pass! Running the tests as written, we end up with different tests overwriting each other's elements and getting very confused. One problem is the about:blank double-load-event thing, but fixing that doesn't fix everything.
  • ElementInternals-validation doesn't work because we don't have form validation in general; I've commented the relevant stubs.
  • ElementInternals-form-disabled-callback fails on Mutating the tabindex content attribute isn't changing focusability #25713.

This patch is originally from #25705


pshaughn and others added 2 commits April 2, 2024 19:27
…use the code in Validatable trait. 3. The form associated custom element is not a customized built-in element.
@servo-wpt-sync
Copy link
Collaborator

🤖 Opened new upstream WPT pull request (web-platform-tests/wpt#45471) with upstreamable changes.

@servo-wpt-sync
Copy link
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#45471).

Copy link
Member

@mrobinson mrobinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lot going on here, so I wasn't able to check the logic of everything. I have some comments, but I don't see any glaring issues with this change.

components/script/dom/customelementregistry.rs Outdated Show resolved Hide resolved
components/script/dom/customelementregistry.rs Outdated Show resolved Hide resolved
components/script/dom/customelementregistry.rs Outdated Show resolved Hide resolved
components/script/dom/customelementregistry.rs Outdated Show resolved Hide resolved
components/script/dom/customelementregistry.rs Outdated Show resolved Hide resolved
components/script/dom/htmlformelement.rs Outdated Show resolved Hide resolved
components/script/dom/htmlformelement.rs Outdated Show resolved Hide resolved
components/script/dom/htmlformelement.rs Outdated Show resolved Hide resolved
components/script/dom/htmlformelement.rs Outdated Show resolved Hide resolved
components/script/dom/raredata.rs Outdated Show resolved Hide resolved
@servo-wpt-sync
Copy link
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#45471).

@servo-wpt-sync
Copy link
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#45471).

Copy link
Contributor Author

@cathiechen cathiechen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make "readonly" effective to element with internals.

// or the element has a datalist element ancestor.
!self.as_element().read_write_state() &&
!self.as_element().disabled_state() &&
!is_barred_by_datalist_ancestor(self.target_element.upcast::<Node>())
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The readonly attribute affects "barred from constraint validation"

},
}
}
},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the read_write_state when "readonly" changes.

Copy link
Contributor Author

@cathiechen cathiechen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes to fix the WPT failures.

if definition.form_associated {
element.upcast::<Element>().set_enabled_state(true);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this change to AttachInternals which also check the invalid state.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice cleanup.

// of enabled/disabled/not-form-control and
// becoming a form control is a change.
element.upcast::<Element>().set_enabled_state(true);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this change to AttachInternals which also check the invalid state.

@@ -867,6 +867,7 @@ pub fn upgrade_element(definition: Rc<CustomElementDefinition>, element: &Elemen
// so it doesn't describe this check as an action.)
element.check_disabled_attribute();
element.check_ancestors_disabled_state_for_form_control();
element.check_readonly_attribute();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also check the readonly attribute after upgrade, so that the value of is_instance_validatable will be correct.

@@ -3137,6 +3138,9 @@ impl VirtualMethods for Element {
self.super_type().unwrap().unbind_from_tree(context);

if let Some(f) = self.as_maybe_form_control() {
// TODO: The valid state of ancestors might be wrong if the form control element
// is with a fieldset ancestor, for instance: `<form><fieldset><input>`,
// if `<input>` is unbinded, `<form><fieldset>` should `update_validity()`.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This affects the test case "[Custom control affects :valid :invalid for FORM and FIELDSET]" in ElementInternals-validation.html

return internals.is_invalid();
}
true
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because validatable including the form control elements and elements with internals, it is not easy to check both outside element.rs, so we create functions here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function checks if the form control elements or elements with internals are invalid or not.

}
element.check_readonly_attribute();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems unbind_from_tree won't affect the "readonly" attribute, so maybe we could remove this change.

false
}
});
.any(|element| element.is_invalid(false));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use is_invalid instead, and consider of element with internals.

validatable.is_instance_validatable() &&
!validatable.validity_state().invalid_flags().is_empty()
});
let is_any_invalid = controls.iter().any(|control| control.is_invalid(false));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use is_invalid, and consider element with internals case.

None
if let Some(element) = field.downcast::<Element>() {
if element.is_invalid(true) {
Some(DomRoot::from_ref(element))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, use is_invalid instead.

self.element.set_state(ElementState::INVALID, false);
}
pub fn update_pseudo_classes(&self) {
if self.element.is_instance_validatable() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use is_instance_validatable instead, and handle with the element with internals case.

if definition.form_associated {
element.upcast::<Element>().set_enabled_state(true);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice cleanup.

components/script/dom/customelementregistry.rs Outdated Show resolved Hide resolved
components/script/dom/customelementregistry.rs Outdated Show resolved Hide resolved
components/script/dom/element.rs Outdated Show resolved Hide resolved
components/script/dom/element.rs Outdated Show resolved Hide resolved
components/script/dom/elementinternals.rs Outdated Show resolved Hide resolved
if !bits.is_empty() && !message.iter().any(|m| m.len() > 0) {
// Step 3: If flags contains one or more true values and message is not given or is the empty
// string, then throw a TypeError.
let bits = ValidationFlags::from(flags);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be an into() call. I can try to make this change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, thanks:) Then I'll leave it as it is for now.

@servo-wpt-sync
Copy link
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#45471).

@servo-wpt-sync
Copy link
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#45471).

@mrobinson mrobinson added this pull request to the merge queue Apr 10, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Apr 10, 2024
Copy link
Member

@mrobinson mrobinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that many tests are failing now unfortunately: https://github.com/servo/servo/runs/23680344451

I'm not sure if this was due to changes made during this final review round or before.

}
element.check_readonly_attribute();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice that this was removed, perhaps it was inadvertent?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it intentional, let me take a loot at the failures:)

@servo-wpt-sync
Copy link
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#45471).

@mrobinson mrobinson added this pull request to the merge queue Apr 11, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Apr 11, 2024
@mrobinson
Copy link
Member

Looks like this just needs some expectations updates: https://github.com/servo/servo/runs/23705832258

@cathiechen
Copy link
Contributor Author

Looks like this just needs some expectations updates: https://github.com/servo/servo/runs/23705832258

Yeah, true, will do:)

@cathiechen
Copy link
Contributor Author

Done!

@servo-wpt-sync
Copy link
Collaborator

📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#45471).

@servo-wpt-sync
Copy link
Collaborator

✍ Updated existing upstream WPT pull request (web-platform-tests/wpt#45471) title and body.

@mrobinson mrobinson added this pull request to the merge queue Apr 11, 2024
Merged via the queue into servo:main with commit 4e4a4c0 Apr 11, 2024
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement attachInternals and ElementInternals
4 participants