Skip to content

Commit

Permalink
Reland of [DevTools] Migrate SoftContextMenu to use GlassPane (patchset
Browse files Browse the repository at this point in the history
#1 id:1 of https://codereview.chromium.org/2771413006/ )

Reason for revert:
The regression was fixed in https://codereview.chromium.org/2776263006/

Original issue's description:
> Revert of [DevTools] Migrate SoftContextMenu to use GlassPane (patchset #2 id:20001 of https://codereview.chromium.org/2778623002/ )
>
> Reason for revert:
> Broke DevTools settings
>
> Original issue's description:
> > [DevTools] Migrate SoftContextMenu to use GlassPane
> >
> > Let the GlassPane handle all the tricky details about positioning.
> >
> > BUG=none
>
> [email protected],[email protected]
> # Not skipping CQ checks because original CL landed more than 1 days ago.
> BUG=none
>
> Review-Url: https://codereview.chromium.org/2771413006
> Cr-Commit-Position: refs/heads/master@{#460228}
> Committed: https://chromium.googlesource.com/chromium/src/+/ac4d06a47287a0303deac7879251b476d0de3b46

[email protected],[email protected]
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=none

Review-Url: https://codereview.chromium.org/2790613003
Cr-Commit-Position: refs/heads/master@{#460911}
  • Loading branch information
dgozman authored and Commit bot committed Mar 30, 2017
1 parent 2fbbb11 commit 9d17ac1
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 111 deletions.
2 changes: 1 addition & 1 deletion front_end/inline_editor/SwatchPopoverHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ InlineEditor.SwatchPopoverHelper = class extends Common.Object {
this._popover.registerRequiredCSS('inline_editor/swatchPopover.css');
this._popover.setBlockPointerEvents(false);
this._popover.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent);
this._popover.setShowArrow(true);
this._popover.setMarginBehavior(UI.GlassPane.MarginBehavior.Arrow);
this._popover.element.addEventListener('mousedown', e => e.consume(), false);

this._hideProxy = this.hide.bind(this, true);
Expand Down
2 changes: 1 addition & 1 deletion front_end/ui/ContextMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ UI.ContextMenu = class extends UI.ContextSubMenuItem {
UI._contextMenu = this;
if (this._useSoftMenu || UI.ContextMenu._useSoftMenu || InspectorFrontendHost.isHostedMode()) {
this._softMenu = new UI.SoftContextMenu(menuObject, this._itemSelected.bind(this));
this._softMenu.show(this._event.target.ownerDocument, this._x, this._y);
this._softMenu.show(this._event.target.ownerDocument, new AnchorBox(this._x, this._y, 0, 0));
} else {
InspectorFrontendHost.showContextMenuAtPoint(this._x, this._y, menuObject, this._event.target.ownerDocument);

Expand Down
30 changes: 20 additions & 10 deletions front_end/ui/GlassPane.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ UI.GlassPane = class {
this._anchorBox = null;
this._anchorBehavior = UI.GlassPane.AnchorBehavior.PreferTop;
this._sizeBehavior = UI.GlassPane.SizeBehavior.SetExactSize;
this._showArrow = false;
this._marginBehavior = UI.GlassPane.MarginBehavior.DefaultMargin;
}

/**
Expand Down Expand Up @@ -108,11 +108,11 @@ UI.GlassPane = class {
}

/**
* @param {boolean} showArrow
* @param {boolean} behavior
*/
setShowArrow(showArrow) {
this._showArrow = showArrow;
this._arrowElement.classList.toggle('hidden', !showArrow);
setMarginBehavior(behavior) {
this._marginBehavior = behavior;
this._arrowElement.classList.toggle('hidden', behavior !== UI.GlassPane.MarginBehavior.Arrow);
}

/**
Expand All @@ -123,7 +123,7 @@ UI.GlassPane = class {
return;
// Deliberately starts with 3000 to hide other z-indexed elements below.
this.element.style.zIndex = 3000 + 1000 * UI.GlassPane._panes.size;
document.body.addEventListener('mousedown', this._onMouseDownBound, true);
document.body.addEventListener('click', this._onMouseDownBound, true);
this._widget.show(document.body);
UI.GlassPane._panes.add(this);
this._positionContent();
Expand All @@ -133,7 +133,7 @@ UI.GlassPane = class {
if (!this.isShowing())
return;
UI.GlassPane._panes.delete(this);
this.element.ownerDocument.body.removeEventListener('mousedown', this._onMouseDownBound, true);
this.element.ownerDocument.body.removeEventListener('click', this._onMouseDownBound, true);
this._widget.detach();
}

Expand All @@ -152,7 +152,8 @@ UI.GlassPane = class {
if (!this.isShowing())
return;

var gutterSize = this._showArrow ? 8 : 3;
var showArrow = this._marginBehavior === UI.GlassPane.MarginBehavior.Arrow;
var gutterSize = showArrow ? 8 : (this._marginBehavior === UI.GlassPane.MarginBehavior.NoMargin ? 0 : 3);
var scrollbarSize = 14;
var arrowSize = 10;

Expand Down Expand Up @@ -240,7 +241,7 @@ UI.GlassPane = class {
positionX = Math.max(gutterSize, Math.min(anchorBox.x, containerWidth - width - gutterSize));
if (!enoughHeight)
positionX += arrowSize;
else if (this._showArrow && positionX - arrowSize >= gutterSize)
else if (showArrow && positionX - arrowSize >= gutterSize)
positionX -= arrowSize;
width = Math.min(width, containerWidth - positionX - gutterSize);
if (2 * arrowSize >= width) {
Expand Down Expand Up @@ -298,7 +299,7 @@ UI.GlassPane = class {
positionY = Math.max(gutterSize, Math.min(anchorBox.y, containerHeight - height - gutterSize));
if (!enoughWidth)
positionY += arrowSize;
else if (this._showArrow && positionY - arrowSize >= gutterSize)
else if (showArrow && positionY - arrowSize >= gutterSize)
positionY -= arrowSize;
height = Math.min(height, containerHeight - positionY - gutterSize);
if (2 * arrowSize >= height) {
Expand Down Expand Up @@ -381,6 +382,15 @@ UI.GlassPane.SizeBehavior = {
MeasureContent: Symbol('MeasureContent')
};

/**
* @enum {symbol}
*/
UI.GlassPane.MarginBehavior = {
Arrow: Symbol('Arrow'),
DefaultMargin: Symbol('DefaultMargin'),
NoMargin: Symbol('NoMargin')
};

/** @type {!Map<!Document, !Element>} */
UI.GlassPane._containers = new Map();
/** @type {!Set<!UI.GlassPane>} */
Expand Down
2 changes: 1 addition & 1 deletion front_end/ui/Popover.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ UI.PopoverHelper = class {
popover.registerRequiredCSS('ui/popover.css');
popover.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent);
popover.setBlockPointerEvents(false);
popover.setShowArrow(true);
popover.setMarginBehavior(UI.GlassPane.MarginBehavior.Arrow);
var request = this._scheduledRequest;
request.show.call(null, popover).then(success => {
if (!success)
Expand Down
130 changes: 35 additions & 95 deletions front_end/ui/SoftContextMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,82 +40,43 @@ UI.SoftContextMenu = class {

/**
* @param {!Document} document
* @param {number} x
* @param {number} y
* @param {!AnchorBox} anchorBox
*/
show(document, x, y) {
show(document, anchorBox) {
if (!this._items.length)
return;

this._document = document;
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._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._contextMenuElement.tabIndex = 0;
this._contextMenuElement.addEventListener('mouseup', e => e.consume(), false);
this._contextMenuElement.addEventListener('keydown', this._menuKeyDown.bind(this), false);

for (var i = 0; i < this._items.length; ++i)
this._contextMenuElement.appendChild(this._createMenuItem(this._items[i]));

// 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._glassPane.show(document);
this._focus();
}

discard() {
this._discardMenu(true);
}

_parentGlassPaneElement() {
if (this._glassPaneElement)
return this._glassPaneElement;
if (this._parentMenu)
return this._parentMenu._parentGlassPaneElement();
return null;
}

_createMenuItem(item) {
if (item.type === 'separator')
return this._createSeparator();
Expand Down Expand Up @@ -221,10 +182,13 @@ UI.SoftContextMenu = class {
return;

this._subMenu = new UI.SoftContextMenu(menuItemElement._subItems, this._itemSelectedCallback, this);
var topPadding = 4;
this._subMenu.show(
this._document, menuItemElement.totalOffsetLeft() + menuItemElement.offsetWidth,
menuItemElement.totalOffsetTop() - 1 - topPadding);
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);
}

_hideSubMenu() {
Expand All @@ -245,7 +209,7 @@ UI.SoftContextMenu = class {
}

var relatedTarget = event.relatedTarget;
if (relatedTarget.classList.contains('soft-context-menu-glass-pane'))
if (relatedTarget === this._contextMenuElement)
this._highlightMenuItem(null, true);
}

Expand Down Expand Up @@ -339,58 +303,34 @@ UI.SoftContextMenu = class {
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
*/
_discardMenu(closeParentMenus, event) {
if (this._subMenu && !closeParentMenus)
return;
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();
this._discardSubMenus();

if (this._parentMenu) {
if (closeParentMenus)
this._parentMenu._discardMenu(closeParentMenus, event);
else
this._parentMenu._focus();
if (event)
event.consume(true);
}
if (this._discardMenuOnResizeListener) {
this._document.defaultView.removeEventListener('resize', this._discardMenuOnResizeListener, false);
delete this._discardMenuOnResizeListener;
}

if (event)
event.consume(true);
}

_discardSubMenus() {
if (this._subMenu)
this._subMenu._discardSubMenus();
if (this.element)
this.element.remove();
if (this._glassPane) {
this._glassPane.hide();
delete this._glassPane;
}
if (this._parentMenu)
delete this._parentMenu._subMenu;
}
Expand Down
5 changes: 2 additions & 3 deletions front_end/ui/softContextMenu.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
* found in the LICENSE file.
*/

:host {
position: absolute;
.soft-context-menu {
border: 1px solid rgba(196, 196, 196, 0.9);
border-top: 1px solid rgba(196, 196, 196, 0.5);
/* NOTE: Keep padding top in sync with topPadding in SoftContextMenu.js */
/* NOTE: Keep padding in sync with padding adjustment in SoftContextMenu.js */
padding: 4px 0 4px 0;
border-radius: 4px;
background-color: rgb(240, 240, 240);
Expand Down

0 comments on commit 9d17ac1

Please sign in to comment.