Browse Source

Browser+LibWeb+WebContent: Add ability to inspect local storage

The storage inspector now has a new tab for local storage. The next step
would be to persist local storage and receive real-time notifications
for changes to update the table view.
Valtteri Koskivuori 3 năm trước cách đây
mục cha
commit
45a81f5a2c

+ 4 - 0
Userland/Applications/Browser/BrowserWindow.cpp

@@ -555,6 +555,10 @@ void BrowserWindow::create_new_tab(URL url, bool activate)
         return m_cookie_jar.get_all_cookies();
     };
 
+    new_tab.on_get_local_storage_entries = [this]() {
+        return active_tab().m_web_content_view->get_local_storage_entries();
+    };
+
     new_tab.load(url);
 
     dbgln_if(SPAM_DEBUG, "Added new tab {:p}, loading {}", &new_tab, url);

+ 1 - 0
Userland/Applications/Browser/CMakeLists.txt

@@ -25,6 +25,7 @@ set(SOURCES
     History.cpp
     IconBag.cpp
     InspectorWidget.cpp
+    LocalStorageModel.cpp
     StorageWidget.cpp
     StorageWidgetGML.h
     Tab.cpp

+ 69 - 0
Userland/Applications/Browser/LocalStorageModel.cpp

@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2022, Valtteri Koskivuori <vkoskiv@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "LocalStorageModel.h"
+
+namespace Browser {
+
+void LocalStorageModel::set_items(OrderedHashMap<String, String> map)
+{
+    begin_insert_rows({}, m_local_storage_entries.size(), m_local_storage_entries.size());
+    m_local_storage_entries = map;
+    end_insert_rows();
+
+    did_update(DontInvalidateIndices);
+}
+
+void LocalStorageModel::clear_items()
+{
+    begin_insert_rows({}, m_local_storage_entries.size(), m_local_storage_entries.size());
+    m_local_storage_entries.clear();
+    end_insert_rows();
+
+    did_update(DontInvalidateIndices);
+}
+
+String LocalStorageModel::column_name(int column) const
+{
+    switch (column) {
+    case Column::Key:
+        return "Key";
+    case Column::Value:
+        return "Value";
+    case Column::__Count:
+        return {};
+    }
+
+    return {};
+}
+
+GUI::ModelIndex LocalStorageModel::index(int row, int column, GUI::ModelIndex const&) const
+{
+    if (static_cast<size_t>(row) < m_local_storage_entries.size())
+        return create_index(row, column, NULL);
+    return {};
+}
+
+GUI::Variant LocalStorageModel::data(GUI::ModelIndex const& index, GUI::ModelRole role) const
+{
+    if (role != GUI::ModelRole::Display)
+        return {};
+
+    auto const& keys = m_local_storage_entries.keys();
+    auto const& local_storage_key = keys[index.row()];
+    auto const& local_storage_value = m_local_storage_entries.get(local_storage_key).value_or({});
+
+    switch (index.column()) {
+    case Column::Key:
+        return local_storage_key;
+    case Column::Value:
+        return local_storage_value;
+    }
+
+    VERIFY_NOT_REACHED();
+}
+
+}

+ 33 - 0
Userland/Applications/Browser/LocalStorageModel.h

@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2022, Valtteri Koskivuori <vkoskiv@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibGUI/Model.h>
+
+namespace Browser {
+
+class LocalStorageModel final : public GUI::Model {
+public:
+    enum Column {
+        Key,
+        Value,
+        __Count,
+    };
+
+    void set_items(OrderedHashMap<String, String> map);
+    void clear_items();
+    virtual int row_count(GUI::ModelIndex const&) const override { return m_local_storage_entries.size(); }
+    virtual int column_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return Column::__Count; }
+    virtual String column_name(int column) const override;
+    virtual GUI::ModelIndex index(int row, int column = 0, GUI::ModelIndex const& = GUI::ModelIndex()) const override;
+    virtual GUI::Variant data(GUI::ModelIndex const& index, GUI::ModelRole role = GUI::ModelRole::Display) const override;
+
+private:
+    OrderedHashMap<String, String> m_local_storage_entries;
+};
+
+}

