mirror of
https://github.com/lexmount/moli.git
synced 2026-10-30 16:07:24 +00:00
fix(parser): preserve fragment context form submission state
This commit is contained in:
@@ -3970,6 +3970,45 @@ fn parser_stream_marks_only_eof_unclosed_form_controls_as_submission_blocking()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn live_fragment_parser_preserves_the_contexts_submission_blocking_state() {
|
||||
for (tag_name, html) in [("select", "<option>value</option>"), ("textarea", "value")] {
|
||||
for blocked in [false, true] {
|
||||
let url = Url::parse("https://fragment.test/").expect("test url");
|
||||
let mut dom_host = DomHost::from_dom(NativeDom::new_html(url.clone()));
|
||||
let document = dom_host.document_handle();
|
||||
let context = dom_host.create_element(tag_name);
|
||||
dom_host.set_blocks_form_submission(context, blocked);
|
||||
let fragment = dom_host.create_document_fragment();
|
||||
let mut effects = DomMutationEffects::default();
|
||||
let mut collector = TestMutationEffectCollector {
|
||||
host: &mut dom_host,
|
||||
effects: &mut effects,
|
||||
panic_on_mutation: false,
|
||||
};
|
||||
crate::HtmlParser::with_scripting_enabled(true).parse_fragment_into_live_dom(
|
||||
url,
|
||||
fragment,
|
||||
document,
|
||||
context,
|
||||
"http://www.w3.org/1999/xhtml",
|
||||
tag_name,
|
||||
html,
|
||||
&mut collector,
|
||||
false,
|
||||
);
|
||||
assert_eq!(
|
||||
dom_host
|
||||
.node(context)
|
||||
.and_then(Node::as_element)
|
||||
.is_some_and(|element| element.blocks_form_submission()),
|
||||
blocked,
|
||||
"fragment parsing must preserve {tag_name}'s pre-existing EOF state"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parser_stream_async_prefetch_uses_shared_script_type_classification() {
|
||||
let html = concat!(
|
||||
|
||||
@@ -47,6 +47,7 @@ enum TokenizerPause {
|
||||
|
||||
struct EmbedderPausingTreeBuilder {
|
||||
inner: TreeBuilder<ParseHandle, DocumentSink>,
|
||||
fragment_context: Option<NativeNodeId>,
|
||||
// Retain a callback's Break until html5ever accepts a pause result. This is
|
||||
// an undelivered notification, not a copy of the owner's current run state;
|
||||
// it must survive both later Continue callbacks and input chunk boundaries.
|
||||
@@ -56,6 +57,7 @@ struct EmbedderPausingTreeBuilder {
|
||||
#[derive(Default)]
|
||||
struct OpenFormControlTracer {
|
||||
handles: RefCell<Vec<NativeNodeId>>,
|
||||
fragment_context: Option<NativeNodeId>,
|
||||
}
|
||||
|
||||
impl Tracer for OpenFormControlTracer {
|
||||
@@ -72,6 +74,11 @@ impl Tracer for OpenFormControlTracer {
|
||||
let Some(node_id) = node.dom_node_id() else {
|
||||
return;
|
||||
};
|
||||
// html5ever also traces the fragment context for GC. It is an existing
|
||||
// element, not an unclosed control created by this parser.
|
||||
if Some(node_id) == self.fragment_context {
|
||||
return;
|
||||
}
|
||||
let mut handles = self.handles.borrow_mut();
|
||||
if !handles.contains(&node_id) {
|
||||
handles.push(node_id);
|
||||
@@ -83,6 +90,7 @@ impl EmbedderPausingTreeBuilder {
|
||||
fn new(sink: DocumentSink, opts: TreeBuilderOpts) -> Self {
|
||||
Self {
|
||||
inner: TreeBuilder::new(sink, opts),
|
||||
fragment_context: None,
|
||||
deferred_owner_interruption: Cell::new(false),
|
||||
}
|
||||
}
|
||||
@@ -92,8 +100,10 @@ impl EmbedderPausingTreeBuilder {
|
||||
context_handle: ParseHandle,
|
||||
opts: TreeBuilderOpts,
|
||||
) -> Self {
|
||||
let fragment_context = context_handle.dom_node_id();
|
||||
Self {
|
||||
inner: TreeBuilder::new_for_fragment(sink, context_handle, None, opts),
|
||||
fragment_context,
|
||||
deferred_owner_interruption: Cell::new(false),
|
||||
}
|
||||
}
|
||||
@@ -103,7 +113,10 @@ impl EmbedderPausingTreeBuilder {
|
||||
}
|
||||
|
||||
fn begin_tree_builder_finish(&self) {
|
||||
let tracer = OpenFormControlTracer::default();
|
||||
let tracer = OpenFormControlTracer {
|
||||
fragment_context: self.fragment_context,
|
||||
..OpenFormControlTracer::default()
|
||||
};
|
||||
self.inner.trace_handles(&tracer);
|
||||
self.inner
|
||||
.sink
|
||||
|
||||
Reference in New Issue
Block a user