mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 19:12:43 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									f2b4c044db
								
							
						
					
					
						commit
						45a81f5a2c
					
				
					 14 changed files with 168 additions and 4 deletions
				
			
		|  | @ -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); | ||||
|  |  | |||
|  | @ -25,6 +25,7 @@ set(SOURCES | |||
|     History.cpp | ||||
|     IconBag.cpp | ||||
|     InspectorWidget.cpp | ||||
|     LocalStorageModel.cpp | ||||
|     StorageWidget.cpp | ||||
|     StorageWidgetGML.h | ||||
|     Tab.cpp | ||||
|  |  | |||
							
								
								
									
										69
									
								
								Userland/Applications/Browser/LocalStorageModel.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								Userland/Applications/Browser/LocalStorageModel.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -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
									
								
								Userland/Applications/Browser/LocalStorageModel.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								Userland/Applications/Browser/LocalStorageModel.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  | @ -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(); | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -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; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
|  | @ -32,6 +32,8 @@ public: | |||
| 
 | ||||
|     Vector<String> supported_property_names() const; | ||||
| 
 | ||||
|     auto const& map() const { return m_map; } | ||||
| 
 | ||||
|     void dump() const; | ||||
| 
 | ||||
| private: | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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(); | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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) | ||||
| 
 | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Valtteri Koskivuori
						Valtteri Koskivuori