Ver código fonte

Ladybird: Add the node properties tabs to the inspector

This now allows you to view the computed and resolved style values,
along with the CSS variables of a node.
MacDue 2 anos atrás
pai
commit
33249c727a

+ 19 - 0
Ladybird/DOMNodeProperties.h

@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2022, MacDue <macdue@dueutil.tech>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/String.h>
+
+namespace Ladybird {
+
+struct DOMNodeProperties {
+    String computed_style_json;
+    String resolved_style_json;
+    String custom_properties_json;
+};
+
+}

+ 59 - 10
Ladybird/InspectorWidget.cpp

@@ -6,9 +6,16 @@
 
 #define AK_DONT_REPLACE_STD
 
-#include "InspectorWidget.h"
 #include <LibWebView/DOMTreeModel.h>
+#include <LibWebView/StylePropertiesModel.h>
+
+#include "InspectorWidget.h"
 #include <QCloseEvent>
+#include <QHeaderView>
+#include <QSplitter>
+#include <QStringList>
+#include <QTabWidget>
+#include <QTableView>
 #include <QTreeView>
 #include <QVBoxLayout>
 
@@ -17,12 +24,15 @@ namespace Ladybird {
 InspectorWidget::InspectorWidget()
 {
     setLayout(new QVBoxLayout);
-    m_tree_view = new QTreeView;
-    m_tree_view->setHeaderHidden(true);
-    m_tree_view->expandToDepth(3);
-    layout()->addWidget(m_tree_view);
-    m_tree_view->setModel(&m_dom_model);
-    QObject::connect(m_tree_view->selectionModel(), &QItemSelectionModel::selectionChanged,
+    auto splitter = new QSplitter(this);
+    layout()->addWidget(splitter);
+    splitter->setOrientation(Qt::Vertical);
+    auto tree_view = new QTreeView;
+    tree_view->setHeaderHidden(true);
+    tree_view->expandToDepth(3);
+    splitter->addWidget(tree_view);
+    tree_view->setModel(&m_dom_model);
+    QObject::connect(tree_view->selectionModel(), &QItemSelectionModel::selectionChanged,
         [this](QItemSelection const& selected, QItemSelection const&) {
             auto indexes = selected.indexes();
             if (indexes.size()) {
@@ -30,16 +40,49 @@ InspectorWidget::InspectorWidget()
                 set_selection(index);
             }
         });
+
+    auto add_table_tab = [&](auto* tab_widget, auto& model, auto name) {
+        auto container = new QWidget;
+        auto table_view = new QTableView;
+        table_view->setModel(&model);
+        container->setLayout(new QVBoxLayout);
+        container->layout()->addWidget(table_view);
+        table_view->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+        table_view->verticalHeader()->setVisible(false);
+        table_view->horizontalHeader()->setVisible(false);
+        tab_widget->addTab(container, name);
+    };
+
+    auto node_tabs = new QTabWidget;
+    add_table_tab(node_tabs, m_computed_style_model, "Computed");
+    add_table_tab(node_tabs, m_resolved_style_model, "Resolved");
+    add_table_tab(node_tabs, m_custom_properties_model, "Variables");
+    splitter->addWidget(node_tabs);
+}
+
+void InspectorWidget::set_dom_json(StringView dom_json)
+{
+    m_dom_model.set_underlying_model(WebView::DOMTreeModel::create(dom_json));
 }
 
 void InspectorWidget::clear_dom_json()
 {
     m_dom_model.set_underlying_model(nullptr);
+    clear_style_json();
 }
 
-void InspectorWidget::set_dom_json(StringView dom_json)
+void InspectorWidget::load_style_json(StringView computed_style_json, StringView resolved_style_json, StringView custom_properties_json)
 {
-    m_dom_model.set_underlying_model(::WebView::DOMTreeModel::create(dom_json));
+    m_computed_style_model.set_underlying_model(WebView::StylePropertiesModel::create(computed_style_json));
+    m_resolved_style_model.set_underlying_model(WebView::StylePropertiesModel::create(resolved_style_json));
+    m_custom_properties_model.set_underlying_model(WebView::StylePropertiesModel::create(custom_properties_json));
+}
+
+void InspectorWidget::clear_style_json()
+{
+    m_computed_style_model.set_underlying_model(nullptr);
+    m_resolved_style_model.set_underlying_model(nullptr);
+    m_custom_properties_model.set_underlying_model(nullptr);
 }
 
 void InspectorWidget::closeEvent(QCloseEvent* event)
@@ -70,7 +113,13 @@ void InspectorWidget::set_selection(GUI::ModelIndex index)
     m_selection = selection;
 
     VERIFY(on_dom_node_inspected);
-    on_dom_node_inspected(m_selection.dom_node_id, m_selection.pseudo_element);
+    auto maybe_inspected_node_properties = on_dom_node_inspected(m_selection.dom_node_id, m_selection.pseudo_element);
+    if (!maybe_inspected_node_properties.is_error()) {
+        auto properties = maybe_inspected_node_properties.release_value();
+        load_style_json(properties.computed_style_json, properties.resolved_style_json, properties.custom_properties_json);
+    } else {
+        clear_style_json();
+    }
 }
 
 }

