LibWeb: Implement <script src> support for synchronous scripts

Scripts loaded in this way will block the parser until they finish
executing. This means that they see the DOM before the whole document
has been fully parsed. This is all normal, of course.

To make this work, I changed the way we notify DOM nodes about tree
insertion. The inserted_into() callbacks are now incrementally invoked
during parse, as each node is appended to its parent.

To accomodate inline scripts and inline style sheets, we now also have
a children_changed() callback which is invoked on any parent when it
has children added/removed.
This commit is contained in:
Andreas Kling 2020-04-03 23:06:09 +02:00
parent 18d45d1082
commit 56ca91b9f8
Notes: sideshowbarker 2024-07-19 07:58:05 +09:00
10 changed files with 69 additions and 27 deletions

View file

@ -30,6 +30,7 @@
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/HTMLScriptElement.h>
#include <LibWeb/DOM/Text.h>
#include <LibWeb/ResourceLoader.h>
namespace Web {
@ -42,17 +43,48 @@ HTMLScriptElement::~HTMLScriptElement()
{
}
void HTMLScriptElement::inserted_into(Node& new_parent)
void HTMLScriptElement::children_changed()
{
HTMLElement::inserted_into(new_parent);
HTMLElement::children_changed();
if (has_attribute("src"))
return;
StringBuilder builder;
for_each_child([&](auto& child) {
if (is<Text>(child))
builder.append(to<Text>(child).text_content());
});
auto source = builder.to_string();
if (source.is_empty())
return;
auto program = JS::Parser(JS::Lexer(source)).parse_program();
document().interpreter().run(*program);
}
void HTMLScriptElement::inserted_into(Node& new_parent)
{
HTMLElement::inserted_into(new_parent);
auto src = attribute("src");
if (src.is_null())
return;
String source;
URL src_url = document().complete_url(src);
ResourceLoader::the().load_sync(src_url, [&](auto& data) {
if (data.is_null()) {
dbg() << "HTMLScriptElement: Failed to load " << src;
return;
}
source = String::copy(data);
});
if (source.is_empty()) {
dbg() << "HTMLScriptElement: No source to parse :(";
return;
}
auto program = JS::Parser(JS::Lexer(source)).parse_program();
document().interpreter().run(*program);
}