diff --git a/Libraries/LibDevTools/Actors/NodeActor.cpp b/Libraries/LibDevTools/Actors/NodeActor.cpp index a0021903bbb..2cce2f7cd35 100644 --- a/Libraries/LibDevTools/Actors/NodeActor.cpp +++ b/Libraries/LibDevTools/Actors/NodeActor.cpp @@ -5,14 +5,63 @@ */ #include +#include +#include #include #include #include #include #include +#include namespace DevTools { +struct AttributeModification { + Optional attribute_to_replace; + Vector replacement_attributes; +}; +static AttributeModification parse_attribute_modification(JsonArray const& modifications) +{ + if (modifications.is_empty()) + return {}; + + Optional attribute_to_replace; + Vector replacement_attributes; + + auto parse_modification = [&](JsonValue const& modification) -> Variant { + if (!modification.is_object()) + return {}; + + auto name = modification.as_object().get_string("attributeName"sv); + if (!name.has_value()) + return {}; + + auto value = modification.as_object().get_string("newValue"sv); + if (!value.has_value()) + return *name; + + return WebView::Attribute { *name, *value }; + }; + + auto modification = parse_modification(modifications.at(0)); + if (modification.has()) + return {}; + + modification.visit( + [&](String& name) { attribute_to_replace = move(name); }, + [&](WebView::Attribute& attribute) { replacement_attributes.append(move(attribute)); }, + [](Empty) { VERIFY_NOT_REACHED(); }); + + for (auto i = 1uz; i < modifications.size(); ++i) { + auto modification = parse_modification(modifications.at(i)); + + if (auto* attribute = modification.get_pointer()) + replacement_attributes.empend(move(attribute->name), move(attribute->value)); + } + + return AttributeModification { move(attribute_to_replace), move(replacement_attributes) }; +} + NodeIdentifier NodeIdentifier::for_node(JsonObject const& node) { NodeIdentifier identifier; @@ -57,6 +106,40 @@ void NodeActor::handle_message(StringView type, JsonObject const& message) return; } + if (type == "modifyAttributes"sv) { + auto modifications = message.get_array("modifications"sv); + if (!modifications.has_value()) { + send_missing_parameter_error("modifications"sv); + return; + } + + auto [attribute_to_replace, replacement_attributes] = parse_attribute_modification(*modifications); + if (!attribute_to_replace.has_value() && replacement_attributes.is_empty()) + return; + + if (auto dom_node = WalkerActor::dom_node_for(m_walker, name()); dom_node.has_value()) { + auto block_token = block_responses(); + + auto on_complete = [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()) + self->finished_editing_dom_node(move(block_token)); + }; + + if (attribute_to_replace.has_value()) { + devtools().delegate().replace_dom_node_attribute(dom_node->tab->description(), dom_node->identifier.id, attribute_to_replace.release_value(), move(replacement_attributes), move(on_complete)); + } else { + devtools().delegate().add_dom_node_attributes(dom_node->tab->description(), dom_node->identifier.id, move(replacement_attributes), move(on_complete)); + } + } + + return; + } + if (type == "setNodeValue"sv) { auto value = message.get_string("value"sv); if (!value.has_value()) { diff --git a/Libraries/LibDevTools/DevToolsDelegate.h b/Libraries/LibDevTools/DevToolsDelegate.h index 4ec995e73c2..d31ca0cdda2 100644 --- a/Libraries/LibDevTools/DevToolsDelegate.h +++ b/Libraries/LibDevTools/DevToolsDelegate.h @@ -43,6 +43,8 @@ public: using OnDOMNodeEditComplete = Function)>; virtual void set_dom_node_text(TabDescription const&, Web::UniqueNodeID, String, OnDOMNodeEditComplete) const { } + virtual void add_dom_node_attributes(TabDescription const&, Web::UniqueNodeID, Vector, OnDOMNodeEditComplete) const { } + virtual void replace_dom_node_attribute(TabDescription const&, Web::UniqueNodeID, String, Vector, OnDOMNodeEditComplete) const { } using OnScriptEvaluationComplete = Function)>; virtual void evaluate_javascript(TabDescription const&, String, OnScriptEvaluationComplete) const { } diff --git a/Libraries/LibWebView/Application.cpp b/Libraries/LibWebView/Application.cpp index 744daab7a78..c10fd6aa0cb 100644 --- a/Libraries/LibWebView/Application.cpp +++ b/Libraries/LibWebView/Application.cpp @@ -465,6 +465,20 @@ void Application::set_dom_node_text(DevTools::TabDescription const& description, }); } +void Application::add_dom_node_attributes(DevTools::TabDescription const& description, Web::UniqueNodeID node_id, Vector replacement_attributes, OnDOMNodeEditComplete on_complete) const +{ + edit_dom_node(description, move(on_complete), [&](auto& view) { + view.add_dom_node_attributes(node_id, move(replacement_attributes)); + }); +} + +void Application::replace_dom_node_attribute(DevTools::TabDescription const& description, Web::UniqueNodeID node_id, String name, Vector replacement_attributes, OnDOMNodeEditComplete on_complete) const +{ + edit_dom_node(description, move(on_complete), [&](auto& view) { + view.replace_dom_node_attribute(node_id, move(name), move(replacement_attributes)); + }); +} + void Application::evaluate_javascript(DevTools::TabDescription const& description, String script, OnScriptEvaluationComplete on_complete) const { auto view = ViewImplementation::find_view_by_id(description.id); diff --git a/Libraries/LibWebView/Application.h b/Libraries/LibWebView/Application.h index 195d2a9fb0c..acaa3aa2f14 100644 --- a/Libraries/LibWebView/Application.h +++ b/Libraries/LibWebView/Application.h @@ -99,6 +99,8 @@ private: 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 set_dom_node_text(DevTools::TabDescription const&, Web::UniqueNodeID, String, OnDOMNodeEditComplete) const override; + virtual void add_dom_node_attributes(DevTools::TabDescription const&, Web::UniqueNodeID, Vector, OnDOMNodeEditComplete) const override; + virtual void replace_dom_node_attribute(DevTools::TabDescription const&, Web::UniqueNodeID, String, Vector, OnDOMNodeEditComplete) const override; virtual void evaluate_javascript(DevTools::TabDescription const&, String, OnScriptEvaluationComplete) const override; virtual void listen_for_console_messages(DevTools::TabDescription const&, OnConsoleMessageAvailable, OnReceivedConsoleMessages) const override; virtual void stop_listening_for_console_messages(DevTools::TabDescription const&) const override;