OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 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 UI.GlassPane = class { |
| 6 /** |
| 7 * @param {!Document} document |
| 8 * @param {boolean} dimmed |
| 9 * @param {boolean} blockPointerEvents |
| 10 */ |
| 11 constructor(document, dimmed, blockPointerEvents) { |
| 12 this.element = createElementWithClass('div', 'glass-pane'); |
| 13 this.element.style.backgroundColor = dimmed ? 'rgba(255, 255, 255, 0.5)' : '
transparent'; |
| 14 if (!blockPointerEvents) |
| 15 this.element.style.pointerEvents = 'none'; |
| 16 |
| 17 this._document = document; |
| 18 /** @type {?Element} */ |
| 19 this._contentElement = null; |
| 20 this._visible = false; |
| 21 /** @type {?UI.Size} */ |
| 22 this._maxSize = null; |
| 23 /** @type {?number} */ |
| 24 this._positionX = null; |
| 25 /** @type {?number} */ |
| 26 this._positionY = null; |
| 27 /** @type {?AnchorBox} */ |
| 28 this._anchorBox = null; |
| 29 this._anchorBehavior = UI.GlassPane.AnchorBehavior.PreferTop; |
| 30 } |
| 31 |
| 32 /** |
| 33 * @param {?Element} contentElement |
| 34 */ |
| 35 setContentElement(contentElement) { |
| 36 if (this._contentElement) { |
| 37 this._contentElement.classList.remove('glass-pane-content'); |
| 38 if (this._visible) |
| 39 this.element.removeChild(this._contentElement); |
| 40 } |
| 41 this._contentElement = contentElement; |
| 42 if (this._contentElement) { |
| 43 this._contentElement.classList.add('glass-pane-content'); |
| 44 if (this._visible) |
| 45 this.element.appendChild(this._contentElement); |
| 46 } |
| 47 } |
| 48 |
| 49 /** |
| 50 * @param {?UI.Size} size |
| 51 */ |
| 52 setMaxContentSize(size) { |
| 53 this._maxSize = size; |
| 54 } |
| 55 |
| 56 /** |
| 57 * @param {?number} x |
| 58 * @param {?number} y |
| 59 * Position is relative to root element. |
| 60 */ |
| 61 setContentPosition(x, y) { |
| 62 this._positionX = x; |
| 63 this._positionY = y; |
| 64 } |
| 65 |
| 66 /** |
| 67 * @param {?AnchorBox} anchorBox |
| 68 * Anchor box is relative to the document. |
| 69 */ |
| 70 setAnchorBox(anchorBox) { |
| 71 this._anchorBox = anchorBox; |
| 72 } |
| 73 |
| 74 /** |
| 75 * @param {!UI.GlassPane.AnchorBehavior} behavior |
| 76 */ |
| 77 setAnchorBehavior(behavior) { |
| 78 this._anchorBehavior = behavior; |
| 79 } |
| 80 |
| 81 show() { |
| 82 if (this._visible) |
| 83 return; |
| 84 this._visible = true; |
| 85 // Deliberately starts with 3000 to hide other z-indexed elements below. |
| 86 this.element.style.zIndex = 3000 + 1000 * UI.GlassPane._panes.size; |
| 87 this._document.body.appendChild(this.element); |
| 88 if (this._contentElement) |
| 89 this.element.appendChild(this._contentElement); |
| 90 UI.GlassPane._panes.add(this); |
| 91 } |
| 92 |
| 93 hide() { |
| 94 if (!this._visible) |
| 95 return; |
| 96 UI.GlassPane._panes.delete(this); |
| 97 if (this._contentElement) |
| 98 this.element.removeChild(this._contentElement); |
| 99 this._document.body.removeChild(this.element); |
| 100 this._visible = false; |
| 101 } |
| 102 |
| 103 /** |
| 104 * @return {boolean} |
| 105 */ |
| 106 visible() { |
| 107 return this._visible; |
| 108 } |
| 109 |
| 110 positionContent() { |
| 111 if (!this._visible || !this._contentElement) |
| 112 return; |
| 113 |
| 114 var gutterSize = 5; |
| 115 var container = UI.GlassPane._containers.get(this._document); |
| 116 var containerWidth = container.offsetWidth; |
| 117 var containerHeight = container.offsetHeight; |
| 118 |
| 119 var width = containerWidth - gutterSize * 2; |
| 120 var height = containerHeight - gutterSize * 2; |
| 121 var positionX = gutterSize; |
| 122 var positionY = gutterSize; |
| 123 |
| 124 if (this._maxSize) { |
| 125 width = Math.min(width, this._maxSize.width); |
| 126 height = Math.min(height, this._maxSize.height); |
| 127 } |
| 128 |
| 129 if (this._anchorBox) { |
| 130 var anchorBox = this._anchorBox.relativeToElement(container); |
| 131 var behavior = this._anchorBehavior; |
| 132 |
| 133 if (behavior === UI.GlassPane.AnchorBehavior.PreferTop || behavior === UI.
GlassPane.AnchorBehavior.PreferBottom) { |
| 134 var top = anchorBox.y - gutterSize; |
| 135 var bottom = containerHeight - anchorBox.y - anchorBox.height - gutterSi
ze; |
| 136 if (behavior === UI.GlassPane.AnchorBehavior.PreferTop && top < height &
& bottom >= height) |
| 137 behavior = UI.GlassPane.AnchorBehavior.PreferBottom; |
| 138 if (behavior === UI.GlassPane.AnchorBehavior.PreferBottom && bottom < he
ight && top >= height) |
| 139 behavior = UI.GlassPane.AnchorBehavior.PreferTop; |
| 140 |
| 141 positionX = Math.max(gutterSize, Math.min(anchorBox.x, containerWidth -
width - gutterSize)); |
| 142 width = Math.min(width, containerWidth - positionX - gutterSize); |
| 143 if (behavior === UI.GlassPane.AnchorBehavior.PreferTop) { |
| 144 positionY = Math.max(gutterSize, anchorBox.y - height); |
| 145 height = Math.min(height, anchorBox.y - positionY); |
| 146 } else { |
| 147 positionY = anchorBox.y + anchorBox.height; |
| 148 height = Math.min(height, containerHeight - positionY - gutterSize); |
| 149 } |
| 150 } else { |
| 151 var left = anchorBox.x - gutterSize; |
| 152 var right = containerWidth - anchorBox.x - anchorBox.width - gutterSize; |
| 153 if (behavior === UI.GlassPane.AnchorBehavior.PreferLeft && left < width
&& right >= width) |
| 154 behavior = UI.GlassPane.AnchorBehavior.PreferRight; |
| 155 if (behavior === UI.GlassPane.AnchorBehavior.PreferRight && right < widt
h && left >= width) |
| 156 behavior = UI.GlassPane.AnchorBehavior.PreferLeft; |
| 157 |
| 158 positionY = Math.max(gutterSize, Math.min(anchorBox.y, containerHeight -
height - gutterSize)); |
| 159 height = Math.min(height, containerHeight - positionY - gutterSize); |
| 160 if (behavior === UI.GlassPane.AnchorBehavior.PreferLeft) { |
| 161 positionX = Math.max(gutterSize, anchorBox.x - width); |
| 162 width = Math.min(width, anchorBox.x - positionX); |
| 163 } else { |
| 164 positionX = anchorBox.x + anchorBox.width; |
| 165 width = Math.min(width, containerWidth - positionX - gutterSize); |
| 166 } |
| 167 } |
| 168 } else { |
| 169 positionX = this._positionX !== null ? this._positionX : (containerWidth -
width) / 2; |
| 170 positionY = this._positionY !== null ? this._positionY : (containerHeight
- height) / 2; |
| 171 width = Math.min(width, containerWidth - positionX - gutterSize); |
| 172 height = Math.min(height, containerHeight - positionY - gutterSize); |
| 173 } |
| 174 |
| 175 this._contentElement.style.width = width + 'px'; |
| 176 this._contentElement.style.height = height + 'px'; |
| 177 this._contentElement.positionAt(positionX, positionY, container); |
| 178 } |
| 179 |
| 180 /** |
| 181 * @param {!Element} element |
| 182 */ |
| 183 static setContainer(element) { |
| 184 UI.GlassPane._containers.set(/** @type {!Document} */ (element.ownerDocument
), element); |
| 185 UI.GlassPane.containerMoved(element); |
| 186 } |
| 187 |
| 188 /** |
| 189 * @param {!Document} document |
| 190 * @return {!Element} |
| 191 */ |
| 192 static container(document) { |
| 193 return UI.GlassPane._containers.get(document); |
| 194 } |
| 195 |
| 196 /** |
| 197 * @param {!Element} element |
| 198 */ |
| 199 static containerMoved(element) { |
| 200 for (var pane of UI.GlassPane._panes) { |
| 201 if (pane._document === element.ownerDocument) |
| 202 pane.positionContent(); |
| 203 } |
| 204 } |
| 205 }; |
| 206 |
| 207 /** |
| 208 * @enum {symbol} |
| 209 */ |
| 210 UI.GlassPane.AnchorBehavior = { |
| 211 PreferTop: Symbol('PreferTop'), |
| 212 PreferBottom: Symbol('PreferBottom'), |
| 213 PreferLeft: Symbol('PreferLeft'), |
| 214 PreferRight: Symbol('PreferRight'), |
| 215 }; |
| 216 |
| 217 /** @type {!Map<!Document, !Element>} */ |
| 218 UI.GlassPane._containers = new Map(); |
| 219 /** @type {!Set<!UI.GlassPane>} */ |
| 220 UI.GlassPane._panes = new Set(); |
OLD | NEW |