+ 27 - 3
Userland/Applications/Browser/StorageWidget.cpp

@@ -6,6 +6,7 @@
 
 #include "StorageWidget.h"
 #include "CookiesModel.h"
+#include "LocalStorageModel.h"
 #include <AK/Variant.h>
 #include <Applications/Browser/CookiesTabGML.h>
 #include <Applications/Browser/StorageWidgetGML.h>
@@ -26,12 +27,25 @@ StorageWidget::StorageWidget()
     m_cookies_table_view = cookies_tab->find_descendant_of_type_named<GUI::TableView>("cookies_tableview");
     m_cookies_model = adopt_ref(*new CookiesModel());
 
-    m_sorting_model = MUST(GUI::SortingProxyModel::create(*m_cookies_model));
-    m_sorting_model->set_sort_role(GUI::ModelRole::Display);
+    m_cookie_sorting_model = MUST(GUI::SortingProxyModel::create(*m_cookies_model));
+    m_cookie_sorting_model->set_sort_role(GUI::ModelRole::Display);
 
-    m_cookies_table_view->set_model(m_sorting_model);
+    m_cookies_table_view->set_model(m_cookie_sorting_model);
     m_cookies_table_view->set_column_headers_visible(true);
     m_cookies_table_view->set_alternating_row_colors(true);
+
+    auto local_storage_tab = tab_widget.try_add_tab<GUI::Widget>("Local Storage").release_value_but_fixme_should_propagate_errors();
+    local_storage_tab->load_from_gml(cookies_tab_gml);
+
+    m_local_storage_table_view = local_storage_tab->find_descendant_of_type_named<GUI::TableView>("cookies_tableview");
+    m_local_storage_model = adopt_ref(*new LocalStorageModel());
+
+    m_local_storage_sorting_model = MUST(GUI::SortingProxyModel::create(*m_local_storage_model));
+    m_local_storage_sorting_model->set_sort_role(GUI::ModelRole::Display);
+
+    m_local_storage_table_view->set_model(m_local_storage_sorting_model);
+    m_local_storage_table_view->set_column_headers_visible(true);
+    m_local_storage_table_view->set_alternating_row_colors(true);
 }
 
 void StorageWidget::add_cookie(Web::Cookie::Cookie const& cookie)
@@ -44,4 +58,14 @@ void StorageWidget::clear_cookies()
     m_cookies_model->clear_items();
 }
 
+void StorageWidget::set_local_storage_entries(OrderedHashMap<String, String> entries)
+{
+    m_local_storage_model->set_items(entries);
+}
+
+void StorageWidget::clear_local_storage_entries()
+{
+    m_local_storage_model->clear_items();
+}
+
 }

+ 8 - 1
Userland/Applications/Browser/StorageWidget.h

@@ -7,6 +7,7 @@
 #pragma once
 
 #include "CookiesModel.h"
+#include "LocalStorageModel.h"
 #include "Tab.h"
 #include <LibGUI/SortingProxyModel.h>
 #include <LibGUI/Widget.h>
@@ -22,12 +23,18 @@ public:
     void add_cookie(Web::Cookie::Cookie const& cookie);
     void clear_cookies();
 
+    void set_local_storage_entries(OrderedHashMap<String, String> entries);
+    void clear_local_storage_entries();
+
 private:
     StorageWidget();
 
     RefPtr<GUI::TableView> m_cookies_table_view;
     RefPtr<CookiesModel> m_cookies_model;
