diff --git a/Userland/Libraries/LibWeb/DOM/Document.h b/Userland/Libraries/LibWeb/DOM/Document.h index b4e2d5ff67..a356ac563f 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.h +++ b/Userland/Libraries/LibWeb/DOM/Document.h @@ -195,6 +195,7 @@ public: void add_script_to_execute_as_soon_as_possible(Badge, HTML::HTMLScriptElement&); NonnullRefPtrVector take_scripts_to_execute_as_soon_as_possible(Badge); + NonnullRefPtrVector& scripts_to_execute_as_soon_as_possible() { return m_scripts_to_execute_as_soon_as_possible; } QuirksMode mode() const { return m_quirks_mode; } bool in_quirks_mode() const { return m_quirks_mode == QuirksMode::Yes; } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp index 7f49301239..5941782d7c 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp @@ -291,9 +291,8 @@ void HTMLScriptElement::prepare_script() // Fetch a classic script given url, settings object, options, classic script CORS setting, and encoding. auto request = LoadRequest::create_for_url_on_page(url, document().page()); - // FIXME: This load should be made asynchronous and the parser should spin an event loop etc. m_script_filename = url.to_string(); - ResourceLoader::the().load_sync( + ResourceLoader::the().load( request, [this, url](auto data, auto&, auto) { if (data.is_null()) { @@ -310,6 +309,8 @@ void HTMLScriptElement::prepare_script() }, [this](auto&, auto) { m_failed_to_load = true; + dbgln("HONK! Failed to load script, but ready nonetheless."); + script_became_ready(); }); } else if (m_script_type == ScriptType::Module) { // FIXME: -> "module" @@ -374,21 +375,34 @@ void HTMLScriptElement::prepare_script() // Add the element to the end of the list of scripts that will execute in order as soon as possible associated with the element's preparation-time document. m_preparation_time_document->add_script_to_execute_as_soon_as_possible({}, *this); - // FIXME: When the script is ready, run the following steps: + // When the script is ready, run the following steps: + when_the_script_is_ready([this] { + // 1. If the element is not now the first element in the list of scripts + // that will execute in order as soon as possible to which it was added above, + // then mark the element as ready but return without executing the script yet. + if (this != &m_preparation_time_document->scripts_to_execute_as_soon_as_possible().first()) { + m_script_ready = true; + return; + } - // FIXME: 1. If the element is not now the first element in the list of scripts - // that will execute in order as soon as possible to which it was added above, - // then mark the element as ready but return without executing the script yet. + for (;;) { + // 2. Execution: Execute the script block corresponding to the first script element + // in this list of scripts that will execute in order as soon as possible. + m_preparation_time_document->scripts_to_execute_as_soon_as_possible().first().execute_script(); - // FIXME: 2. Execution: Execute the script block corresponding to the first script element - // in this list of scripts that will execute in order as soon as possible. - // - // FIXME: 3. Remove the first element from this list of scripts that will execute in order - // as soon as possible. - // - // FIXME: 4. If this list of scripts that will execute in order as soon as possible is still - // not empty and the first entry has already been marked as ready, then jump back - // to the step labeled execution. + // 3. Remove the first element from this list of scripts that will execute in order + // as soon as possible. + m_preparation_time_document->scripts_to_execute_as_soon_as_possible().take_first(); + + // 4. If this list of scripts that will execute in order as soon as possible is still + // not empty and the first entry has already been marked as ready, then jump back + // to the step labeled execution. + if (!m_preparation_time_document->scripts_to_execute_as_soon_as_possible().is_empty() && m_preparation_time_document->scripts_to_execute_as_soon_as_possible().first().m_script_ready) + continue; + + break; + } + }); } // -> If the script's type is "classic", and the element has a src attribute @@ -399,6 +413,8 @@ void HTMLScriptElement::prepare_script() m_preparation_time_document->add_script_to_execute_as_soon_as_possible({}, *this); // FIXME: When the script is ready, execute the script block and then remove the element // from the set of scripts that will execute as soon as possible. + + TODO(); } // FIXME: -> If the element does not have a src attribute, and the element is "parser-inserted", diff --git a/Userland/Libraries/LibWeb/HTML/Parser/HTMLDocumentParser.cpp b/Userland/Libraries/LibWeb/HTML/Parser/HTMLDocumentParser.cpp index 88e4493257..6503eaaf49 100644 --- a/Userland/Libraries/LibWeb/HTML/Parser/HTMLDocumentParser.cpp +++ b/Userland/Libraries/LibWeb/HTML/Parser/HTMLDocumentParser.cpp @@ -184,8 +184,11 @@ void HTMLDocumentParser::run(const AK::URL& url) m_stack_of_open_elements.pop(); auto scripts_to_execute_when_parsing_has_finished = m_document->take_scripts_to_execute_when_parsing_has_finished({}); + for (auto& script : scripts_to_execute_when_parsing_has_finished) { - // FIXME: Spin the event loop until the script is ready to be parser executed and there's no style sheets blocking scripts. + main_thread_event_loop().spin_until([&] { + return script.is_ready_to_be_parser_executed() && !document().has_a_style_sheet_that_is_blocking_scripts(); + }); script.execute_script(); } @@ -193,12 +196,10 @@ void HTMLDocumentParser::run(const AK::URL& url) content_loaded_event->set_bubbles(true); m_document->dispatch_event(content_loaded_event); - // FIXME: The document parser shouldn't execute these, it should just spin the event loop until the list becomes empty. - // FIXME: Once the set has been added, also spin the event loop until the set becomes empty. - auto scripts_to_execute_as_soon_as_possible = m_document->take_scripts_to_execute_as_soon_as_possible({}); - for (auto& script : scripts_to_execute_as_soon_as_possible) { - script.execute_script(); - } + // 7. Spin the event loop until the set of scripts that will execute as soon as possible and the list of scripts that will execute in order as soon as possible are empty. + main_thread_event_loop().spin_until([&] { + return m_document->scripts_to_execute_as_soon_as_possible().is_empty(); + }); // FIXME: Spin the event loop until there is nothing that delays the load event in the Document.