LibWeb/HTML: Move connectedness check for script post_connection()

Corresponds to:
905384d140

Also import the test added along with that change.
This commit is contained in:
Sam Atkins
2025-11-27 15:57:18 +00:00
parent 5179c57ca0
commit c0b8f47a76
Notes: github-actions[bot] 2025-12-01 11:09:06 +00:00
3 changed files with 67 additions and 14 deletions

View File

@@ -63,7 +63,7 @@ void HTMLScriptElement::attribute_changed(FlyString const& name, Optional<String
} else if (name == HTML::AttributeNames::referrerpolicy) {
m_referrer_policy = ReferrerPolicy::from_string(value.value_or(""_string)).value_or(ReferrerPolicy::ReferrerPolicy::EmptyString);
} else if (name == HTML::AttributeNames::src) {
// https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model:html-element-post-connection-steps-6
// https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model:concept-element-attributes-change-ext
// 1. If namespace is not null, then return.
if (namespace_.has_value())
return;
@@ -73,8 +73,9 @@ void HTMLScriptElement::attribute_changed(FlyString const& name, Optional<String
if (!value.has_value())
return;
// 2. If localName is src, then run the script HTML element post-connection steps, given element.
post_connection();
// 2. If localName is src and element is connected, then run the script HTML element post-connection steps, given element.
if (is_connected())
post_connection();
} else if (name == HTML::AttributeNames::async) {
// https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model:script-force-async
// When an async attribute is added to a script element el, the user agent must set el's force async to false.
@@ -631,27 +632,27 @@ void HTMLScriptElement::prepare_script()
}
}
// https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model:html-element-post-connection-steps-4
// https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model:children-changed-steps
void HTMLScriptElement::children_changed(ChildrenChangedMetadata const* metadata)
{
Base::children_changed(metadata);
// 1. Run the script HTML element post-connection steps, given the script element.
post_connection();
}
// https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model:prepare-the-script-element-5
void HTMLScriptElement::post_connection()
{
// 1. If insertedNode is not connected, then return.
// 1. If the script element is not connected, then return.
if (!is_connected())
return;
// 2. If insertedNode is parser-inserted, then return.
// 2. Run the script HTML element post-connection steps, given the script element.
post_connection();
}
// https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model:html-element-post-connection-steps
void HTMLScriptElement::post_connection()
{
// 1. If insertedNode is parser-inserted, then return.
if (is_parser_inserted())
return;
// 3. Prepare the script element given insertedNode.
// 2. Prepare the script element given insertedNode.
prepare_script();
}

View File

@@ -0,0 +1,7 @@
Harness status: OK
Found 2 tests
2 Pass
Pass A later-inserted script removed by an earlier-inserted script in the same document fragment should not run
Pass A later-inserted script removed by an earlier-inserted script in the same append() call should not run

View File

@@ -0,0 +1,45 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>A later-inserted script removed by an earlier-inserted script does not run</title>
<script src=../../../resources/testharness.js></script>
<script src=../../../resources/testharnessreport.js></script>
<body>
<script>
test(t => {
const fragment = document.createDocumentFragment();
// Global so they can be more easily accessed by the inner script blocks.
window.script1 = fragment.appendChild(document.createElement("script"));
window.script2 = fragment.appendChild(document.createElement("script"));
window.script2Run = false;
t.add_cleanup(() => { window.script2Run = false; });
script1.textContent = `
assert_true(script2.isConnected, 'script2 is connected when script2 runs');
script2.remove();
`;
script2.textContent = "window.script2Run = true;";
document.body.append(fragment);
assert_false(window.script2Run, "script2 did not run");
}, "A later-inserted script removed by an earlier-inserted script in the " +
"same document fragment should not run");
test(t => {
window.script1 = document.createElement("script");
window.script2 = document.createElement("script");
window.script2Run = false;
t.add_cleanup(() => { window.script2Run = false; });
script1.textContent = `
assert_true(script2.isConnected, 'script2 is connected when script2 runs');
script2.remove();
`;
script2.textContent = "window.script2Run = true;";
document.body.append(script1, script2);
assert_false(window.script2Run, "script2 did not run");
}, "A later-inserted script removed by an earlier-inserted script in the " +
"same append() call should not run");
</script>
</body>