mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-04 05:19:58 +03:00
Ladybird: Port over ConsoleWidget from the SerenityOS Browser
While this adds a fair bit of widget code, we're also increasing code sharing by using the same bits in WebContentClient for interacting with the JS console. That said, we should look for more ways to share code here.
This commit is contained in:
parent
26a7ea0e0f
commit
1298baa9ad
Notes:
sideshowbarker
2024-07-17 03:27:40 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/1298baa9ad Pull-request: https://github.com/SerenityOS/serenity/pull/16583 Reviewed-by: https://github.com/ADKaster Reviewed-by: https://github.com/linusg
@ -50,14 +50,15 @@ find_package(Qt6 REQUIRED COMPONENTS Core Widgets Network)
|
|||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
BrowserWindow.cpp
|
BrowserWindow.cpp
|
||||||
|
ConsoleWidget.cpp
|
||||||
CookieJar.cpp
|
CookieJar.cpp
|
||||||
WebContentView.cpp
|
|
||||||
History.cpp
|
History.cpp
|
||||||
ModelTranslator.cpp
|
ModelTranslator.cpp
|
||||||
Settings.cpp
|
Settings.cpp
|
||||||
SettingsDialog.cpp
|
SettingsDialog.cpp
|
||||||
Tab.cpp
|
Tab.cpp
|
||||||
Utilities.cpp
|
Utilities.cpp
|
||||||
|
WebContentView.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
158
Ladybird/ConsoleWidget.cpp
Normal file
158
Ladybird/ConsoleWidget.cpp
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Hunter Salyer <thefalsehonesty@gmail.com>
|
||||||
|
* Copyright (c) 2021-2022, Andreas Kling <kling@serenityos.org>
|
||||||
|
* Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
|
||||||
|
* Copyright (c) 2022, the SerenityOS developers.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define AK_DONT_REPLACE_STD
|
||||||
|
|
||||||
|
#include "ConsoleWidget.h"
|
||||||
|
#include "Utilities.h"
|
||||||
|
#include <AK/StringBuilder.h>
|
||||||
|
#include <LibJS/MarkupGenerator.h>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
namespace Ladybird {
|
||||||
|
|
||||||
|
ConsoleWidget::ConsoleWidget()
|
||||||
|
{
|
||||||
|
setLayout(new QVBoxLayout);
|
||||||
|
|
||||||
|
m_output_view = new QTextEdit(this);
|
||||||
|
m_output_view->setReadOnly(true);
|
||||||
|
layout()->addWidget(m_output_view);
|
||||||
|
|
||||||
|
if (on_request_messages)
|
||||||
|
on_request_messages(0);
|
||||||
|
|
||||||
|
auto* bottom_container = new QWidget(this);
|
||||||
|
bottom_container->setLayout(new QHBoxLayout);
|
||||||
|
|
||||||
|
layout()->addWidget(bottom_container);
|
||||||
|
|
||||||
|
m_input = new QLineEdit(bottom_container);
|
||||||
|
bottom_container->layout()->addWidget(m_input);
|
||||||
|
|
||||||
|
QObject::connect(m_input, &QLineEdit::returnPressed, [this] {
|
||||||
|
auto js_source = akstring_from_qstring(m_input->text());
|
||||||
|
|
||||||
|
if (js_source.is_whitespace())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_input->clear();
|
||||||
|
|
||||||
|
print_source_line(js_source);
|
||||||
|
|
||||||
|
if (on_js_input)
|
||||||
|
on_js_input(js_source);
|
||||||
|
});
|
||||||
|
|
||||||
|
setFocusProxy(m_input);
|
||||||
|
|
||||||
|
auto* clear_button = new QPushButton(bottom_container);
|
||||||
|
bottom_container->layout()->addWidget(clear_button);
|
||||||
|
clear_button->setFixedSize(22, 22);
|
||||||
|
clear_button->setText("X");
|
||||||
|
clear_button->setToolTip("Clear the console output");
|
||||||
|
QObject::connect(clear_button, &QPushButton::pressed, [this] {
|
||||||
|
clear_output();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_input->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsoleWidget::request_console_messages()
|
||||||
|
{
|
||||||
|
VERIFY(!m_waiting_for_messages);
|
||||||
|
VERIFY(on_request_messages);
|
||||||
|
on_request_messages(m_highest_received_message_index + 1);
|
||||||
|
m_waiting_for_messages = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsoleWidget::notify_about_new_console_message(i32 message_index)
|
||||||
|
{
|
||||||
|
if (message_index <= m_highest_received_message_index) {
|
||||||
|
dbgln("Notified about console message we already have");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (message_index <= m_highest_notified_message_index) {
|
||||||
|
dbgln("Notified about console message we're already aware of");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_highest_notified_message_index = message_index;
|
||||||
|
if (!m_waiting_for_messages)
|
||||||
|
request_console_messages();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsoleWidget::handle_console_messages(i32 start_index, Vector<String> const& message_types, Vector<String> const& messages)
|
||||||
|
{
|
||||||
|
i32 end_index = start_index + message_types.size() - 1;
|
||||||
|
if (end_index <= m_highest_received_message_index) {
|
||||||
|
dbgln("Received old console messages");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < message_types.size(); i++) {
|
||||||
|
auto& type = message_types[i];
|
||||||
|
auto& message = messages[i];
|
||||||
|
|
||||||
|
if (type == "html") {
|
||||||
|
print_html(message);
|
||||||
|
} else if (type == "clear") {
|
||||||
|
clear_output();
|
||||||
|
} else if (type == "group") {
|
||||||
|
// FIXME: Implement.
|
||||||
|
} else if (type == "groupCollapsed") {
|
||||||
|
// FIXME: Implement.
|
||||||
|
} else if (type == "groupEnd") {
|
||||||
|
// FIXME: Implement.
|
||||||
|
} else {
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_highest_received_message_index = end_index;
|
||||||
|
m_waiting_for_messages = false;
|
||||||
|
|
||||||
|
if (m_highest_received_message_index < m_highest_notified_message_index)
|
||||||
|
request_console_messages();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsoleWidget::print_source_line(StringView source)
|
||||||
|
{
|
||||||
|
StringBuilder html;
|
||||||
|
html.append("<span class=\"repl-indicator\">"sv);
|
||||||
|
html.append("> "sv);
|
||||||
|
html.append("</span>"sv);
|
||||||
|
|
||||||
|
html.append(JS::MarkupGenerator::html_from_source(source));
|
||||||
|
|
||||||
|
print_html(html.string_view());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsoleWidget::print_html(StringView line)
|
||||||
|
{
|
||||||
|
m_output_view->append(QString::fromUtf8(line.characters_without_null_termination(), line.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsoleWidget::clear_output()
|
||||||
|
{
|
||||||
|
m_output_view->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsoleWidget::reset()
|
||||||
|
{
|
||||||
|
clear_output();
|
||||||
|
m_highest_notified_message_index = -1;
|
||||||
|
m_highest_received_message_index = -1;
|
||||||
|
m_waiting_for_messages = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
49
Ladybird/ConsoleWidget.h
Normal file
49
Ladybird/ConsoleWidget.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Hunter Salyer <thefalsehonesty@gmail.com>
|
||||||
|
* Copyright (c) 2021-2022, Andreas Kling <kling@serenityos.org>
|
||||||
|
* Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
|
||||||
|
* Copyright (c) 2022, the SerenityOS developers.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Function.h>
|
||||||
|
#include <AK/String.h>
|
||||||
|
#include <AK/Vector.h>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class QLineEdit;
|
||||||
|
class QTextEdit;
|
||||||
|
|
||||||
|
namespace Ladybird {
|
||||||
|
|
||||||
|
class ConsoleWidget final : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ConsoleWidget();
|
||||||
|
virtual ~ConsoleWidget() = default;
|
||||||
|
|
||||||
|
void notify_about_new_console_message(i32 message_index);
|
||||||
|
void handle_console_messages(i32 start_index, Vector<String> const& message_types, Vector<String> const& messages);
|
||||||
|
void print_source_line(StringView);
|
||||||
|
void print_html(StringView);
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
Function<void(String const&)> on_js_input;
|
||||||
|
Function<void(i32)> on_request_messages;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void request_console_messages();
|
||||||
|
void clear_output();
|
||||||
|
|
||||||
|
QTextEdit* m_output_view { nullptr };
|
||||||
|
QLineEdit* m_input { nullptr };
|
||||||
|
|
||||||
|
i32 m_highest_notified_message_index { -1 };
|
||||||
|
i32 m_highest_received_message_index { -1 };
|
||||||
|
bool m_waiting_for_messages { false };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -7,6 +7,7 @@
|
|||||||
#define AK_DONT_REPLACE_STD
|
#define AK_DONT_REPLACE_STD
|
||||||
|
|
||||||
#include "WebContentView.h"
|
#include "WebContentView.h"
|
||||||
|
#include "ConsoleWidget.h"
|
||||||
#include "CookieJar.h"
|
#include "CookieJar.h"
|
||||||
#include "ModelTranslator.h"
|
#include "ModelTranslator.h"
|
||||||
#include "Utilities.h"
|
#include "Utilities.h"
|
||||||
@ -446,46 +447,35 @@ void WebContentView::run_javascript(String const& js_source)
|
|||||||
|
|
||||||
void WebContentView::did_output_js_console_message(i32 message_index)
|
void WebContentView::did_output_js_console_message(i32 message_index)
|
||||||
{
|
{
|
||||||
// FIXME
|
if (m_console_widget)
|
||||||
(void)message_index;
|
m_console_widget->notify_about_new_console_message(message_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContentView::did_get_js_console_messages(i32, Vector<String>, Vector<String> messages)
|
void WebContentView::did_get_js_console_messages(i32 start_index, Vector<String> message_types, Vector<String> messages)
|
||||||
{
|
{
|
||||||
ensure_js_console_widget();
|
if (m_console_widget)
|
||||||
for (auto& message : messages) {
|
m_console_widget->handle_console_messages(start_index, message_types, messages);
|
||||||
m_js_console_output_edit->append(qstring_from_akstring(message).trimmed());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContentView::ensure_js_console_widget()
|
void WebContentView::ensure_js_console_widget()
|
||||||
{
|
{
|
||||||
if (!m_js_console_widget) {
|
if (!m_console_widget) {
|
||||||
m_js_console_widget = new QWidget;
|
m_console_widget = new Ladybird::ConsoleWidget;
|
||||||
m_js_console_widget->setWindowTitle("JS Console");
|
m_console_widget->setWindowTitle("JS Console");
|
||||||
auto* layout = new QVBoxLayout(m_js_console_widget);
|
m_console_widget->resize(640, 480);
|
||||||
m_js_console_widget->setLayout(layout);
|
m_console_widget->on_js_input = [this](auto js_source) {
|
||||||
m_js_console_output_edit = new QTextEdit(this);
|
client().async_js_console_input(js_source);
|
||||||
m_js_console_output_edit->setReadOnly(true);
|
};
|
||||||
m_js_console_input_edit = new QLineEdit(this);
|
m_console_widget->on_request_messages = [this](i32 start_index) {
|
||||||
layout->addWidget(m_js_console_output_edit);
|
client().async_js_console_request_messages(start_index);
|
||||||
layout->addWidget(m_js_console_input_edit);
|
};
|
||||||
m_js_console_widget->resize(640, 480);
|
|
||||||
|
|
||||||
QObject::connect(m_js_console_input_edit, &QLineEdit::returnPressed, [this] {
|
|
||||||
auto code = m_js_console_input_edit->text().trimmed();
|
|
||||||
client().async_js_console_input(akstring_from_qstring(code));
|
|
||||||
m_js_console_input_edit->clear();
|
|
||||||
m_js_console_output_edit->append(QString("> %1").arg(code));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContentView::show_js_console()
|
void WebContentView::show_js_console()
|
||||||
{
|
{
|
||||||
ensure_js_console_widget();
|
ensure_js_console_widget();
|
||||||
m_js_console_widget->show();
|
m_console_widget->show();
|
||||||
m_js_console_input_edit->setFocus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContentView::ensure_inspector_widget()
|
void WebContentView::ensure_inspector_widget()
|
||||||
@ -846,14 +836,14 @@ void WebContentView::notify_server_did_get_dom_node_properties(i32 node_id, Stri
|
|||||||
|
|
||||||
void WebContentView::notify_server_did_output_js_console_message(i32 message_index)
|
void WebContentView::notify_server_did_output_js_console_message(i32 message_index)
|
||||||
{
|
{
|
||||||
if (on_js_console_new_message)
|
if (m_console_widget)
|
||||||
on_js_console_new_message(message_index);
|
m_console_widget->notify_about_new_console_message(message_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContentView::notify_server_did_get_js_console_messages(i32 start_index, Vector<String> const& message_types, Vector<String> const& messages)
|
void WebContentView::notify_server_did_get_js_console_messages(i32 start_index, Vector<String> const& message_types, Vector<String> const& messages)
|
||||||
{
|
{
|
||||||
if (on_get_js_console_messages)
|
if (m_console_widget)
|
||||||
on_get_js_console_messages(start_index, message_types, messages);
|
m_console_widget->handle_console_messages(start_index, message_types, messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContentView::notify_server_did_change_favicon(Gfx::Bitmap const& bitmap)
|
void WebContentView::notify_server_did_change_favicon(Gfx::Bitmap const& bitmap)
|
||||||
|
@ -25,6 +25,10 @@
|
|||||||
class QTextEdit;
|
class QTextEdit;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
|
|
||||||
|
namespace Ladybird {
|
||||||
|
class ConsoleWidget;
|
||||||
|
}
|
||||||
|
|
||||||
namespace WebView {
|
namespace WebView {
|
||||||
class WebContentClient;
|
class WebContentClient;
|
||||||
}
|
}
|
||||||
@ -152,11 +156,9 @@ private:
|
|||||||
qreal m_inverse_pixel_scaling_ratio { 1.0 };
|
qreal m_inverse_pixel_scaling_ratio { 1.0 };
|
||||||
bool m_should_show_line_box_borders { false };
|
bool m_should_show_line_box_borders { false };
|
||||||
|
|
||||||
QPointer<QWidget> m_js_console_widget;
|
|
||||||
QPointer<QWidget> m_inspector_widget;
|
QPointer<QWidget> m_inspector_widget;
|
||||||
|
|
||||||
QTextEdit* m_js_console_output_edit { nullptr };
|
Ladybird::ConsoleWidget* m_console_widget { nullptr };
|
||||||
QLineEdit* m_js_console_input_edit { nullptr };
|
|
||||||
|
|
||||||
Gfx::IntRect m_viewport_rect;
|
Gfx::IntRect m_viewport_rect;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user