OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "core/page/CustomContextMenuProvider.h" | |
6 | |
7 #include "core/dom/Document.h" | |
8 #include "core/dom/ElementTraversal.h" | |
9 #include "core/events/EventDispatcher.h" | |
10 #include "core/events/MouseEvent.h" | |
11 #include "core/html/HTMLMenuElement.h" | |
12 #include "core/html/HTMLMenuItemElement.h" | |
13 #include "core/page/ContextMenuController.h" | |
14 #include "core/page/Page.h" | |
15 #include "platform/ContextMenu.h" | |
16 | |
17 namespace blink { | |
18 | |
19 using namespace HTMLNames; | |
20 | |
21 CustomContextMenuProvider::CustomContextMenuProvider(HTMLMenuElement& menu, | |
22 HTMLElement& subject) | |
23 : menu_(menu), subject_element_(subject) {} | |
24 | |
25 CustomContextMenuProvider::~CustomContextMenuProvider() {} | |
26 | |
27 DEFINE_TRACE(CustomContextMenuProvider) { | |
28 visitor->Trace(menu_); | |
29 visitor->Trace(subject_element_); | |
30 visitor->Trace(menu_items_); | |
31 ContextMenuProvider::Trace(visitor); | |
32 } | |
33 | |
34 void CustomContextMenuProvider::PopulateContextMenu(ContextMenu* menu) { | |
35 PopulateContextMenuItems(*menu_, *menu); | |
36 } | |
37 | |
38 void CustomContextMenuProvider::ContextMenuItemSelected( | |
39 const ContextMenuItem* item) { | |
40 if (HTMLElement* element = MenuItemAt(item->Action())) { | |
41 MouseEvent* click = MouseEvent::Create( | |
42 EventTypeNames::click, menu_->GetDocument().domWindow(), | |
43 Event::Create(), SimulatedClickCreationScope::kFromUserAgent); | |
44 click->SetRelatedTarget(subject_element_.Get()); | |
45 element->DispatchEvent(click); | |
46 } | |
47 } | |
48 | |
49 void CustomContextMenuProvider::ContextMenuCleared() { | |
50 menu_items_.clear(); | |
51 subject_element_ = nullptr; | |
52 } | |
53 | |
54 void CustomContextMenuProvider::AppendSeparator(ContextMenu& context_menu) { | |
55 // Avoid separators at the start of any menu and submenu. | |
56 if (!context_menu.Items().size()) | |
57 return; | |
58 | |
59 // Collapse all sequences of two or more adjacent separators in the menu or | |
60 // any submenus to a single separator. | |
61 ContextMenuItem last_item = context_menu.Items().back(); | |
62 if (last_item.GetType() == kSeparatorType) | |
63 return; | |
64 | |
65 context_menu.AppendItem(ContextMenuItem( | |
66 kSeparatorType, kContextMenuItemCustomTagNoAction, String(), String())); | |
67 } | |
68 | |
69 void CustomContextMenuProvider::AppendMenuItem(HTMLMenuItemElement* menu_item, | |
70 ContextMenu& context_menu) { | |
71 // Avoid menuitems with no label. | |
72 String label_string = menu_item->label(); | |
73 if (label_string.IsEmpty()) | |
74 return; | |
75 | |
76 menu_items_.push_back(menu_item); | |
77 | |
78 bool enabled = !menu_item->FastHasAttribute(disabledAttr); | |
79 String icon = menu_item->FastGetAttribute(iconAttr); | |
80 if (!icon.IsEmpty()) { | |
81 // To obtain the absolute URL of the icon when the attribute's value is not | |
82 // the empty string, the attribute's value must be resolved relative to the | |
83 // element. | |
84 KURL icon_url = KURL(menu_item->baseURI(), icon); | |
85 icon = icon_url.GetString(); | |
86 } | |
87 ContextMenuAction action = static_cast<ContextMenuAction>( | |
88 kContextMenuItemBaseCustomTag + menu_items_.size() - 1); | |
89 if (DeprecatedEqualIgnoringCase(menu_item->FastGetAttribute(typeAttr), | |
90 "checkbox") || | |
91 DeprecatedEqualIgnoringCase(menu_item->FastGetAttribute(typeAttr), | |
92 "radio")) | |
93 context_menu.AppendItem( | |
94 ContextMenuItem(kCheckableActionType, action, label_string, icon, | |
95 enabled, menu_item->FastHasAttribute(checkedAttr))); | |
96 else | |
97 context_menu.AppendItem(ContextMenuItem(kActionType, action, label_string, | |
98 icon, enabled, false)); | |
99 } | |
100 | |
101 void CustomContextMenuProvider::PopulateContextMenuItems( | |
102 const HTMLMenuElement& menu, | |
103 ContextMenu& context_menu) { | |
104 HTMLElement* next_element = Traversal<HTMLElement>::FirstWithin(menu); | |
105 while (next_element) { | |
106 if (isHTMLHRElement(*next_element)) { | |
107 AppendSeparator(context_menu); | |
108 next_element = Traversal<HTMLElement>::Next(*next_element, &menu); | |
109 } else if (isHTMLMenuElement(*next_element)) { | |
110 ContextMenu sub_menu; | |
111 String label_string = next_element->FastGetAttribute(labelAttr); | |
112 if (label_string.IsNull()) { | |
113 AppendSeparator(context_menu); | |
114 PopulateContextMenuItems(*toHTMLMenuElement(next_element), | |
115 context_menu); | |
116 AppendSeparator(context_menu); | |
117 } else if (!label_string.IsEmpty()) { | |
118 PopulateContextMenuItems(*toHTMLMenuElement(next_element), sub_menu); | |
119 context_menu.AppendItem( | |
120 ContextMenuItem(kSubmenuType, kContextMenuItemCustomTagNoAction, | |
121 label_string, String(), &sub_menu)); | |
122 } | |
123 next_element = Traversal<HTMLElement>::NextSibling(*next_element); | |
124 } else if (isHTMLMenuItemElement(*next_element)) { | |
125 AppendMenuItem(toHTMLMenuItemElement(next_element), context_menu); | |
126 if (kContextMenuItemBaseCustomTag + menu_items_.size() >= | |
127 kContextMenuItemLastCustomTag) | |
128 break; | |
129 next_element = Traversal<HTMLElement>::Next(*next_element, &menu); | |
130 } else { | |
131 next_element = Traversal<HTMLElement>::Next(*next_element, &menu); | |
132 } | |
133 } | |
134 | |
135 // Remove separators at the end of the menu and any submenus. | |
136 while (context_menu.Items().size() && | |
137 context_menu.Items().back().GetType() == kSeparatorType) | |
138 context_menu.RemoveLastItem(); | |
139 } | |
140 | |
141 HTMLElement* CustomContextMenuProvider::MenuItemAt(unsigned menu_id) { | |
142 int item_index = menu_id - kContextMenuItemBaseCustomTag; | |
143 if (item_index < 0 || | |
144 static_cast<unsigned long>(item_index) >= menu_items_.size()) | |
145 return nullptr; | |
146 return menu_items_[item_index].Get(); | |
147 } | |
148 | |
149 } // namespace blink | |
OLD | NEW |