| Index: third_party/WebKit/Source/devtools/front_end/ui/GlassPane.js
|
| diff --git a/third_party/WebKit/Source/devtools/front_end/ui/GlassPane.js b/third_party/WebKit/Source/devtools/front_end/ui/GlassPane.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..22669c0b970aedb1c8b778d94c0d7a61ce5eb3fa
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/devtools/front_end/ui/GlassPane.js
|
| @@ -0,0 +1,220 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +UI.GlassPane = class {
|
| + /**
|
| + * @param {!Document} document
|
| + * @param {boolean} dimmed
|
| + * @param {boolean} blockPointerEvents
|
| + */
|
| + constructor(document, dimmed, blockPointerEvents) {
|
| + this.element = createElementWithClass('div', 'glass-pane');
|
| + this.element.style.backgroundColor = dimmed ? 'rgba(255, 255, 255, 0.5)' : 'transparent';
|
| + if (!blockPointerEvents)
|
| + this.element.style.pointerEvents = 'none';
|
| +
|
| + this._document = document;
|
| + /** @type {?Element} */
|
| + this._contentElement = null;
|
| + this._visible = false;
|
| + /** @type {?UI.Size} */
|
| + this._maxSize = null;
|
| + /** @type {?number} */
|
| + this._positionX = null;
|
| + /** @type {?number} */
|
| + this._positionY = null;
|
| + /** @type {?AnchorBox} */
|
| + this._anchorBox = null;
|
| + this._anchorBehavior = UI.GlassPane.AnchorBehavior.PreferTop;
|
| + }
|
| +
|
| + /**
|
| + * @param {?Element} contentElement
|
| + */
|
| + setContentElement(contentElement) {
|
| + if (this._contentElement) {
|
| + this._contentElement.classList.remove('glass-pane-content');
|
| + if (this._visible)
|
| + this.element.removeChild(this._contentElement);
|
| + }
|
| + this._contentElement = contentElement;
|
| + if (this._contentElement) {
|
| + this._contentElement.classList.add('glass-pane-content');
|
| + if (this._visible)
|
| + this.element.appendChild(this._contentElement);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @param {?UI.Size} size
|
| + */
|
| + setMaxContentSize(size) {
|
| + this._maxSize = size;
|
| + }
|
| +
|
| + /**
|
| + * @param {?number} x
|
| + * @param {?number} y
|
| + * Position is relative to root element.
|
| + */
|
| + setContentPosition(x, y) {
|
| + this._positionX = x;
|
| + this._positionY = y;
|
| + }
|
| +
|
| + /**
|
| + * @param {?AnchorBox} anchorBox
|
| + * Anchor box is relative to the document.
|
| + */
|
| + setAnchorBox(anchorBox) {
|
| + this._anchorBox = anchorBox;
|
| + }
|
| +
|
| + /**
|
| + * @param {!UI.GlassPane.AnchorBehavior} behavior
|
| + */
|
| + setAnchorBehavior(behavior) {
|
| + this._anchorBehavior = behavior;
|
| + }
|
| +
|
| + show() {
|
| + if (this._visible)
|
| + return;
|
| + this._visible = true;
|
| + // Deliberately starts with 3000 to hide other z-indexed elements below.
|
| + this.element.style.zIndex = 3000 + 1000 * UI.GlassPane._panes.size;
|
| + this._document.body.appendChild(this.element);
|
| + if (this._contentElement)
|
| + this.element.appendChild(this._contentElement);
|
| + UI.GlassPane._panes.add(this);
|
| + }
|
| +
|
| + hide() {
|
| + if (!this._visible)
|
| + return;
|
| + UI.GlassPane._panes.delete(this);
|
| + if (this._contentElement)
|
| + this.element.removeChild(this._contentElement);
|
| + this._document.body.removeChild(this.element);
|
| + this._visible = false;
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + visible() {
|
| + return this._visible;
|
| + }
|
| +
|
| + positionContent() {
|
| + if (!this._visible || !this._contentElement)
|
| + return;
|
| +
|
| + var gutterSize = 5;
|
| + var container = UI.GlassPane._containers.get(this._document);
|
| + var containerWidth = container.offsetWidth;
|
| + var containerHeight = container.offsetHeight;
|
| +
|
| + var width = containerWidth - gutterSize * 2;
|
| + var height = containerHeight - gutterSize * 2;
|
| + var positionX = gutterSize;
|
| + var positionY = gutterSize;
|
| +
|
| + if (this._maxSize) {
|
| + width = Math.min(width, this._maxSize.width);
|
| + height = Math.min(height, this._maxSize.height);
|
| + }
|
| +
|
| + if (this._anchorBox) {
|
| + var anchorBox = this._anchorBox.relativeToElement(container);
|
| + var behavior = this._anchorBehavior;
|
| +
|
| + if (behavior === UI.GlassPane.AnchorBehavior.PreferTop || behavior === UI.GlassPane.AnchorBehavior.PreferBottom) {
|
| + var top = anchorBox.y - gutterSize;
|
| + var bottom = containerHeight - anchorBox.y - anchorBox.height - gutterSize;
|
| + if (behavior === UI.GlassPane.AnchorBehavior.PreferTop && top < height && bottom >= height)
|
| + behavior = UI.GlassPane.AnchorBehavior.PreferBottom;
|
| + if (behavior === UI.GlassPane.AnchorBehavior.PreferBottom && bottom < height && top >= height)
|
| + behavior = UI.GlassPane.AnchorBehavior.PreferTop;
|
| +
|
| + positionX = Math.max(gutterSize, Math.min(anchorBox.x, containerWidth - width - gutterSize));
|
| + width = Math.min(width, containerWidth - positionX - gutterSize);
|
| + if (behavior === UI.GlassPane.AnchorBehavior.PreferTop) {
|
| + positionY = Math.max(gutterSize, anchorBox.y - height);
|
| + height = Math.min(height, anchorBox.y - positionY);
|
| + } else {
|
| + positionY = anchorBox.y + anchorBox.height;
|
| + height = Math.min(height, containerHeight - positionY - gutterSize);
|
| + }
|
| + } else {
|
| + var left = anchorBox.x - gutterSize;
|
| + var right = containerWidth - anchorBox.x - anchorBox.width - gutterSize;
|
| + if (behavior === UI.GlassPane.AnchorBehavior.PreferLeft && left < width && right >= width)
|
| + behavior = UI.GlassPane.AnchorBehavior.PreferRight;
|
| + if (behavior === UI.GlassPane.AnchorBehavior.PreferRight && right < width && left >= width)
|
| + behavior = UI.GlassPane.AnchorBehavior.PreferLeft;
|
| +
|
| + positionY = Math.max(gutterSize, Math.min(anchorBox.y, containerHeight - height - gutterSize));
|
| + height = Math.min(height, containerHeight - positionY - gutterSize);
|
| + if (behavior === UI.GlassPane.AnchorBehavior.PreferLeft) {
|
| + positionX = Math.max(gutterSize, anchorBox.x - width);
|
| + width = Math.min(width, anchorBox.x - positionX);
|
| + } else {
|
| + positionX = anchorBox.x + anchorBox.width;
|
| + width = Math.min(width, containerWidth - positionX - gutterSize);
|
| + }
|
| + }
|
| + } else {
|
| + positionX = this._positionX !== null ? this._positionX : (containerWidth - width) / 2;
|
| + positionY = this._positionY !== null ? this._positionY : (containerHeight - height) / 2;
|
| + width = Math.min(width, containerWidth - positionX - gutterSize);
|
| + height = Math.min(height, containerHeight - positionY - gutterSize);
|
| + }
|
| +
|
| + this._contentElement.style.width = width + 'px';
|
| + this._contentElement.style.height = height + 'px';
|
| + this._contentElement.positionAt(positionX, positionY, container);
|
| + }
|
| +
|
| + /**
|
| + * @param {!Element} element
|
| + */
|
| + static setContainer(element) {
|
| + UI.GlassPane._containers.set(/** @type {!Document} */ (element.ownerDocument), element);
|
| + UI.GlassPane.containerMoved(element);
|
| + }
|
| +
|
| + /**
|
| + * @param {!Document} document
|
| + * @return {!Element}
|
| + */
|
| + static container(document) {
|
| + return UI.GlassPane._containers.get(document);
|
| + }
|
| +
|
| + /**
|
| + * @param {!Element} element
|
| + */
|
| + static containerMoved(element) {
|
| + for (var pane of UI.GlassPane._panes) {
|
| + if (pane._document === element.ownerDocument)
|
| + pane.positionContent();
|
| + }
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * @enum {symbol}
|
| + */
|
| +UI.GlassPane.AnchorBehavior = {
|
| + PreferTop: Symbol('PreferTop'),
|
| + PreferBottom: Symbol('PreferBottom'),
|
| + PreferLeft: Symbol('PreferLeft'),
|
| + PreferRight: Symbol('PreferRight'),
|
| +};
|
| +
|
| +/** @type {!Map<!Document, !Element>} */
|
| +UI.GlassPane._containers = new Map();
|
| +/** @type {!Set<!UI.GlassPane>} */
|
| +UI.GlassPane._panes = new Set();
|
|
|