Browse Source

Ladybird+LibWebView: Add an Inspector action to insert a child DOM node

Timothy Flynn 1 year ago
parent
commit
d5d6ff8bf1

+ 30 - 0
Ladybird/AppKit/UI/Inspector.mm

@@ -176,6 +176,16 @@ static constexpr NSInteger CONTEXT_MENU_COPY_ATTRIBUTE_VALUE_TAG = 3;
     m_inspector_client->context_menu_screenshot_dom_node();
 }
 
+- (void)createChildElement:(id)sender
+{
+    m_inspector_client->context_menu_create_child_element();
+}
+
+- (void)createChildTextNode:(id)sender
+{
+    m_inspector_client->context_menu_create_child_text_node();
+}
+
 - (void)deleteDOMNode:(id)sender
 {
     m_inspector_client->context_menu_remove_dom_node();
@@ -198,6 +208,24 @@ static constexpr NSInteger CONTEXT_MENU_COPY_ATTRIBUTE_VALUE_TAG = 3;
 
 #pragma mark - Properties
 
++ (NSMenuItem*)make_create_child_menu
+{
+    auto* create_child_menu = [[NSMenu alloc] init];
+    [create_child_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Create child element"
+                                                          action:@selector(createChildElement:)
+                                                   keyEquivalent:@""]];
+    [create_child_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Create child text node"
+                                                          action:@selector(createChildTextNode:)
+                                                   keyEquivalent:@""]];
+
+    auto* create_child_menu_item = [[NSMenuItem alloc] initWithTitle:@"Create child"
+                                                              action:nil
+                                                       keyEquivalent:@""];
+    [create_child_menu_item setSubmenu:create_child_menu];
+
+    return create_child_menu_item;
+}
+
 - (NSMenu*)dom_node_text_context_menu
 {
     if (!_dom_node_text_context_menu) {
@@ -236,6 +264,7 @@ static constexpr NSInteger CONTEXT_MENU_COPY_ATTRIBUTE_VALUE_TAG = 3;
         [_dom_node_tag_context_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Add attribute"
                                                                        action:@selector(addDOMAttribute:)
                                                                 keyEquivalent:@""]];
+        [_dom_node_tag_context_menu addItem:[Inspector make_create_child_menu]];
         [_dom_node_tag_context_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Delete node"
                                                                        action:@selector(deleteDOMNode:)
                                                                 keyEquivalent:@""]];
@@ -281,6 +310,7 @@ static constexpr NSInteger CONTEXT_MENU_COPY_ATTRIBUTE_VALUE_TAG = 3;
         [_dom_node_attribute_context_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Add attribute"
                                                                              action:@selector(addDOMAttribute:)
                                                                       keyEquivalent:@""]];
+        [_dom_node_attribute_context_menu addItem:[Inspector make_create_child_menu]];
         [_dom_node_attribute_context_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Delete node"
                                                                              action:@selector(deleteDOMNode:)
                                                                       keyEquivalent:@""]];

+ 12 - 0
Ladybird/Qt/InspectorWidget.cpp

@@ -36,6 +36,12 @@ InspectorWidget::InspectorWidget(QWidget* tab, WebContentView& content_view)
     m_screenshot_node_action = new QAction("Take node &screenshot", this);
     connect(m_screenshot_node_action, &QAction::triggered, [this]() { m_inspector_client->context_menu_screenshot_dom_node(); });
 
+    m_create_child_element_action = new QAction("Create child &element", this);
+    connect(m_create_child_element_action, &QAction::triggered, [this]() { m_inspector_client->context_menu_create_child_element(); });
+
+    m_create_child_text_node_action = new QAction("Create child &text node", this);
+    connect(m_create_child_text_node_action, &QAction::triggered, [this]() { m_inspector_client->context_menu_create_child_text_node(); });
+
     m_delete_node_action = new QAction("&Delete node", this);
     connect(m_delete_node_action, &QAction::triggered, [this]() { m_inspector_client->context_menu_remove_dom_node(); });
 
