fix(forms): avoid quadratic selectedcontent synchronization

This commit is contained in:
ldm0
2026-09-27 19:28:50 +08:00
parent 57be192c04
commit 86bb5b7f73
3 changed files with 66 additions and 3 deletions
+14 -1
View File
@@ -189,7 +189,20 @@ impl DomHost {
}
pub fn select_selectedcontent_elements(&self, handle: DomHandle) -> Vec<DomHandle> {
self.dom.select_selectedcontent_elements(handle)
if !self.is_html_element_named(handle, "select") {
return Vec::new();
}
self.elements_by_tag_name_ns(
handle,
Some("http://www.w3.org/1999/xhtml"),
"selectedcontent",
false,
)
.into_iter()
.filter(|selectedcontent| {
self.selectedcontent_nearest_ancestor_select(*selectedcontent) == Some(handle)
})
.collect()
}
pub fn option_is_disabled(&self, handle: DomHandle) -> bool {
+41 -1
View File
@@ -1742,9 +1742,11 @@ mod tests {
let body = host.document_body_handle().unwrap();
let select = host.create_element("select");
assert!(host.append_child(body, select));
assert!(host.select_selectedcontent_elements(select).is_empty());
let button = host.create_element("button");
let selectedcontent = host.create_element("selectedcontent");
assert!(host.append_child(body, select));
assert!(host.append_child(select, button));
assert!(host.append_child(button, selectedcontent));
assert_eq!(
@@ -1776,6 +1778,44 @@ mod tests {
host.select_selectedcontent_elements(select),
vec![selectedcontent]
);
assert!(host.remove_child(button, selectedcontent));
assert!(host.select_selectedcontent_elements(select).is_empty());
assert!(host.append_child(button, selectedcontent));
assert_eq!(
host.select_selectedcontent_elements(select),
vec![selectedcontent]
);
}
#[test]
fn selectedcontent_query_index_preserves_detached_subtree_order_and_namespace() {
let mut host = DomHost::from_dom(NativeDom::new_html(test_url()));
let select = host.create_element("select");
assert!(host.select_selectedcontent_elements(select).is_empty());
let first_button = host.create_element("button");
let first = host.create_element("selectedcontent");
let second_button = host.create_element("button");
let second = host.create_element("selectedcontent");
let foreign = host
.create_element_ns(Some("urn:selectedcontent-test"), "selectedcontent")
.expect("foreign selectedcontent element");
assert!(host.append_child(select, first_button));
assert!(host.append_child(first_button, first));
assert!(host.append_child(select, second_button));
assert!(host.append_child(second_button, second));
assert!(host.append_child(select, foreign));
assert_eq!(
host.select_selectedcontent_elements(select),
vec![first, second]
);
assert!(host.insert_before(select, second_button, Some(first_button)));
assert_eq!(
host.select_selectedcontent_elements(select),
vec![second, first]
);
}
#[test]
@@ -260,6 +260,13 @@ impl DocumentRuntime {
let Some(select) = self.dom_host.option_nearest_ancestor_select(option) else {
return false;
};
if self
.dom_host
.select_selectedcontent_elements(select)
.is_empty()
{
return false;
}
if self
.dom_host
.select_selected_option_elements(select)
@@ -406,12 +413,15 @@ impl DocumentRuntime {
return false;
}
let targets = self.dom_host.select_selectedcontent_elements(select);
if targets.is_empty() {
return false;
}
let selected_option = self
.dom_host
.select_selected_option_elements(select)
.first()
.copied();
let targets = self.dom_host.select_selectedcontent_elements(select);
let mut changed = false;
for target in targets {
changed |= self.clone_selected_option_contents_into_selectedcontent(