diff --git a/Libraries/LibDevTools/Actors/WalkerActor.cpp b/Libraries/LibDevTools/Actors/WalkerActor.cpp index 0109efa04fb..6b6789cde0f 100644 --- a/Libraries/LibDevTools/Actors/WalkerActor.cpp +++ b/Libraries/LibDevTools/Actors/WalkerActor.cpp @@ -214,6 +214,36 @@ void WalkerActor::handle_message(StringView type, JsonObject const& message) return; } + if (type == "outerHTML"sv) { + auto node = message.get_string("node"sv); + if (!node.has_value()) { + send_missing_parameter_error("node"sv); + return; + } + + if (auto dom_node = WalkerActor::dom_node_for(*this, *node); dom_node.has_value()) { + auto block_token = block_responses(); + + devtools().delegate().get_dom_node_outer_html( + dom_node->tab->description(), dom_node->identifier.id, + [weak_self = make_weak_ptr(), block_token = move(block_token)](ErrorOr html) mutable { + if (html.is_error()) { + dbgln_if(DEVTOOLS_DEBUG, "Unable to edit DOM node: {}", html.error()); + return; + } + + if (auto self = weak_self.strong_ref()) { + JsonObject message; + message.set("from"sv, self->name()); + message.set("value"sv, html.release_value()); + self->send_message(move(message), move(block_token)); + } + }); + } + + return; + } + if (type == "previousSibling"sv) { auto node = message.get_string("node"sv); if (!node.has_value()) { @@ -307,6 +337,41 @@ void WalkerActor::handle_message(StringView type, JsonObject const& message) return; } + if (type == "setOuterHTML"sv) { + auto node = message.get_string("node"sv); + if (!node.has_value()) { + send_missing_parameter_error("node"sv); + return; + } + + auto value = message.get_string("value"sv); + if (!value.has_value()) { + send_missing_parameter_error("value"sv); + return; + } + + if (auto dom_node = WalkerActor::dom_node_for(*this, *node); dom_node.has_value()) { + auto block_token = block_responses(); + + devtools().delegate().set_dom_node_outer_html( + dom_node->tab->description(), dom_node->identifier.id, value.release_value(), + [weak_self = make_weak_ptr(), block_token = move(block_token)](ErrorOr node_id) mutable { + if (node_id.is_error()) { + dbgln_if(DEVTOOLS_DEBUG, "Unable to edit DOM node: {}", node_id.error()); + return; + } + + if (auto self = weak_self.strong_ref()) { + JsonObject message; + message.set("from"sv, self->name()); + self->send_message(move(message), move(block_token)); + } + }); + } + + return; + } + if (type == "watchRootNode"sv) { response.set("type"sv, "root-available"sv); response.set("node"sv, serialize_root()); diff --git a/Libraries/LibDevTools/DevToolsDelegate.h b/Libraries/LibDevTools/DevToolsDelegate.h index c24152c74ee..418602dd6cf 100644 --- a/Libraries/LibDevTools/DevToolsDelegate.h +++ b/Libraries/LibDevTools/DevToolsDelegate.h @@ -41,7 +41,10 @@ public: virtual void listen_for_dom_mutations(TabDescription const&, OnDOMMutationReceived) const { } virtual void stop_listening_for_dom_mutations(TabDescription const&) const { } + using OnDOMNodeHTMLReceived = Function)>; using OnDOMNodeEditComplete = Function)>; + virtual void get_dom_node_outer_html(TabDescription const&, Web::UniqueNodeID, OnDOMNodeHTMLReceived) const { } + virtual void set_dom_node_outer_html(TabDescription const&, Web::UniqueNodeID, String const&, OnDOMNodeEditComplete) const { } virtual void set_dom_node_text(TabDescription const&, Web::UniqueNodeID, String const&, OnDOMNodeEditComplete) const { } virtual void set_dom_node_tag(TabDescription const&, Web::UniqueNodeID, String const&, OnDOMNodeEditComplete) const { } virtual void add_dom_node_attributes(TabDescription const&, Web::UniqueNodeID, ReadonlySpan, OnDOMNodeEditComplete) const { } diff --git a/Libraries/LibWebView/Application.cpp b/Libraries/LibWebView/Application.cpp index adf1ffdd628..7df0bd98d77 100644 --- a/Libraries/LibWebView/Application.cpp +++ b/Libraries/LibWebView/Application.cpp @@ -504,6 +504,29 @@ static void edit_dom_node(DevTools::TabDescription const& description, Applicati edit(*view); } +void Application::get_dom_node_outer_html(DevTools::TabDescription const& description, Web::UniqueNodeID node_id, OnDOMNodeHTMLReceived on_complete) const +{ + auto view = ViewImplementation::find_view_by_id(description.id); + if (!view.has_value()) { + on_complete(Error::from_string_literal("Unable to locate tab")); + return; + } + + view->on_received_dom_node_html = [&view = *view, on_complete = move(on_complete)](auto html) { + view.on_received_dom_node_html = nullptr; + on_complete(html); + }; + + view->get_dom_node_outer_html(node_id); +} + +void Application::set_dom_node_outer_html(DevTools::TabDescription const& description, Web::UniqueNodeID node_id, String const& value, OnDOMNodeEditComplete on_complete) const +{ + edit_dom_node(description, move(on_complete), [&](auto& view) { + view.set_dom_node_outer_html(node_id, value); + }); +} + void Application::set_dom_node_text(DevTools::TabDescription const& description, Web::UniqueNodeID node_id, String const& value, OnDOMNodeEditComplete on_complete) const { edit_dom_node(description, move(on_complete), [&](auto& view) { diff --git a/Libraries/LibWebView/Application.h b/Libraries/LibWebView/Application.h index 1595f8a7d42..6c67bce0cd6 100644 --- a/Libraries/LibWebView/Application.h +++ b/Libraries/LibWebView/Application.h @@ -100,6 +100,8 @@ private: virtual void clear_highlighted_dom_node(DevTools::TabDescription const&) const override; virtual void listen_for_dom_mutations(DevTools::TabDescription const&, OnDOMMutationReceived) const override; virtual void stop_listening_for_dom_mutations(DevTools::TabDescription const&) const override; + virtual void get_dom_node_outer_html(DevTools::TabDescription const&, Web::UniqueNodeID, OnDOMNodeHTMLReceived) const override; + virtual void set_dom_node_outer_html(DevTools::TabDescription const&, Web::UniqueNodeID, String const&, OnDOMNodeEditComplete) const override; virtual void set_dom_node_text(DevTools::TabDescription const&, Web::UniqueNodeID, String const&, OnDOMNodeEditComplete) const override; virtual void set_dom_node_tag(DevTools::TabDescription const&, Web::UniqueNodeID, String const&, OnDOMNodeEditComplete) const override; virtual void add_dom_node_attributes(DevTools::TabDescription const&, Web::UniqueNodeID, ReadonlySpan, OnDOMNodeEditComplete) const override; diff --git a/Libraries/LibWebView/InspectorClient.cpp b/Libraries/LibWebView/InspectorClient.cpp index 1eb52698ee7..c27f02c8ee6 100644 --- a/Libraries/LibWebView/InspectorClient.cpp +++ b/Libraries/LibWebView/InspectorClient.cpp @@ -368,7 +368,7 @@ void InspectorClient::context_menu_copy_dom_node() { VERIFY(m_context_menu_data.has_value()); - m_content_web_view.get_dom_node_html(m_context_menu_data->dom_node_id); + m_content_web_view.get_dom_node_outer_html(m_context_menu_data->dom_node_id); m_context_menu_data.clear(); } diff --git a/Libraries/LibWebView/ViewImplementation.cpp b/Libraries/LibWebView/ViewImplementation.cpp index 3ae345ebe32..aacaea31d10 100644 --- a/Libraries/LibWebView/ViewImplementation.cpp +++ b/Libraries/LibWebView/ViewImplementation.cpp @@ -354,6 +354,16 @@ void ViewImplementation::set_listen_for_dom_mutations(bool listen_for_dom_mutati client().async_set_listen_for_dom_mutations(page_id(), listen_for_dom_mutations); } +void ViewImplementation::get_dom_node_outer_html(Web::UniqueNodeID node_id) +{ + client().async_get_dom_node_outer_html(page_id(), node_id); +} + +void ViewImplementation::set_dom_node_outer_html(Web::UniqueNodeID node_id, String const& html) +{ + client().async_set_dom_node_outer_html(page_id(), node_id, html); +} + void ViewImplementation::set_dom_node_text(Web::UniqueNodeID node_id, String const& text) { client().async_set_dom_node_text(page_id(), node_id, text); @@ -394,11 +404,6 @@ void ViewImplementation::remove_dom_node(Web::UniqueNodeID node_id) client().async_remove_dom_node(page_id(), node_id); } -void ViewImplementation::get_dom_node_html(Web::UniqueNodeID node_id) -{ - client().async_get_dom_node_html(page_id(), node_id); -} - void ViewImplementation::list_style_sheets() { client().async_list_style_sheets(page_id()); diff --git a/Libraries/LibWebView/ViewImplementation.h b/Libraries/LibWebView/ViewImplementation.h index c1f8ed73592..eb6e322dafa 100644 --- a/Libraries/LibWebView/ViewImplementation.h +++ b/Libraries/LibWebView/ViewImplementation.h @@ -115,6 +115,8 @@ public: void clear_highlighted_dom_node(); void set_listen_for_dom_mutations(bool); + void get_dom_node_outer_html(Web::UniqueNodeID node_id); + void set_dom_node_outer_html(Web::UniqueNodeID node_id, String const& html); void set_dom_node_text(Web::UniqueNodeID node_id, String const& text); void set_dom_node_tag(Web::UniqueNodeID node_id, String const& name); void add_dom_node_attributes(Web::UniqueNodeID node_id, ReadonlySpan attributes); @@ -123,7 +125,6 @@ public: void create_child_text_node(Web::UniqueNodeID node_id); void clone_dom_node(Web::UniqueNodeID node_id); void remove_dom_node(Web::UniqueNodeID node_id); - void get_dom_node_html(Web::UniqueNodeID node_id); void list_style_sheets(); void request_style_sheet_source(Web::CSS::StyleSheetIdentifier const&); @@ -218,7 +219,7 @@ public: Function on_received_hovered_node_id; Function on_dom_mutation_received; Function const& node_id)> on_finshed_editing_dom_node; - Function on_received_dom_node_html; + Function on_received_dom_node_html; Function on_received_js_console_result; Function on_console_message_available; Function const& message_types, Vector const& messages)> on_received_styled_console_messages; diff --git a/Libraries/LibWebView/WebContentClient.cpp b/Libraries/LibWebView/WebContentClient.cpp index be244be42ee..146140b2f06 100644 --- a/Libraries/LibWebView/WebContentClient.cpp +++ b/Libraries/LibWebView/WebContentClient.cpp @@ -371,7 +371,7 @@ void WebContentClient::did_get_dom_node_html(u64 page_id, String html) { if (auto view = view_for_page_id(page_id); view.has_value()) { if (view->on_received_dom_node_html) - view->on_received_dom_node_html(html); + view->on_received_dom_node_html(move(html)); } } diff --git a/Services/WebContent/ConnectionFromClient.cpp b/Services/WebContent/ConnectionFromClient.cpp index d68f468c879..a1ac9502f24 100644 --- a/Services/WebContent/ConnectionFromClient.cpp +++ b/Services/WebContent/ConnectionFromClient.cpp @@ -676,6 +676,49 @@ void ConnectionFromClient::set_listen_for_dom_mutations(u64 page_id, bool listen page->page().set_listen_for_dom_mutations(listen_for_dom_mutations); } +void ConnectionFromClient::get_dom_node_outer_html(u64 page_id, Web::UniqueNodeID node_id) +{ + auto* dom_node = Web::DOM::Node::from_unique_id(node_id); + if (!dom_node) + return; + + String html; + + if (dom_node->is_element()) { + auto const& element = static_cast(*dom_node); + html = element.outer_html().release_value_but_fixme_should_propagate_errors(); + } else if (dom_node->is_text() || dom_node->is_comment()) { + auto const& character_data = static_cast(*dom_node); + html = character_data.data(); + } else { + return; + } + + async_did_get_dom_node_html(page_id, html); +} + +void ConnectionFromClient::set_dom_node_outer_html(u64 page_id, Web::UniqueNodeID node_id, String html) +{ + auto* dom_node = Web::DOM::Node::from_unique_id(node_id); + if (!dom_node) { + async_did_finish_editing_dom_node(page_id, {}); + return; + } + + if (dom_node->is_element()) { + auto& element = static_cast(*dom_node); + element.set_outer_html(html).release_value_but_fixme_should_propagate_errors(); + } else if (dom_node->is_text() || dom_node->is_comment()) { + auto& character_data = static_cast(*dom_node); + character_data.set_data(html); + } else { + async_did_finish_editing_dom_node(page_id, {}); + return; + } + + async_did_finish_editing_dom_node(page_id, node_id); +} + void ConnectionFromClient::set_dom_node_text(u64 page_id, Web::UniqueNodeID node_id, String text) { auto* dom_node = Web::DOM::Node::from_unique_id(node_id); @@ -826,27 +869,6 @@ void ConnectionFromClient::remove_dom_node(u64 page_id, Web::UniqueNodeID node_i async_did_finish_editing_dom_node(page_id, previous_dom_node->unique_id()); } -void ConnectionFromClient::get_dom_node_html(u64 page_id, Web::UniqueNodeID node_id) -{ - auto* dom_node = Web::DOM::Node::from_unique_id(node_id); - if (!dom_node) - return; - - String html; - - if (dom_node->is_element()) { - auto const& element = static_cast(*dom_node); - html = element.outer_html().release_value_but_fixme_should_propagate_errors(); - } else if (dom_node->is_text() || dom_node->is_comment()) { - auto const& character_data = static_cast(*dom_node); - html = character_data.data(); - } else { - return; - } - - async_did_get_dom_node_html(page_id, html); -} - void ConnectionFromClient::take_document_screenshot(u64 page_id) { auto page = this->page(page_id); diff --git a/Services/WebContent/ConnectionFromClient.h b/Services/WebContent/ConnectionFromClient.h index 8ba5b0eb351..65d7146ed92 100644 --- a/Services/WebContent/ConnectionFromClient.h +++ b/Services/WebContent/ConnectionFromClient.h @@ -84,6 +84,8 @@ private: virtual void request_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier identifier) override; virtual void set_listen_for_dom_mutations(u64 page_id, bool) override; + virtual void get_dom_node_outer_html(u64 page_id, Web::UniqueNodeID node_id) override; + virtual void set_dom_node_outer_html(u64 page_id, Web::UniqueNodeID node_id, String html) override; virtual void set_dom_node_text(u64 page_id, Web::UniqueNodeID node_id, String text) override; virtual void set_dom_node_tag(u64 page_id, Web::UniqueNodeID node_id, String name) override; virtual void add_dom_node_attributes(u64 page_id, Web::UniqueNodeID node_id, Vector attributes) override; @@ -92,7 +94,6 @@ private: virtual void create_child_text_node(u64 page_id, Web::UniqueNodeID node_id) override; virtual void clone_dom_node(u64 page_id, Web::UniqueNodeID node_id) override; virtual void remove_dom_node(u64 page_id, Web::UniqueNodeID node_id) override; - virtual void get_dom_node_html(u64 page_id, Web::UniqueNodeID node_id) override; virtual void set_content_filters(u64 page_id, Vector) override; virtual void set_autoplay_allowed_on_all_websites(u64 page_id) override; diff --git a/Services/WebContent/WebContentServer.ipc b/Services/WebContent/WebContentServer.ipc index 18b0b036fcc..ddad965753a 100644 --- a/Services/WebContent/WebContentServer.ipc +++ b/Services/WebContent/WebContentServer.ipc @@ -57,6 +57,8 @@ endpoint WebContentServer request_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier identifier) =| set_listen_for_dom_mutations(u64 page_id, bool listen_for_dom_mutations) =| + get_dom_node_outer_html(u64 page_id, Web::UniqueNodeID node_id) =| + set_dom_node_outer_html(u64 page_id, Web::UniqueNodeID node_id, String html) =| set_dom_node_text(u64 page_id, Web::UniqueNodeID node_id, String text) =| set_dom_node_tag(u64 page_id, Web::UniqueNodeID node_id, String name) =| add_dom_node_attributes(u64 page_id, Web::UniqueNodeID node_id, Vector attributes) =| @@ -65,7 +67,6 @@ endpoint WebContentServer create_child_text_node(u64 page_id, Web::UniqueNodeID node_id) =| clone_dom_node(u64 page_id, Web::UniqueNodeID node_id) =| remove_dom_node(u64 page_id, Web::UniqueNodeID node_id) =| - get_dom_node_html(u64 page_id, Web::UniqueNodeID node_id) =| take_document_screenshot(u64 page_id) =| take_dom_node_screenshot(u64 page_id, Web::UniqueNodeID node_id) =|