@@ -54,10 +60,15 @@ InspectorWidget::InspectorWidget(QWidget* tab, WebContentView& content_view)
     m_dom_node_text_context_menu->addSeparator();
     m_dom_node_text_context_menu->addAction(m_delete_node_action);
 
+    auto* create_child_menu = new QMenu("Create child", this);
+    create_child_menu->addAction(m_create_child_element_action);
+    create_child_menu->addAction(m_create_child_text_node_action);
+
     m_dom_node_tag_context_menu = new QMenu("DOM tag context menu", this);
     m_dom_node_tag_context_menu->addAction(m_edit_node_action);
     m_dom_node_tag_context_menu->addSeparator();
     m_dom_node_tag_context_menu->addAction(m_add_attribute_action);
+    m_dom_node_tag_context_menu->addMenu(create_child_menu);
     m_dom_node_tag_context_menu->addAction(m_delete_node_action);
     m_dom_node_tag_context_menu->addSeparator();
     m_dom_node_tag_context_menu->addAction(m_copy_node_action);
@@ -69,6 +80,7 @@ InspectorWidget::InspectorWidget(QWidget* tab, WebContentView& content_view)
     m_dom_node_attribute_context_menu->addAction(m_remove_attribute_action);
     m_dom_node_attribute_context_menu->addSeparator();
     m_dom_node_attribute_context_menu->addAction(m_add_attribute_action);
+    m_dom_node_attribute_context_menu->addMenu(create_child_menu);
     m_dom_node_attribute_context_menu->addAction(m_delete_node_action);
     m_dom_node_attribute_context_menu->addSeparator();
     m_dom_node_attribute_context_menu->addAction(m_copy_node_action);

+ 2 - 0
Ladybird/Qt/InspectorWidget.h

@@ -46,6 +46,8 @@ private:
     QAction* m_edit_node_action { nullptr };
     QAction* m_copy_node_action { nullptr };
     QAction* m_screenshot_node_action { nullptr };
+    QAction* m_create_child_element_action { nullptr };
+    QAction* m_create_child_text_node_action { nullptr };
     QAction* m_delete_node_action { nullptr };
     QAction* m_add_attribute_action { nullptr };
     QAction* m_remove_attribute_action { nullptr };

+ 10 - 0
Userland/Applications/Browser/InspectorWidget.cpp

@@ -32,11 +32,19 @@ InspectorWidget::InspectorWidget(WebView::OutOfProcessWebView& content_view)
     m_edit_node_action = GUI::Action::create("&Edit node"sv, [this](auto&) { m_inspector_client->context_menu_edit_dom_node(); });
     m_copy_node_action = GUI::Action::create("&Copy HTML"sv, [this](auto&) { m_inspector_client->context_menu_copy_dom_node(); });
     m_screenshot_node_action = GUI::Action::create("Take node &screenshot"sv, [this](auto&) { m_inspector_client->context_menu_screenshot_dom_node(); });
+    m_create_child_element_action = GUI::Action::create("Create child &element"sv, [this](auto&) { m_inspector_client->context_menu_create_child_element(); });
+    m_create_child_text_node_action = GUI::Action::create("Create child &text node"sv, [this](auto&) { m_inspector_client->context_menu_create_child_text_node(); });
     m_delete_node_action = GUI::Action::create("&Delete node"sv, [this](auto&) { m_inspector_client->context_menu_remove_dom_node(); });
     m_add_attribute_action = GUI::Action::create("&Add attribute"sv, [this](auto&) { m_inspector_client->context_menu_add_dom_node_attribute(); });
     m_remove_attribute_action = GUI::Action::create("&Remove attribute"sv, [this](auto&) { m_inspector_client->context_menu_remove_dom_node_attribute(); });
     m_copy_attribute_value_action = GUI::Action::create("Copy attribute &value"sv, [this](auto&) { m_inspector_client->context_menu_copy_dom_node_attribute_value(); });
 
