This is to prepare for an upcoming change where we will need to track replies to messages by ID. We will be able to add parameters to this structure without having to edit every single actor subclass header file.
153 lines
5.2 KiB
C++
153 lines
5.2 KiB
C++
/*
|
|
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/JsonObject.h>
|
|
#include <AK/Optional.h>
|
|
#include <AK/Variant.h>
|
|
#include <LibDevTools/Actors/NodeActor.h>
|
|
#include <LibDevTools/Actors/TabActor.h>
|
|
#include <LibDevTools/Actors/WalkerActor.h>
|
|
#include <LibDevTools/DevToolsDelegate.h>
|
|
#include <LibDevTools/DevToolsServer.h>
|
|
#include <LibWebView/Attribute.h>
|
|
|
|
namespace DevTools {
|
|
|
|
struct AttributeModification {
|
|
Optional<String> attribute_to_replace;
|
|
Vector<WebView::Attribute> replacement_attributes;
|
|
};
|
|
static AttributeModification parse_attribute_modification(JsonArray const& modifications)
|
|
{
|
|
if (modifications.is_empty())
|
|
return {};
|
|
|
|
Optional<String> attribute_to_replace;
|
|
Vector<WebView::Attribute> replacement_attributes;
|
|
|
|
auto parse_modification = [&](JsonValue const& modification) -> Variant<Empty, String, WebView::Attribute> {
|
|
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<Empty>())
|
|
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<WebView::Attribute>())
|
|
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;
|
|
|
|
identifier.pseudo_element = node.get_integer<UnderlyingType<Web::CSS::Selector::PseudoElement::Type>>("pseudo-element"sv).map([](auto value) {
|
|
VERIFY(value < to_underlying(Web::CSS::Selector::PseudoElement::Type::KnownPseudoElementCount));
|
|
return static_cast<Web::CSS::Selector::PseudoElement::Type>(value);
|
|
});
|
|
|
|
if (identifier.pseudo_element.has_value())
|
|
identifier.id = node.get_integer<Web::UniqueNodeID::Type>("parent-id"sv).value();
|
|
else
|
|
identifier.id = node.get_integer<Web::UniqueNodeID::Type>("id"sv).value();
|
|
|
|
return identifier;
|
|
}
|
|
|
|
NonnullRefPtr<NodeActor> NodeActor::create(DevToolsServer& devtools, String name, NodeIdentifier node_identifier, WeakPtr<WalkerActor> walker)
|
|
{
|
|
return adopt_ref(*new NodeActor(devtools, move(name), move(node_identifier), move(walker)));
|
|
}
|
|
|
|
NodeActor::NodeActor(DevToolsServer& devtools, String name, NodeIdentifier node_identifier, WeakPtr<WalkerActor> walker)
|
|
: Actor(devtools, move(name))
|
|
, m_node_identifier(move(node_identifier))
|
|
, m_walker(move(walker))
|
|
{
|
|
}
|
|
|
|
NodeActor::~NodeActor() = default;
|
|
|
|
void NodeActor::handle_message(Message const& message)
|
|
{
|
|
JsonObject response;
|
|
|
|
if (message.type == "getUniqueSelector"sv) {
|
|
auto dom_node = WalkerActor::dom_node_for(m_walker, name());
|
|
if (!dom_node.has_value()) {
|
|
send_unknown_actor_error(name());
|
|
return;
|
|
}
|
|
|
|
response.set("value"sv, dom_node->node.get_string("name"sv)->to_ascii_lowercase());
|
|
send_message(move(response));
|
|
return;
|
|
}
|
|
|
|
if (message.type == "modifyAttributes"sv) {
|
|
auto modifications = get_required_parameter<JsonArray>(message, "modifications"sv);
|
|
if (!modifications.has_value())
|
|
return;
|
|
|
|
auto [attribute_to_replace, replacement_attributes] = parse_attribute_modification(*modifications);
|
|
if (!attribute_to_replace.has_value() && replacement_attributes.is_empty())
|
|
return;
|
|
|
|
auto dom_node = WalkerActor::dom_node_for(m_walker, name());
|
|
if (!dom_node.has_value()) {
|
|
send_unknown_actor_error(name());
|
|
return;
|
|
}
|
|
|
|
if (attribute_to_replace.has_value())
|
|
devtools().delegate().replace_dom_node_attribute(dom_node->tab->description(), dom_node->identifier.id, *attribute_to_replace, move(replacement_attributes), default_async_handler());
|
|
else
|
|
devtools().delegate().add_dom_node_attributes(dom_node->tab->description(), dom_node->identifier.id, move(replacement_attributes), default_async_handler());
|
|
|
|
return;
|
|
}
|
|
|
|
if (message.type == "setNodeValue"sv) {
|
|
auto value = get_required_parameter<String>(message, "value"sv);
|
|
if (!value.has_value())
|
|
return;
|
|
|
|
auto dom_node = WalkerActor::dom_node_for(m_walker, name());
|
|
if (!dom_node.has_value()) {
|
|
send_unknown_actor_error(name());
|
|
return;
|
|
}
|
|
|
|
devtools().delegate().set_dom_node_text(dom_node->tab->description(), dom_node->identifier.id, *value, default_async_handler());
|
|
return;
|
|
}
|
|
|
|
send_unrecognized_packet_type_error(message);
|
|
}
|
|
|
|
}
|