Index: third_party/WebKit/Source/devtools/front_end/ui/SoftContextMenu.js |
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/SoftContextMenu.js b/third_party/WebKit/Source/devtools/front_end/ui/SoftContextMenu.js |
index aa43be97ea93d6c8c5b6f32b69a9de822752b784..1f905c91545ae1cd73d2db88ea4479134a4ee13d 100644 |
--- a/third_party/WebKit/Source/devtools/front_end/ui/SoftContextMenu.js |
+++ b/third_party/WebKit/Source/devtools/front_end/ui/SoftContextMenu.js |
@@ -40,28 +40,26 @@ |
/** |
* @param {!Document} document |
- * @param {!AnchorBox} anchorBox |
+ * @param {number} x |
+ * @param {number} y |
*/ |
- show(document, anchorBox) { |
+ show(document, x, y) { |
if (!this._items.length) |
return; |
this._document = document; |
- |
- this._glassPane = new UI.GlassPane(); |
- this._glassPane.setBlockPointerEvents(!this._parentMenu); |
- this._glassPane.setSetOutsideClickCallback(event => { |
- this._discardMenu(true, event); |
- event.consume(); |
- }); |
- this._glassPane.registerRequiredCSS('ui/softContextMenu.css'); |
- this._glassPane.setContentAnchorBox(anchorBox); |
- this._glassPane.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent); |
- this._glassPane.setMarginBehavior(UI.GlassPane.MarginBehavior.NoMargin); |
- this._glassPane.setAnchorBehavior( |
- this._parentMenu ? UI.GlassPane.AnchorBehavior.PreferRight : UI.GlassPane.AnchorBehavior.PreferBottom); |
- |
- this._contextMenuElement = this._glassPane.contentElement.createChild('div', 'soft-context-menu'); |
+ this._x = x; |
+ this._y = y; |
+ this._time = new Date().getTime(); |
+ |
+ // Create context menu. |
+ this.element = createElementWithClass('div', 'soft-context-menu'); |
+ var root = UI.createShadowRootWithCoreStyles(this.element, 'ui/softContextMenu.css'); |
+ this._contextMenuElement = root.createChild('div'); |
+ this.element.style.top = y + 'px'; |
+ var subMenuOverlap = 3; |
+ this.element.style.left = (this._parentMenu ? x - subMenuOverlap : x) + 'px'; |
+ |
this._contextMenuElement.tabIndex = 0; |
this._contextMenuElement.addEventListener('mouseup', e => e.consume(), false); |
this._contextMenuElement.addEventListener('keydown', this._menuKeyDown.bind(this), false); |
@@ -69,12 +67,53 @@ |
for (var i = 0; i < this._items.length; ++i) |
this._contextMenuElement.appendChild(this._createMenuItem(this._items[i])); |
- this._glassPane.show(document); |
+ // Install glass pane capturing events. |
+ if (!this._parentMenu) { |
+ this._glassPaneElement = createElementWithClass('div', 'soft-context-menu-glass-pane fill'); |
+ this._glassPaneElement.tabIndex = 0; |
+ this._glassPaneElement.style.zIndex = '20000'; |
+ this._glassPaneElement.addEventListener('mouseup', this._glassPaneMouseUp.bind(this), false); |
+ this._glassPaneElement.appendChild(this.element); |
+ document.body.appendChild(this._glassPaneElement); |
+ this._discardMenuOnResizeListener = this._discardMenu.bind(this, true); |
+ document.defaultView.addEventListener('resize', this._discardMenuOnResizeListener, false); |
+ } else { |
+ this._parentMenu._parentGlassPaneElement().appendChild(this.element); |
+ } |
+ |
+ // Re-position menu in case it does not fit. |
+ var containerElement = UI.GlassPane.container(document); |
+ var hostLeft = containerElement.totalOffsetLeft(); |
+ var hostRight = hostLeft + containerElement.offsetWidth; |
+ if (hostRight < this.element.offsetLeft + this.element.offsetWidth) { |
+ var left = this._parentMenu ? this._parentMenu.element.offsetLeft - this.element.offsetWidth + subMenuOverlap : |
+ hostRight - this.element.offsetWidth; |
+ this.element.style.left = Math.max(hostLeft, left) + 'px'; |
+ } |
+ |
+ // Move submenus upwards if it does not fit. |
+ if (this._parentMenu && document.body.offsetHeight < this.element.offsetTop + this.element.offsetHeight) { |
+ y = Math.max(containerElement.totalOffsetTop(), document.body.offsetHeight - this.element.offsetHeight); |
+ this.element.style.top = y + 'px'; |
+ } |
+ |
+ var maxHeight = containerElement.offsetHeight; |
+ maxHeight -= y - containerElement.totalOffsetTop(); |
+ this.element.style.maxHeight = maxHeight + 'px'; |
+ |
this._focus(); |
} |
discard() { |
this._discardMenu(true); |
+ } |
+ |
+ _parentGlassPaneElement() { |
+ if (this._glassPaneElement) |
+ return this._glassPaneElement; |
+ if (this._parentMenu) |
+ return this._parentMenu._parentGlassPaneElement(); |
+ return null; |
} |
_createMenuItem(item) { |
@@ -182,13 +221,10 @@ |
return; |
this._subMenu = new UI.SoftContextMenu(menuItemElement._subItems, this._itemSelectedCallback, this); |
- var anchorBox = menuItemElement.boxInWindow(); |
- // Adjust for padding. |
- anchorBox.y -= 5; |
- anchorBox.x += 3; |
- anchorBox.width -= 6; |
- anchorBox.height += 10; |
- this._subMenu.show(this._document, anchorBox); |
+ var topPadding = 4; |
+ this._subMenu.show( |
+ this._document, menuItemElement.totalOffsetLeft() + menuItemElement.offsetWidth, |
+ menuItemElement.totalOffsetTop() - 1 - topPadding); |
} |
_hideSubMenu() { |
@@ -209,7 +245,7 @@ |
} |
var relatedTarget = event.relatedTarget; |
- if (relatedTarget === this._contextMenuElement) |
+ if (relatedTarget.classList.contains('soft-context-menu-glass-pane')) |
this._highlightMenuItem(null, true); |
} |
@@ -303,6 +339,16 @@ |
event.consume(true); |
} |
+ _glassPaneMouseUp(event) { |
+ // Return if this is simple 'click', since dispatched on glass pane, can't use 'click' event. |
+ if (new Date().getTime() - this._time < 300) |
+ return; |
+ if (event.target === this.element) |
+ return; |
+ this._discardMenu(true, event); |
+ event.consume(); |
+ } |
+ |
/** |
* @param {boolean} closeParentMenus |
* @param {!Event=} event |
@@ -310,27 +356,41 @@ |
_discardMenu(closeParentMenus, event) { |
if (this._subMenu && !closeParentMenus) |
return; |
- |
- this._discardSubMenus(); |
- |
- if (this._parentMenu) { |
+ if (this._glassPaneElement) { |
+ var glassPane = this._glassPaneElement; |
+ delete this._glassPaneElement; |
+ // This can re-enter discardMenu due to blur. |
+ this._document.body.removeChild(glassPane); |
+ if (this._parentMenu) { |
+ delete this._parentMenu._subMenu; |
+ if (closeParentMenus) |
+ this._parentMenu._discardMenu(closeParentMenus, event); |
+ else |
+ this._parentMenu._focus(); |
+ } |
+ |
+ if (event) |
+ event.consume(true); |
+ } else if (this._parentMenu && this._contextMenuElement.parentElementOrShadowHost()) { |
+ this._discardSubMenus(); |
if (closeParentMenus) |
this._parentMenu._discardMenu(closeParentMenus, event); |
else |
this._parentMenu._focus(); |
- } |
- |
- if (event) |
- event.consume(true); |
+ if (event) |
+ event.consume(true); |
+ } |
+ if (this._discardMenuOnResizeListener) { |
+ this._document.defaultView.removeEventListener('resize', this._discardMenuOnResizeListener, false); |
+ delete this._discardMenuOnResizeListener; |
+ } |
} |
_discardSubMenus() { |
if (this._subMenu) |
this._subMenu._discardSubMenus(); |
- if (this._glassPane) { |
- this._glassPane.hide(); |
- delete this._glassPane; |
- } |
+ if (this.element) |
+ this.element.remove(); |
if (this._parentMenu) |
delete this._parentMenu._subMenu; |
} |