+    auto add_create_child_menu = [&](auto& menu) {
+        auto create_child_menu = menu.add_submenu("Create child"_string);
+        create_child_menu->add_action(*m_create_child_element_action);
+        create_child_menu->add_action(*m_create_child_text_node_action);
+    };
+
     m_dom_node_text_context_menu = GUI::Menu::construct();
     m_dom_node_text_context_menu->add_action(*m_edit_node_action);
     m_dom_node_text_context_menu->add_action(*m_copy_node_action);
@@ -47,6 +55,7 @@ InspectorWidget::InspectorWidget(WebView::OutOfProcessWebView& content_view)
     m_dom_node_tag_context_menu->add_action(*m_edit_node_action);
     m_dom_node_tag_context_menu->add_separator();
     m_dom_node_tag_context_menu->add_action(*m_add_attribute_action);
+    add_create_child_menu(*m_dom_node_tag_context_menu);
     m_dom_node_tag_context_menu->add_action(*m_delete_node_action);
     m_dom_node_tag_context_menu->add_separator();
     m_dom_node_tag_context_menu->add_action(*m_copy_node_action);
@@ -58,6 +67,7 @@ InspectorWidget::InspectorWidget(WebView::OutOfProcessWebView& content_view)
     m_dom_node_attribute_context_menu->add_action(*m_remove_attribute_action);
     m_dom_node_attribute_context_menu->add_separator();
     m_dom_node_attribute_context_menu->add_action(*m_add_attribute_action);
+    add_create_child_menu(*m_dom_node_attribute_context_menu);
     m_dom_node_attribute_context_menu->add_action(*m_delete_node_action);
     m_dom_node_attribute_context_menu->add_separator();
     m_dom_node_attribute_context_menu->add_action(*m_copy_node_action);

+ 2 - 0
Userland/Applications/Browser/InspectorWidget.h

@@ -42,6 +42,8 @@ private:
     RefPtr<GUI::Action> m_edit_node_action;
     RefPtr<GUI::Action> m_copy_node_action;
     RefPtr<GUI::Action> m_screenshot_node_action;
+    RefPtr<GUI::Action> m_create_child_element_action;
+    RefPtr<GUI::Action> m_create_child_text_node_action;
     RefPtr<GUI::Action> m_delete_node_action;
     RefPtr<GUI::Action> m_add_attribute_action;
     RefPtr<GUI::Action> m_remove_attribute_action;

+ 20 - 0
Userland/Libraries/LibWebView/InspectorClient.cpp

@@ -254,6 +254,26 @@ void InspectorClient::context_menu_screenshot_dom_node()
     m_context_menu_data.clear();
 }
 
+void InspectorClient::context_menu_create_child_element()
+{
+    VERIFY(m_context_menu_data.has_value());
+
+    m_pending_selection = m_content_web_view.create_child_element(m_context_menu_data->dom_node_id);
+    inspect();
+
+    m_context_menu_data.clear();
+}
+
+void InspectorClient::context_menu_create_child_text_node()
+{
+    VERIFY(m_context_menu_data.has_value());
+
+    m_pending_selection = m_content_web_view.create_child_text_node(m_context_menu_data->dom_node_id);
+    inspect();
+
+    m_context_menu_data.clear();
+}
+
 void InspectorClient::context_menu_remove_dom_node()
 {
     VERIFY(m_context_menu_data.has_value());

+ 2 - 0
Userland/Libraries/LibWebView/InspectorClient.h

@@ -29,6 +29,8 @@ public:
     void context_menu_edit_dom_node();
     void context_menu_copy_dom_node();
     void context_menu_screenshot_dom_node();
+    void context_menu_create_child_element();
+    void context_menu_create_child_text_node();
     void context_menu_remove_dom_node();
     void context_menu_add_dom_node_attribute();
     void context_menu_remove_dom_node_attribute();