+ 11 - 3
Ladybird/InspectorWidget.h

@@ -6,6 +6,7 @@
 
 #pragma once
 
+#include "DOMNodeProperties.h"
 #include "ModelTranslator.h"
 #include <AK/Optional.h>
 #include <AK/StringView.h>
@@ -13,6 +14,7 @@
 #include <QWidget>
 
 class QTreeView;
+class QTableView;
 
 namespace Ladybird {
 
@@ -31,16 +33,22 @@ public:
     void clear_dom_json();
     void set_dom_json(StringView dom_json);
 
-    Function<void(i32, Optional<Web::CSS::Selector::PseudoElement>)> on_dom_node_inspected;
+    void load_style_json(StringView computed_style_json, StringView resolved_style_json, StringView custom_properties_json);
+    void clear_style_json();
+
+    Function<ErrorOr<DOMNodeProperties>(i32, Optional<Web::CSS::Selector::PseudoElement>)> on_dom_node_inspected;
     Function<void()> on_close;
 
 private:
     void set_selection(GUI::ModelIndex);
     void closeEvent(QCloseEvent*) override;
 
-    QTreeView* m_tree_view { nullptr };
-    ModelTranslator m_dom_model {};
     Selection m_selection;
+
+    ModelTranslator m_dom_model {};
+    ModelTranslator m_computed_style_model {};
+    ModelTranslator m_resolved_style_model {};
+    ModelTranslator m_custom_properties_model {};
 };
 
 }

+ 11 - 5
Ladybird/WebContentView.cpp

@@ -511,7 +511,7 @@ void WebContentView::ensure_inspector_widget()
     };
 
     m_inspector_widget->on_dom_node_inspected = [&](auto id, auto pseudo_element) {
-        inspect_dom_node(id, pseudo_element);
+        return inspect_dom_node(id, pseudo_element);
     };
 }
 
@@ -531,15 +531,21 @@ void WebContentView::inspect_dom_tree()
     client().async_inspect_dom_tree();
 }
 
-void WebContentView::inspect_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement> pseudo_element)
+ErrorOr<Ladybird::DOMNodeProperties> WebContentView::inspect_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement> pseudo_element)
 {
-    // TODO: Use and display response
-    (void)client().inspect_dom_node(node_id, pseudo_element);
+    auto response = client().inspect_dom_node(node_id, pseudo_element);
+    if (!response.has_style())
+        return Error::from_string_view("Inspected node returned no style"sv);
+    return Ladybird::DOMNodeProperties {
+        .computed_style_json = TRY(String::from_deprecated_string(response.take_computed_style())),
+        .resolved_style_json = TRY(String::from_deprecated_string(response.take_resolved_style())),
+        .custom_properties_json = TRY(String::from_deprecated_string(response.take_custom_properties())),
+    };
 }
 
 void WebContentView::clear_inspected_dom_node()
 {
-    inspect_dom_node(0, {});
+    (void)inspect_dom_node(0, {});
 }
 
 void WebContentView::show_inspector()

+ 3 - 1
Ladybird/WebContentView.h

@@ -23,6 +23,8 @@
 #include <QAbstractScrollArea>
 #include <QPointer>
 
+#include "DOMNodeProperties.h"
+
 class QTextEdit;
 class QLineEdit;
 
@@ -189,9 +191,9 @@ private:
 
     bool is_inspector_open() const;
     void inspect_dom_tree();
-    void inspect_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement> pseudo_element);
     void clear_inspected_dom_node();
     void clear_inspector_callbacks();
+    ErrorOr<Ladybird::DOMNodeProperties> inspect_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement> pseudo_element);
 
     qreal m_inverse_pixel_scaling_ratio { 1.0 };
     bool m_should_show_line_box_borders { false };