mirror of
https://github.com/zebrajr/ladybird.git
synced 2025-12-06 12:20:00 +01:00
The "from" field is required in every response. It is the name of the actor sending the message. This patch fills in the "from" field in the Actor base class so that subclasses don't have to.
184 lines
6.3 KiB
C++
184 lines
6.3 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(StringView type, JsonObject const& message)
|
|
{
|
|
JsonObject response;
|
|
|
|
if (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 (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;
|
|
|
|
auto dom_node = WalkerActor::dom_node_for(m_walker, name());
|
|
if (!dom_node.has_value()) {
|
|
send_unknown_actor_error(name());
|
|
return;
|
|
}
|
|
|
|
auto block_token = block_responses();
|
|
|
|
auto on_complete = [weak_self = make_weak_ptr<NodeActor>(), block_token = move(block_token)](ErrorOr<Web::UniqueNodeID> 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->send_message({}, 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, 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()) {
|
|
send_missing_parameter_error("value"sv);
|
|
return;
|
|
}
|
|
|
|
auto dom_node = WalkerActor::dom_node_for(m_walker, name());
|
|
if (!dom_node.has_value()) {
|
|
send_unknown_actor_error(name());
|
|
return;
|
|
}
|
|
|
|
auto block_token = block_responses();
|
|
|
|
devtools().delegate().set_dom_node_text(
|
|
dom_node->tab->description(), dom_node->identifier.id, *value,
|
|
[weak_self = make_weak_ptr<NodeActor>(), block_token = move(block_token)](ErrorOr<Web::UniqueNodeID> 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->send_message({}, move(block_token));
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
send_unrecognized_packet_type_error(type);
|
|
}
|
|
|
|
}
|