Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(145)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/ui/SoftContextMenu.js

Issue 2466123002: DevTools: reformat front-end code to match chromium style. (Closed)
Patch Set: all done Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2011 Google Inc. All Rights Reserved. 2 * Copyright (C) 2011 Google Inc. All Rights Reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * 12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */ 24 */
25
26 /** 25 /**
27 * @constructor 26 * @unrestricted
28 * @param {!Array.<!InspectorFrontendHostAPI.ContextMenuDescriptor>} items
29 * @param {function(string)} itemSelectedCallback
30 * @param {!WebInspector.SoftContextMenu=} parentMenu
31 */ 27 */
32 WebInspector.SoftContextMenu = function(items, itemSelectedCallback, parentMenu) 28 WebInspector.SoftContextMenu = class {
33 { 29 /**
30 * @param {!Array.<!InspectorFrontendHostAPI.ContextMenuDescriptor>} items
31 * @param {function(string)} itemSelectedCallback
32 * @param {!WebInspector.SoftContextMenu=} parentMenu
33 */
34 constructor(items, itemSelectedCallback, parentMenu) {
34 this._items = items; 35 this._items = items;
35 this._itemSelectedCallback = itemSelectedCallback; 36 this._itemSelectedCallback = itemSelectedCallback;
36 this._parentMenu = parentMenu; 37 this._parentMenu = parentMenu;
38 }
39
40 /**
41 * @param {!Document} document
42 * @param {number} x
43 * @param {number} y
44 */
45 show(document, x, y) {
46 if (!this._items.length)
47 return;
48
49 this._document = document;
50 this._x = x;
51 this._y = y;
52 this._time = new Date().getTime();
53
54 // Create context menu.
55 this.element = createElementWithClass('div', 'soft-context-menu');
56 var root = WebInspector.createShadowRootWithCoreStyles(this.element, 'ui/sof tContextMenu.css');
57 this._contextMenuElement = root.createChild('div');
58 this.element.style.top = y + 'px';
59 var subMenuOverlap = 3;
60 this.element.style.left = (this._parentMenu ? x - subMenuOverlap : x) + 'px' ;
61
62 this._contextMenuElement.tabIndex = 0;
63 this._contextMenuElement.addEventListener('mouseup', (e) => e.consume(), fal se);
64 this._contextMenuElement.addEventListener('keydown', this._menuKeyDown.bind( this), false);
65
66 for (var i = 0; i < this._items.length; ++i)
67 this._contextMenuElement.appendChild(this._createMenuItem(this._items[i])) ;
68
69 // Install glass pane capturing events.
70 if (!this._parentMenu) {
71 this._glassPaneElement = createElementWithClass('div', 'soft-context-menu- glass-pane fill');
72 this._glassPaneElement.tabIndex = 0;
73 this._glassPaneElement.style.zIndex = '20000';
74 this._glassPaneElement.addEventListener('mouseup', this._glassPaneMouseUp. bind(this), false);
75 this._glassPaneElement.appendChild(this.element);
76 document.body.appendChild(this._glassPaneElement);
77 this._discardMenuOnResizeListener = this._discardMenu.bind(this, true);
78 document.defaultView.addEventListener('resize', this._discardMenuOnResizeL istener, false);
79 } else {
80 this._parentMenu._parentGlassPaneElement().appendChild(this.element);
81 }
82
83 // Re-position menu in case it does not fit.
84 if (document.body.offsetWidth < this.element.offsetLeft + this.element.offse tWidth) {
85 this.element.style.left =
86 Math.max(
87 WebInspector.Dialog.modalHostView().element.totalOffsetLeft(), thi s._parentMenu ?
88 this._parentMenu.element.offsetLeft - this.element.offsetWidth + subMenuOverlap :
89 document.body.offsetWidth - this.element.offsetWidth) +
90 'px';
91 }
92
93 // Move submenus upwards if it does not fit.
94 if (this._parentMenu && document.body.offsetHeight < this.element.offsetTop + this.element.offsetHeight) {
95 y = Math.max(
96 WebInspector.Dialog.modalHostView().element.totalOffsetTop(),
97 document.body.offsetHeight - this.element.offsetHeight);
98 this.element.style.top = y + 'px';
99 }
100
101 var maxHeight = WebInspector.Dialog.modalHostView().element.offsetHeight;
102 maxHeight -= y - WebInspector.Dialog.modalHostView().element.totalOffsetTop( );
103 this.element.style.maxHeight = maxHeight + 'px';
104
105 this._focus();
106 }
107
108 discard() {
109 this._discardMenu(true);
110 }
111
112 _parentGlassPaneElement() {
113 if (this._glassPaneElement)
114 return this._glassPaneElement;
115 if (this._parentMenu)
116 return this._parentMenu._parentGlassPaneElement();
117 return null;
118 }
119
120 _createMenuItem(item) {
121 if (item.type === 'separator')
122 return this._createSeparator();
123
124 if (item.type === 'subMenu')
125 return this._createSubMenu(item);
126
127 var menuItemElement = createElementWithClass('div', 'soft-context-menu-item' );
128 var checkMarkElement = menuItemElement.createChild('div', 'checkmark');
129 if (!item.checked)
130 checkMarkElement.style.opacity = '0';
131
132 if (item.element) {
133 var wrapper = menuItemElement.createChild('div', 'soft-context-menu-custom -item');
134 wrapper.appendChild(item.element);
135 menuItemElement._isCustom = true;
136 return menuItemElement;
137 }
138
139 if (!item.enabled)
140 menuItemElement.classList.add('soft-context-menu-disabled');
141 menuItemElement.createTextChild(item.label);
142 menuItemElement.createChild('span', 'soft-context-menu-shortcut').textConten t = item.shortcut;
143
144 menuItemElement.addEventListener('mousedown', this._menuItemMouseDown.bind(t his), false);
145 menuItemElement.addEventListener('mouseup', this._menuItemMouseUp.bind(this) , false);
146
147 // Manually manage hover highlight since :hover does not work in case of cli ck-and-hold menu invocation.
148 menuItemElement.addEventListener('mouseover', this._menuItemMouseOver.bind(t his), false);
149 menuItemElement.addEventListener('mouseleave', this._menuItemMouseLeave.bind (this), false);
150
151 menuItemElement._actionId = item.id;
152 return menuItemElement;
153 }
154
155 _createSubMenu(item) {
156 var menuItemElement = createElementWithClass('div', 'soft-context-menu-item' );
157 menuItemElement._subItems = item.subItems;
158
159 // Occupy the same space on the left in all items.
160 var checkMarkElement = menuItemElement.createChild('span', 'soft-context-men u-item-checkmark checkmark');
161 checkMarkElement.textContent = '\u2713 '; // Checkmark Unicode symbol
162 checkMarkElement.style.opacity = '0';
163
164 menuItemElement.createTextChild(item.label);
165
166 var subMenuArrowElement = menuItemElement.createChild('span', 'soft-context- menu-item-submenu-arrow');
167 subMenuArrowElement.textContent = '\u25B6'; // BLACK RIGHT-POINTING TRIANGL E
168
169 menuItemElement.addEventListener('mousedown', this._menuItemMouseDown.bind(t his), false);
170 menuItemElement.addEventListener('mouseup', this._menuItemMouseUp.bind(this) , false);
171
172 // Manually manage hover highlight since :hover does not work in case of cli ck-and-hold menu invocation.
173 menuItemElement.addEventListener('mouseover', this._menuItemMouseOver.bind(t his), false);
174 menuItemElement.addEventListener('mouseleave', this._menuItemMouseLeave.bind (this), false);
175
176 return menuItemElement;
177 }
178
179 _createSeparator() {
180 var separatorElement = createElementWithClass('div', 'soft-context-menu-sepa rator');
181 separatorElement._isSeparator = true;
182 separatorElement.createChild('div', 'separator-line');
183 return separatorElement;
184 }
185
186 _menuItemMouseDown(event) {
187 // Do not let separator's mouse down hit menu's handler - we need to receive mouse up!
188 event.consume(true);
189 }
190
191 _menuItemMouseUp(event) {
192 this._triggerAction(event.target, event);
193 event.consume();
194 }
195
196 _focus() {
197 this._contextMenuElement.focus();
198 }
199
200 _triggerAction(menuItemElement, event) {
201 if (!menuItemElement._subItems) {
202 this._discardMenu(true, event);
203 if (typeof menuItemElement._actionId !== 'undefined') {
204 this._itemSelectedCallback(menuItemElement._actionId);
205 delete menuItemElement._actionId;
206 }
207 return;
208 }
209
210 this._showSubMenu(menuItemElement);
211 event.consume();
212 }
213
214 _showSubMenu(menuItemElement) {
215 if (menuItemElement._subMenuTimer) {
216 clearTimeout(menuItemElement._subMenuTimer);
217 delete menuItemElement._subMenuTimer;
218 }
219 if (this._subMenu)
220 return;
221
222 this._subMenu = new WebInspector.SoftContextMenu(menuItemElement._subItems, this._itemSelectedCallback, this);
223 var topPadding = 4;
224 this._subMenu.show(
225 this._document, menuItemElement.totalOffsetLeft() + menuItemElement.offs etWidth,
226 menuItemElement.totalOffsetTop() - 1 - topPadding);
227 }
228
229 _hideSubMenu() {
230 if (!this._subMenu)
231 return;
232 this._subMenu._discardSubMenus();
233 this._focus();
234 }
235
236 _menuItemMouseOver(event) {
237 this._highlightMenuItem(event.target, true);
238 }
239
240 _menuItemMouseLeave(event) {
241 if (!this._subMenu || !event.relatedTarget) {
242 this._highlightMenuItem(null, true);
243 return;
244 }
245
246 var relatedTarget = event.relatedTarget;
247 if (relatedTarget.classList.contains('soft-context-menu-glass-pane'))
248 this._highlightMenuItem(null, true);
249 }
250
251 /**
252 * @param {?Element} menuItemElement
253 * @param {boolean} scheduleSubMenu
254 */
255 _highlightMenuItem(menuItemElement, scheduleSubMenu) {
256 if (this._highlightedMenuItemElement === menuItemElement)
257 return;
258
259 this._hideSubMenu();
260 if (this._highlightedMenuItemElement) {
261 this._highlightedMenuItemElement.classList.remove('soft-context-menu-item- mouse-over');
262 if (this._highlightedMenuItemElement._subItems && this._highlightedMenuIte mElement._subMenuTimer) {
263 clearTimeout(this._highlightedMenuItemElement._subMenuTimer);
264 delete this._highlightedMenuItemElement._subMenuTimer;
265 }
266 }
267 this._highlightedMenuItemElement = menuItemElement;
268 if (this._highlightedMenuItemElement) {
269 this._highlightedMenuItemElement.classList.add('soft-context-menu-item-mou se-over');
270 this._contextMenuElement.focus();
271 if (scheduleSubMenu && this._highlightedMenuItemElement._subItems &&
272 !this._highlightedMenuItemElement._subMenuTimer)
273 this._highlightedMenuItemElement._subMenuTimer =
274 setTimeout(this._showSubMenu.bind(this, this._highlightedMenuItemEle ment), 150);
275 }
276 }
277
278 _highlightPrevious() {
279 var menuItemElement = this._highlightedMenuItemElement ? this._highlightedMe nuItemElement.previousSibling :
280 this._contextMenuEl ement.lastChild;
281 while (menuItemElement && (menuItemElement._isSeparator || menuItemElement._ isCustom))
282 menuItemElement = menuItemElement.previousSibling;
283 if (menuItemElement)
284 this._highlightMenuItem(menuItemElement, false);
285 }
286
287 _highlightNext() {
288 var menuItemElement = this._highlightedMenuItemElement ? this._highlightedMe nuItemElement.nextSibling :
289 this._contextMenuEl ement.firstChild;
290 while (menuItemElement && (menuItemElement._isSeparator || menuItemElement._ isCustom))
291 menuItemElement = menuItemElement.nextSibling;
292 if (menuItemElement)
293 this._highlightMenuItem(menuItemElement, false);
294 }
295
296 _menuKeyDown(event) {
297 switch (event.key) {
298 case 'ArrowUp':
299 this._highlightPrevious();
300 break;
301 case 'ArrowDown':
302 this._highlightNext();
303 break;
304 case 'ArrowLeft':
305 if (this._parentMenu) {
306 this._highlightMenuItem(null, false);
307 this._parentMenu._hideSubMenu();
308 }
309 break;
310 case 'ArrowRight':
311 if (!this._highlightedMenuItemElement)
312 break;
313 if (this._highlightedMenuItemElement._subItems) {
314 this._showSubMenu(this._highlightedMenuItemElement);
315 this._subMenu._focus();
316 this._subMenu._highlightNext();
317 }
318 break;
319 case 'Escape':
320 this._discardMenu(false, event);
321 break;
322 case 'Enter':
323 if (!isEnterKey(event))
324 break;
325 // Fall through
326 case ' ': // Space
327 if (this._highlightedMenuItemElement)
328 this._triggerAction(this._highlightedMenuItemElement, event);
329 if (this._highlightedMenuItemElement._subItems) {
330 this._subMenu._focus();
331 this._subMenu._highlightNext();
332 }
333 break;
334 }
335 event.consume(true);
336 }
337
338 _glassPaneMouseUp(event) {
339 // Return if this is simple 'click', since dispatched on glass pane, can't u se 'click' event.
340 if (new Date().getTime() - this._time < 300)
341 return;
342 if (event.target === this.element)
343 return;
344 this._discardMenu(true, event);
345 event.consume();
346 }
347
348 /**
349 * @param {boolean} closeParentMenus
350 * @param {!Event=} event
351 */
352 _discardMenu(closeParentMenus, event) {
353 if (this._subMenu && !closeParentMenus)
354 return;
355 if (this._glassPaneElement) {
356 var glassPane = this._glassPaneElement;
357 delete this._glassPaneElement;
358 // This can re-enter discardMenu due to blur.
359 this._document.body.removeChild(glassPane);
360 if (this._parentMenu) {
361 delete this._parentMenu._subMenu;
362 if (closeParentMenus)
363 this._parentMenu._discardMenu(closeParentMenus, event);
364 else
365 this._parentMenu._focus();
366 }
367
368 if (event)
369 event.consume(true);
370 } else if (this._parentMenu && this._contextMenuElement.parentElementOrShado wHost()) {
371 this._discardSubMenus();
372 if (closeParentMenus)
373 this._parentMenu._discardMenu(closeParentMenus, event);
374 else
375 this._parentMenu._focus();
376 if (event)
377 event.consume(true);
378 }
379 if (this._discardMenuOnResizeListener) {
380 this._document.defaultView.removeEventListener('resize', this._discardMenu OnResizeListener, false);
381 delete this._discardMenuOnResizeListener;
382 }
383 }
384
385 _discardSubMenus() {
386 if (this._subMenu)
387 this._subMenu._discardSubMenus();
388 if (this.element)
389 this.element.remove();
390 if (this._parentMenu)
391 delete this._parentMenu._subMenu;
392 }
37 }; 393 };
38
39 WebInspector.SoftContextMenu.prototype = {
40 /**
41 * @param {!Document} document
42 * @param {number} x
43 * @param {number} y
44 */
45 show: function(document, x, y)
46 {
47 if (!this._items.length)
48 return;
49
50 this._document = document;
51 this._x = x;
52 this._y = y;
53 this._time = new Date().getTime();
54
55 // Create context menu.
56 this.element = createElementWithClass("div", "soft-context-menu");
57 var root = WebInspector.createShadowRootWithCoreStyles(this.element, "ui /softContextMenu.css");
58 this._contextMenuElement = root.createChild("div");
59 this.element.style.top = y + "px";
60 var subMenuOverlap = 3;
61 this.element.style.left = (this._parentMenu ? x - subMenuOverlap : x) + "px";
62
63 this._contextMenuElement.tabIndex = 0;
64 this._contextMenuElement.addEventListener("mouseup", (e) => e.consume(), false);
65 this._contextMenuElement.addEventListener("keydown", this._menuKeyDown.b ind(this), false);
66
67 for (var i = 0; i < this._items.length; ++i)
68 this._contextMenuElement.appendChild(this._createMenuItem(this._item s[i]));
69
70 // Install glass pane capturing events.
71 if (!this._parentMenu) {
72 this._glassPaneElement = createElementWithClass("div", "soft-context -menu-glass-pane fill");
73 this._glassPaneElement.tabIndex = 0;
74 this._glassPaneElement.style.zIndex = "20000";
75 this._glassPaneElement.addEventListener("mouseup", this._glassPaneMo useUp.bind(this), false);
76 this._glassPaneElement.appendChild(this.element);
77 document.body.appendChild(this._glassPaneElement);
78 this._discardMenuOnResizeListener = this._discardMenu.bind(this, tru e);
79 document.defaultView.addEventListener("resize", this._discardMenuOnR esizeListener, false);
80 } else {
81 this._parentMenu._parentGlassPaneElement().appendChild(this.element) ;
82 }
83
84 // Re-position menu in case it does not fit.
85 if (document.body.offsetWidth < this.element.offsetLeft + this.element.o ffsetWidth) {
86 this.element.style.left = Math.max(WebInspector.Dialog.modalHostView ().element.totalOffsetLeft(), this._parentMenu
87 ? this._parentMenu.element.offsetLeft - this.element.offsetWidth + subMenuOverlap
88 : document.body.offsetWidth - this.element.offsetWidth) + "px";
89 }
90
91 // Move submenus upwards if it does not fit.
92 if (this._parentMenu && document.body.offsetHeight < this.element.offset Top + this.element.offsetHeight) {
93 y = Math.max(WebInspector.Dialog.modalHostView().element.totalOffset Top(), document.body.offsetHeight - this.element.offsetHeight);
94 this.element.style.top = y + "px";
95 }
96
97 var maxHeight = WebInspector.Dialog.modalHostView().element.offsetHeight ;
98 maxHeight -= y - WebInspector.Dialog.modalHostView().element.totalOffset Top();
99 this.element.style.maxHeight = maxHeight + "px";
100
101 this._focus();
102 },
103
104 discard: function()
105 {
106 this._discardMenu(true);
107 },
108
109 _parentGlassPaneElement: function()
110 {
111 if (this._glassPaneElement)
112 return this._glassPaneElement;
113 if (this._parentMenu)
114 return this._parentMenu._parentGlassPaneElement();
115 return null;
116 },
117
118 _createMenuItem: function(item)
119 {
120 if (item.type === "separator")
121 return this._createSeparator();
122
123 if (item.type === "subMenu")
124 return this._createSubMenu(item);
125
126 var menuItemElement = createElementWithClass("div", "soft-context-menu-i tem");
127 var checkMarkElement = menuItemElement.createChild("div", "checkmark");
128 if (!item.checked)
129 checkMarkElement.style.opacity = "0";
130
131 if (item.element) {
132 var wrapper = menuItemElement.createChild("div", "soft-context-menu- custom-item");
133 wrapper.appendChild(item.element);
134 menuItemElement._isCustom = true;
135 return menuItemElement;
136 }
137
138 if (!item.enabled)
139 menuItemElement.classList.add("soft-context-menu-disabled");
140 menuItemElement.createTextChild(item.label);
141 menuItemElement.createChild("span", "soft-context-menu-shortcut").textCo ntent = item.shortcut;
142
143 menuItemElement.addEventListener("mousedown", this._menuItemMouseDown.bi nd(this), false);
144 menuItemElement.addEventListener("mouseup", this._menuItemMouseUp.bind(t his), false);
145
146 // Manually manage hover highlight since :hover does not work in case of click-and-hold menu invocation.
147 menuItemElement.addEventListener("mouseover", this._menuItemMouseOver.bi nd(this), false);
148 menuItemElement.addEventListener("mouseleave", this._menuItemMouseLeave. bind(this), false);
149
150 menuItemElement._actionId = item.id;
151 return menuItemElement;
152 },
153
154 _createSubMenu: function(item)
155 {
156 var menuItemElement = createElementWithClass("div", "soft-context-menu-i tem");
157 menuItemElement._subItems = item.subItems;
158
159 // Occupy the same space on the left in all items.
160 var checkMarkElement = menuItemElement.createChild("span", "soft-context -menu-item-checkmark checkmark");
161 checkMarkElement.textContent = "\u2713 "; // Checkmark Unicode symbol
162 checkMarkElement.style.opacity = "0";
163
164 menuItemElement.createTextChild(item.label);
165
166 var subMenuArrowElement = menuItemElement.createChild("span", "soft-cont ext-menu-item-submenu-arrow");
167 subMenuArrowElement.textContent = "\u25B6"; // BLACK RIGHT-POINTING TRIA NGLE
168
169 menuItemElement.addEventListener("mousedown", this._menuItemMouseDown.bi nd(this), false);
170 menuItemElement.addEventListener("mouseup", this._menuItemMouseUp.bind(t his), false);
171
172 // Manually manage hover highlight since :hover does not work in case of click-and-hold menu invocation.
173 menuItemElement.addEventListener("mouseover", this._menuItemMouseOver.bi nd(this), false);
174 menuItemElement.addEventListener("mouseleave", this._menuItemMouseLeave. bind(this), false);
175
176 return menuItemElement;
177 },
178
179 _createSeparator: function()
180 {
181 var separatorElement = createElementWithClass("div", "soft-context-menu- separator");
182 separatorElement._isSeparator = true;
183 separatorElement.createChild("div", "separator-line");
184 return separatorElement;
185 },
186
187 _menuItemMouseDown: function(event)
188 {
189 // Do not let separator's mouse down hit menu's handler - we need to rec eive mouse up!
190 event.consume(true);
191 },
192
193 _menuItemMouseUp: function(event)
194 {
195 this._triggerAction(event.target, event);
196 event.consume();
197 },
198
199 _focus: function()
200 {
201 this._contextMenuElement.focus();
202 },
203
204 _triggerAction: function(menuItemElement, event)
205 {
206 if (!menuItemElement._subItems) {
207 this._discardMenu(true, event);
208 if (typeof menuItemElement._actionId !== "undefined") {
209 this._itemSelectedCallback(menuItemElement._actionId);
210 delete menuItemElement._actionId;
211 }
212 return;
213 }
214
215 this._showSubMenu(menuItemElement);
216 event.consume();
217 },
218
219 _showSubMenu: function(menuItemElement)
220 {
221 if (menuItemElement._subMenuTimer) {
222 clearTimeout(menuItemElement._subMenuTimer);
223 delete menuItemElement._subMenuTimer;
224 }
225 if (this._subMenu)
226 return;
227
228 this._subMenu = new WebInspector.SoftContextMenu(menuItemElement._subIte ms, this._itemSelectedCallback, this);
229 var topPadding = 4;
230 this._subMenu.show(this._document, menuItemElement.totalOffsetLeft() + m enuItemElement.offsetWidth, menuItemElement.totalOffsetTop() - 1 - topPadding);
231 },
232
233 _hideSubMenu: function()
234 {
235 if (!this._subMenu)
236 return;
237 this._subMenu._discardSubMenus();
238 this._focus();
239 },
240
241 _menuItemMouseOver: function(event)
242 {
243 this._highlightMenuItem(event.target, true);
244 },
245
246 _menuItemMouseLeave: function(event)
247 {
248 if (!this._subMenu || !event.relatedTarget) {
249 this._highlightMenuItem(null, true);
250 return;
251 }
252
253 var relatedTarget = event.relatedTarget;
254 if (relatedTarget.classList.contains("soft-context-menu-glass-pane"))
255 this._highlightMenuItem(null, true);
256 },
257
258 /**
259 * @param {?Element} menuItemElement
260 * @param {boolean} scheduleSubMenu
261 */
262 _highlightMenuItem: function(menuItemElement, scheduleSubMenu)
263 {
264 if (this._highlightedMenuItemElement === menuItemElement)
265 return;
266
267 this._hideSubMenu();
268 if (this._highlightedMenuItemElement) {
269 this._highlightedMenuItemElement.classList.remove("soft-context-menu -item-mouse-over");
270 if (this._highlightedMenuItemElement._subItems && this._highlightedM enuItemElement._subMenuTimer) {
271 clearTimeout(this._highlightedMenuItemElement._subMenuTimer);
272 delete this._highlightedMenuItemElement._subMenuTimer;
273 }
274 }
275 this._highlightedMenuItemElement = menuItemElement;
276 if (this._highlightedMenuItemElement) {
277 this._highlightedMenuItemElement.classList.add("soft-context-menu-it em-mouse-over");
278 this._contextMenuElement.focus();
279 if (scheduleSubMenu && this._highlightedMenuItemElement._subItems && !this._highlightedMenuItemElement._subMenuTimer)
280 this._highlightedMenuItemElement._subMenuTimer = setTimeout(this ._showSubMenu.bind(this, this._highlightedMenuItemElement), 150);
281 }
282 },
283
284 _highlightPrevious: function()
285 {
286 var menuItemElement = this._highlightedMenuItemElement ? this._highlight edMenuItemElement.previousSibling : this._contextMenuElement.lastChild;
287 while (menuItemElement && (menuItemElement._isSeparator || menuItemEleme nt._isCustom))
288 menuItemElement = menuItemElement.previousSibling;
289 if (menuItemElement)
290 this._highlightMenuItem(menuItemElement, false);
291 },
292
293 _highlightNext: function()
294 {
295 var menuItemElement = this._highlightedMenuItemElement ? this._highlight edMenuItemElement.nextSibling : this._contextMenuElement.firstChild;
296 while (menuItemElement && (menuItemElement._isSeparator || menuItemEleme nt._isCustom))
297 menuItemElement = menuItemElement.nextSibling;
298 if (menuItemElement)
299 this._highlightMenuItem(menuItemElement, false);
300 },
301
302 _menuKeyDown: function(event)
303 {
304 switch (event.key) {
305 case "ArrowUp":
306 this._highlightPrevious(); break;
307 case "ArrowDown":
308 this._highlightNext(); break;
309 case "ArrowLeft":
310 if (this._parentMenu) {
311 this._highlightMenuItem(null, false);
312 this._parentMenu._hideSubMenu();
313 }
314 break;
315 case "ArrowRight":
316 if (!this._highlightedMenuItemElement)
317 break;
318 if (this._highlightedMenuItemElement._subItems) {
319 this._showSubMenu(this._highlightedMenuItemElement);
320 this._subMenu._focus();
321 this._subMenu._highlightNext();
322 }
323 break;
324 case "Escape":
325 this._discardMenu(false, event); break;
326 case "Enter":
327 if (!isEnterKey(event))
328 break;
329 // Fall through
330 case " ": // Space
331 if (this._highlightedMenuItemElement)
332 this._triggerAction(this._highlightedMenuItemElement, event);
333 if (this._highlightedMenuItemElement._subItems) {
334 this._subMenu._focus();
335 this._subMenu._highlightNext();
336 }
337 break;
338 }
339 event.consume(true);
340 },
341
342 _glassPaneMouseUp: function(event)
343 {
344 // Return if this is simple 'click', since dispatched on glass pane, can 't use 'click' event.
345 if (new Date().getTime() - this._time < 300)
346 return;
347 if (event.target === this.element)
348 return;
349 this._discardMenu(true, event);
350 event.consume();
351 },
352
353 /**
354 * @param {boolean} closeParentMenus
355 * @param {!Event=} event
356 */
357 _discardMenu: function(closeParentMenus, event)
358 {
359 if (this._subMenu && !closeParentMenus)
360 return;
361 if (this._glassPaneElement) {
362 var glassPane = this._glassPaneElement;
363 delete this._glassPaneElement;
364 // This can re-enter discardMenu due to blur.
365 this._document.body.removeChild(glassPane);
366 if (this._parentMenu) {
367 delete this._parentMenu._subMenu;
368 if (closeParentMenus)
369 this._parentMenu._discardMenu(closeParentMenus, event);
370 else
371 this._parentMenu._focus();
372 }
373
374 if (event)
375 event.consume(true);
376 } else if (this._parentMenu && this._contextMenuElement.parentElementOrS hadowHost()) {
377 this._discardSubMenus();
378 if (closeParentMenus)
379 this._parentMenu._discardMenu(closeParentMenus, event);
380 else
381 this._parentMenu._focus();
382 if (event)
383 event.consume(true);
384 }
385 if (this._discardMenuOnResizeListener) {
386 this._document.defaultView.removeEventListener("resize", this._disca rdMenuOnResizeListener, false);
387 delete this._discardMenuOnResizeListener;
388 }
389 },
390
391 _discardSubMenus: function()
392 {
393 if (this._subMenu)
394 this._subMenu._discardSubMenus();
395 if (this.element)
396 this.element.remove();
397 if (this._parentMenu)
398 delete this._parentMenu._subMenu;
399 }
400 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698