diff --git a/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp index 01f7caa778..65caedc22c 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp @@ -45,10 +45,11 @@ void HTMLScriptElement::set_non_blocking(Badge, bool non_blocking) // https://html.spec.whatwg.org/multipage/scripting.html#execute-the-script-block void HTMLScriptElement::execute_script() { - // 1. Let document be scriptElement's node document. (NOTE: This is not necessary) + // 1. Let document be scriptElement's node document. + NonnullRefPtr node_document = document(); // 2. If scriptElement's preparation-time document is not equal to document, then return. - if (m_preparation_time_document.ptr() != &document()) { + if (m_preparation_time_document.ptr() != node_document.ptr()) { dbgln("HTMLScriptElement: Refusing to run script because the preparation time document is not the same as the node document."); return; } @@ -63,7 +64,7 @@ void HTMLScriptElement::execute_script() // 4. If scriptElement is from an external file, or the script's type for scriptElement is "module", then increment document's ignore-destructive-writes counter. bool incremented_destructive_writes_counter = false; if (m_from_an_external_file || m_script_type == ScriptType::Module) { - document().increment_ignore_destructive_writes_counter(); + node_document->increment_ignore_destructive_writes_counter(); incremented_destructive_writes_counter = true; } @@ -74,9 +75,9 @@ void HTMLScriptElement::execute_script() auto old_current_script = document().current_script(); // 2. If scriptElement's root is not a shadow root, then set document's currentScript attribute to scriptElement. Otherwise, set it to null. if (!is(root())) - document().set_current_script({}, this); + node_document->set_current_script({}, this); else - document().set_current_script({}, nullptr); + node_document->set_current_script({}, nullptr); if (m_from_an_external_file) dbgln_if(HTML_SCRIPT_DEBUG, "HTMLScriptElement: Running script {}", attribute(HTML::AttributeNames::src)); @@ -86,8 +87,8 @@ void HTMLScriptElement::execute_script() // 3. Run the classic script given by the script's script for scriptElement. verify_cast(*m_script).run(); - // Set document's currentScript attribute to oldCurrentScript. - document().set_current_script({}, old_current_script); + // 4. Set document's currentScript attribute to oldCurrentScript. + node_document->set_current_script({}, old_current_script); } else { // -> "module" // 1. Assert: document's currentScript attribute is null. @@ -99,7 +100,7 @@ void HTMLScriptElement::execute_script() // 6. Decrement the ignore-destructive-writes counter of document, if it was incremented in the earlier step. if (incremented_destructive_writes_counter) - document().decrement_ignore_destructive_writes_counter(); + node_document->decrement_ignore_destructive_writes_counter(); // 7. If scriptElement is from an external file, then fire an event named load at scriptElement. if (m_from_an_external_file) diff --git a/Userland/Libraries/LibWeb/Tests/HTML/document.currentScript.js b/Userland/Libraries/LibWeb/Tests/HTML/document.currentScript.js new file mode 100644 index 0000000000..b26d5a46fb --- /dev/null +++ b/Userland/Libraries/LibWeb/Tests/HTML/document.currentScript.js @@ -0,0 +1,36 @@ +describe("currentScript", () => { + loadLocalPage("/res/html/misc/blank.html"); + + beforeInitialPageLoad(page => { + expect(page.document.currentScript).toBeNull(); + }); + + afterInitialPageLoad(page => { + test("reset to null even if currentScript is adopted into another document", () => { + const script = page.document.createElement("script"); + script.id = "test"; + script.innerText = ` + const newDocument = globalThis.pageObject.document.implementation.createHTMLDocument(); + const thisScript = globalThis.pageObject.document.getElementById("test"); + + // currentScript should stay the same even across adoption. + expect(globalThis.pageObject.document.currentScript).toBe(thisScript); + newDocument.adoptNode(thisScript); + expect(globalThis.pageObject.document.currentScript).toBe(thisScript); + `; + + // currentScript should be null before and after running the script on insertion. + expect(page.document.currentScript).toBeNull(); + expect(script.ownerDocument).toBe(page.document); + + globalThis.pageObject = page; + page.document.body.appendChild(script); + globalThis.pageObject = undefined; + + expect(page.document.currentScript).toBeNull(); + expect(script.ownerDocument).not.toBe(page.document); + }); + }); + + waitForPageToLoad(); +});