-    RefPtr<GUI::SortingProxyModel> m_sorting_model;
+    RefPtr<GUI::SortingProxyModel> m_cookie_sorting_model;
+    RefPtr<GUI::TableView> m_local_storage_table_view;
+    RefPtr<LocalStorageModel> m_local_storage_model;
+    RefPtr<GUI::SortingProxyModel> m_local_storage_sorting_model;
 };
 
 }

+ 6 - 0
Userland/Applications/Browser/Tab.cpp

@@ -613,6 +613,12 @@ void Tab::show_storage_inspector()
             m_storage_widget->add_cookie(cookie);
     }
 
+    if (on_get_local_storage_entries) {
+        auto local_storage_entries = on_get_local_storage_entries();
+        m_storage_widget->clear_local_storage_entries();
+        m_storage_widget->set_local_storage_entries(local_storage_entries);
+    }
+
     auto* window = m_storage_widget->window();
     window->show();
     window->move_to_front();

+ 1 - 0
Userland/Applications/Browser/Tab.h

@@ -65,6 +65,7 @@ public:
     Function<void(const URL&, Web::Cookie::ParsedCookie const& cookie, Web::Cookie::Source source)> on_set_cookie;
     Function<void()> on_dump_cookies;
     Function<Vector<Web::Cookie::Cookie>()> on_want_cookies;
+    Function<OrderedHashMap<String, String>()> on_get_local_storage_entries;
 
     enum class InspectorTarget {
         Document,

+ 2 - 0
Userland/Libraries/LibWeb/HTML/Storage.h

@@ -32,6 +32,8 @@ public:
 
     Vector<String> supported_property_names() const;
 
+    auto const& map() const { return m_map; }
+
     void dump() const;
 
 private:

+ 5 - 0
Userland/Libraries/LibWeb/OutOfProcessWebView.cpp

@@ -490,6 +490,11 @@ String OutOfProcessWebView::dump_layout_tree()
     return client().dump_layout_tree();
 }
 
+OrderedHashMap<String, String> OutOfProcessWebView::get_local_storage_entries()
+{
+    return client().get_local_storage_entries();
+}
+
 void OutOfProcessWebView::set_content_filters(Vector<String> filters)
 {
     client().async_set_content_filters(filters);

+ 2 - 0
Userland/Libraries/LibWeb/OutOfProcessWebView.h

@@ -55,6 +55,8 @@ public:
 
     String dump_layout_tree();
 
+    OrderedHashMap<String, String> get_local_storage_entries();
+
     void set_content_filters(Vector<String>);
     void set_preferred_color_scheme(Web::CSS::PreferredColorScheme);
 

+ 6 - 0
Userland/Services/WebContent/ConnectionFromClient.cpp

@@ -468,4 +468,10 @@ void ConnectionFromClient::set_is_scripting_enabled(bool is_scripting_enabled)
     m_page_host->set_is_scripting_enabled(is_scripting_enabled);
 }
 
+Messages::WebContentServer::GetLocalStorageEntriesResponse ConnectionFromClient::get_local_storage_entries()
+{
+    auto* document = page().top_level_browsing_context().active_document();
+    auto local_storage = document->window().local_storage();
+    return local_storage->map();
+}
 }

+ 2 - 0
Userland/Services/WebContent/ConnectionFromClient.h

@@ -67,6 +67,8 @@ private:
     virtual void run_javascript(String const&) override;
     virtual void js_console_request_messages(i32) override;
 
+    virtual Messages::WebContentServer::GetLocalStorageEntriesResponse get_local_storage_entries() override;
+
     virtual Messages::WebContentServer::GetSelectedTextResponse get_selected_text() override;
     virtual void select_all() override;
 

+ 2 - 0
Userland/Services/WebContent/WebContentServer.ipc

@@ -47,4 +47,6 @@ endpoint WebContentServer
     set_has_focus(bool has_focus) =|
     set_is_scripting_enabled(bool is_scripting_enabled) =|
 
+    get_local_storage_entries() => (OrderedHashMap<String,String> entries)
+
 }