diff --git a/Ladybird/AppKit/UI/Inspector.mm b/Ladybird/AppKit/UI/Inspector.mm index ce9084a1f1..3e633c2c13 100644 --- a/Ladybird/AppKit/UI/Inspector.mm +++ b/Ladybird/AppKit/UI/Inspector.mm @@ -7,9 +7,11 @@ #include #include +#import #import #import #import +#import #if !__has_feature(objc_arc) # error "This project requires ARC" @@ -18,6 +20,9 @@ static constexpr CGFloat const WINDOW_WIDTH = 875; static constexpr CGFloat const WINDOW_HEIGHT = 825; +static constexpr NSInteger CONTEXT_MENU_EDIT_NODE_TAG = 1; +static constexpr NSInteger CONTEXT_MENU_REMOVE_ATTRIBUTE_TAG = 2; + @interface Inspector () { OwnPtr m_inspector_client; @@ -25,11 +30,18 @@ static constexpr CGFloat const WINDOW_HEIGHT = 825; @property (nonatomic, strong) Tab* tab; +@property (nonatomic, strong) NSMenu* dom_node_text_context_menu; +@property (nonatomic, strong) NSMenu* dom_node_tag_context_menu; +@property (nonatomic, strong) NSMenu* dom_node_attribute_context_menu; + @end @implementation Inspector @synthesize tab = _tab; +@synthesize dom_node_text_context_menu = _dom_node_text_context_menu; +@synthesize dom_node_tag_context_menu = _dom_node_tag_context_menu; +@synthesize dom_node_attribute_context_menu = _dom_node_attribute_context_menu; - (instancetype)init:(Tab*)tab { @@ -52,6 +64,51 @@ static constexpr CGFloat const WINDOW_HEIGHT = 825; [self.web_view setPostsBoundsChangedNotifications:YES]; m_inspector_client = make([[tab web_view] view], [[self web_view] view]); + __weak Inspector* weak_self = self; + + m_inspector_client->on_requested_dom_node_text_context_menu = [weak_self](auto position) { + Inspector* strong_self = weak_self; + if (strong_self == nil) { + return; + } + + auto* event = Ladybird::create_context_menu_mouse_event(strong_self.web_view, position); + [NSMenu popUpContextMenu:strong_self.dom_node_text_context_menu withEvent:event forView:strong_self.web_view]; + }; + + m_inspector_client->on_requested_dom_node_tag_context_menu = [weak_self](auto position, auto const& tag) { + Inspector* strong_self = weak_self; + if (strong_self == nil) { + return; + } + + auto edit_node_text = MUST(String::formatted("Edit \"{}\"", tag)); + + auto* edit_node_menu_item = [strong_self.dom_node_tag_context_menu itemWithTag:CONTEXT_MENU_EDIT_NODE_TAG]; + [edit_node_menu_item setTitle:Ladybird::string_to_ns_string(edit_node_text)]; + + auto* event = Ladybird::create_context_menu_mouse_event(strong_self.web_view, position); + [NSMenu popUpContextMenu:strong_self.dom_node_tag_context_menu withEvent:event forView:strong_self.web_view]; + }; + + m_inspector_client->on_requested_dom_node_attribute_context_menu = [weak_self](auto position, auto const& attribute) { + Inspector* strong_self = weak_self; + if (strong_self == nil) { + return; + } + + auto edit_attribute_text = MUST(String::formatted("Edit attribute \"{}\"", attribute)); + auto remove_attribute_text = MUST(String::formatted("Remove attribute \"{}\"", attribute)); + + auto* edit_node_menu_item = [strong_self.dom_node_attribute_context_menu itemWithTag:CONTEXT_MENU_EDIT_NODE_TAG]; + [edit_node_menu_item setTitle:Ladybird::string_to_ns_string(edit_attribute_text)]; + + auto* remove_attribute_menu_item = [strong_self.dom_node_attribute_context_menu itemWithTag:CONTEXT_MENU_REMOVE_ATTRIBUTE_TAG]; + [remove_attribute_menu_item setTitle:Ladybird::string_to_ns_string(remove_attribute_text)]; + + auto* event = Ladybird::create_context_menu_mouse_event(strong_self.web_view, position); + [NSMenu popUpContextMenu:strong_self.dom_node_attribute_context_menu withEvent:event forView:strong_self.web_view]; + }; auto* scroll_view = [[NSScrollView alloc] init]; [scroll_view setHasVerticalScroller:YES]; @@ -92,4 +149,101 @@ static constexpr CGFloat const WINDOW_HEIGHT = 825; m_inspector_client->select_hovered_node(); } +#pragma mark - Private methods + +- (void)editDOMNode:(id)sender +{ + m_inspector_client->context_menu_edit_dom_node(); +} + +- (void)deleteDOMNode:(id)sender +{ + m_inspector_client->context_menu_remove_dom_node(); +} + +- (void)addDOMAttribute:(id)sender +{ + m_inspector_client->context_menu_add_dom_node_attribute(); +} + +- (void)removeDOMAttribute:(id)sender +{ + m_inspector_client->context_menu_remove_dom_node_attribute(); +} + +#pragma mark - Properties + +- (NSMenu*)dom_node_text_context_menu +{ + if (!_dom_node_text_context_menu) { + _dom_node_text_context_menu = [[NSMenu alloc] initWithTitle:@"DOM Text Context Menu"]; + + [_dom_node_text_context_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Edit text" + action:@selector(editDOMNode:) + keyEquivalent:@""]]; + + [_dom_node_text_context_menu addItem:[NSMenuItem separatorItem]]; + + [_dom_node_text_context_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Delete node" + action:@selector(deleteDOMNode:) + keyEquivalent:@""]]; + } + + return _dom_node_text_context_menu; +} + +- (NSMenu*)dom_node_tag_context_menu +{ + if (!_dom_node_tag_context_menu) { + _dom_node_tag_context_menu = [[NSMenu alloc] initWithTitle:@"DOM Tag Context Menu"]; + + auto* edit_node_menu_item = [[NSMenuItem alloc] initWithTitle:@"Edit tag" + action:@selector(editDOMNode:) + keyEquivalent:@""]; + [edit_node_menu_item setTag:CONTEXT_MENU_EDIT_NODE_TAG]; + [_dom_node_tag_context_menu addItem:edit_node_menu_item]; + + [_dom_node_tag_context_menu addItem:[NSMenuItem separatorItem]]; + + [_dom_node_tag_context_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Add attribute" + action:@selector(addDOMAttribute:) + keyEquivalent:@""]]; + [_dom_node_tag_context_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Delete node" + action:@selector(deleteDOMNode:) + keyEquivalent:@""]]; + } + + return _dom_node_tag_context_menu; +} + +- (NSMenu*)dom_node_attribute_context_menu +{ + if (!_dom_node_attribute_context_menu) { + _dom_node_attribute_context_menu = [[NSMenu alloc] initWithTitle:@"DOM Attribute Context Menu"]; + + auto* edit_node_menu_item = [[NSMenuItem alloc] initWithTitle:@"Edit attribute" + action:@selector(editDOMNode:) + keyEquivalent:@""]; + [edit_node_menu_item setTag:CONTEXT_MENU_EDIT_NODE_TAG]; + [_dom_node_attribute_context_menu addItem:edit_node_menu_item]; + + auto* remove_attribute_menu_item = [[NSMenuItem alloc] initWithTitle:@"Remove attribute" + action:@selector(removeDOMAttribute:) + keyEquivalent:@""]; + [remove_attribute_menu_item setTag:CONTEXT_MENU_REMOVE_ATTRIBUTE_TAG]; + [_dom_node_attribute_context_menu addItem:remove_attribute_menu_item]; + + [_dom_node_attribute_context_menu addItem:[NSMenuItem separatorItem]]; + + [_dom_node_attribute_context_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Add attribute" + action:@selector(addDOMAttribute:) + keyEquivalent:@""]]; + [_dom_node_attribute_context_menu addItem:[[NSMenuItem alloc] initWithTitle:@"Delete node" + action:@selector(deleteDOMNode:) + keyEquivalent:@""]]; + } + + return _dom_node_attribute_context_menu; +} + @end