mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 22:17:45 +00:00
Browser: Use OutOfProcessWebView for the Browser JavaScript console
Instead of building the web DOM by hand, we now load an empty document into an OutOfProcessWebView, and then append things to it by sending little snippets of JavaScript to the host process. :^)
This commit is contained in:
parent
fd922cf92f
commit
fe09f85414
2 changed files with 19 additions and 82 deletions
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Hunter Salyer <thefalsehonesty@gmail.com>
|
||||
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -10,15 +11,8 @@
|
|||
#include <LibGUI/Button.h>
|
||||
#include <LibGUI/TextBox.h>
|
||||
#include <LibGfx/FontDatabase.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/MarkupGenerator.h>
|
||||
#include <LibJS/Parser.h>
|
||||
#include <LibJS/Runtime/Error.h>
|
||||
#include <LibJS/SyntaxHighlighter.h>
|
||||
#include <LibWeb/Bindings/DOMExceptionWrapper.h>
|
||||
#include <LibWeb/DOM/DocumentType.h>
|
||||
#include <LibWeb/DOM/Text.h>
|
||||
#include <LibWeb/DOMTreeModel.h>
|
||||
|
||||
namespace Browser {
|
||||
|
||||
|
@ -27,18 +21,8 @@ ConsoleWidget::ConsoleWidget()
|
|||
set_layout<GUI::VerticalBoxLayout>();
|
||||
set_fill_with_background_color(true);
|
||||
|
||||
auto base_document = Web::DOM::Document::create();
|
||||
base_document->append_child(adopt_ref(*new Web::DOM::DocumentType(base_document)));
|
||||
auto html_element = base_document->create_element("html");
|
||||
base_document->append_child(html_element);
|
||||
auto head_element = base_document->create_element("head");
|
||||
html_element->append_child(head_element);
|
||||
auto body_element = base_document->create_element("body");
|
||||
html_element->append_child(body_element);
|
||||
m_output_container = body_element;
|
||||
|
||||
m_output_view = add<Web::InProcessWebView>();
|
||||
m_output_view->set_document(base_document);
|
||||
m_output_view = add<Web::OutOfProcessWebView>();
|
||||
m_output_view->load("data:text/html,<html></html>");
|
||||
|
||||
auto& bottom_container = add<GUI::Widget>();
|
||||
bottom_container.set_layout<GUI::HorizontalBoxLayout>();
|
||||
|
@ -64,39 +48,6 @@ ConsoleWidget::ConsoleWidget()
|
|||
|
||||
if (on_js_input)
|
||||
on_js_input(js_source);
|
||||
|
||||
// no interpreter being set means we are running in multi-process mode
|
||||
if (!m_interpreter)
|
||||
return;
|
||||
|
||||
auto parser = JS::Parser(JS::Lexer(js_source));
|
||||
auto program = parser.parse_program();
|
||||
|
||||
StringBuilder output_html;
|
||||
if (parser.has_errors()) {
|
||||
auto error = parser.errors()[0];
|
||||
auto hint = error.source_location_hint(js_source);
|
||||
if (!hint.is_empty())
|
||||
output_html.append(String::formatted("<pre>{}</pre>", escape_html_entities(hint)));
|
||||
m_interpreter->vm().throw_exception<JS::SyntaxError>(m_interpreter->global_object(), error.to_string());
|
||||
} else {
|
||||
m_interpreter->run(m_interpreter->global_object(), *program);
|
||||
}
|
||||
|
||||
if (m_interpreter->exception()) {
|
||||
auto* exception = m_interpreter->exception();
|
||||
m_interpreter->vm().clear_exception();
|
||||
output_html.append("Uncaught exception: ");
|
||||
auto error = exception->value();
|
||||
if (error.is_object())
|
||||
output_html.append(JS::MarkupGenerator::html_from_error(error.as_object()));
|
||||
else
|
||||
output_html.append(JS::MarkupGenerator::html_from_value(error));
|
||||
print_html(output_html.string_view());
|
||||
return;
|
||||
}
|
||||
|
||||
print_html(JS::MarkupGenerator::html_from_value(m_interpreter->vm().last_value()));
|
||||
};
|
||||
|
||||
set_focus_proxy(m_input);
|
||||
|
@ -123,18 +74,6 @@ void ConsoleWidget::handle_js_console_output(const String& method, const String&
|
|||
}
|
||||
}
|
||||
|
||||
void ConsoleWidget::set_interpreter(WeakPtr<JS::Interpreter> interpreter)
|
||||
{
|
||||
if (m_interpreter.ptr() == interpreter.ptr())
|
||||
return;
|
||||
|
||||
m_interpreter = interpreter;
|
||||
m_console_client = make<BrowserConsoleClient>(interpreter->global_object().console(), *this);
|
||||
interpreter->global_object().console().set_client(*m_console_client.ptr());
|
||||
|
||||
clear_output();
|
||||
}
|
||||
|
||||
void ConsoleWidget::print_source_line(const StringView& source)
|
||||
{
|
||||
StringBuilder html;
|
||||
|
@ -147,22 +86,25 @@ void ConsoleWidget::print_source_line(const StringView& source)
|
|||
print_html(html.string_view());
|
||||
}
|
||||
|
||||
void ConsoleWidget::print_html(const StringView& line)
|
||||
void ConsoleWidget::print_html(StringView const& line)
|
||||
{
|
||||
auto paragraph = m_output_container->document().create_element("p");
|
||||
paragraph->set_inner_html(line);
|
||||
|
||||
m_output_container->append_child(paragraph);
|
||||
m_output_container->document().invalidate_layout();
|
||||
m_output_container->document().update_layout();
|
||||
|
||||
StringBuilder builder;
|
||||
builder.append(R"~~~(
|
||||
var p = document.createElement("p");
|
||||
p.innerHTML = ")~~~");
|
||||
builder.append_escaped_for_json(line);
|
||||
builder.append(R"~~~("
|
||||
document.body.appendChild(p);
|
||||
)~~~");
|
||||
m_output_view->run_javascript(builder.string_view());
|
||||
m_output_view->scroll_to_bottom();
|
||||
}
|
||||
|
||||
void ConsoleWidget::clear_output()
|
||||
{
|
||||
m_output_container->remove_all_children();
|
||||
m_output_view->update();
|
||||
m_output_view->run_javascript(R"~~~(
|
||||
document.body.innerHTML = "";
|
||||
)~~~");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue