Chromium Code Reviews| 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.ModalOverlay = class { | |
|
pfeldman
2017/01/31 21:30:18
Could you clarify when this is used and how? The m
dgozman
2017/01/31 23:39:49
Updated.
| |
| 6 constructor() { | |
| 7 this.element = createElementWithClass('div', 'modal-overlay'); | |
| 8 this._visible = false; | |
| 9 this._blockPointerEvents = true; | |
| 10 this._dimmed = false; | |
| 11 /** @type {?UI.Size} */ | |
| 12 this._maxSize = null; | |
| 13 /** @type {?number} */ | |
| 14 this._positionX = null; | |
| 15 /** @type {?number} */ | |
| 16 this._positionY = null; | |
| 17 /** @type {?AnchorBox} */ | |
| 18 this._anchorBox = null; | |
| 19 /** @type {?UI.GlassPane} */ | |
| 20 this._glassPane = null; | |
| 21 this._anchorBehavior = UI.ModalOverlay.AnchorBehavior.PreferTop; | |
| 22 } | |
| 23 | |
| 24 /** | |
| 25 * @param {boolean} blockPointerEvents | |
| 26 */ | |
| 27 setBlockPointerEvents(blockPointerEvents) { | |
| 28 this._blockPointerEvents = blockPointerEvents; | |
| 29 } | |
| 30 | |
| 31 /** | |
| 32 * @param {?UI.Size} size | |
| 33 */ | |
| 34 setMaxSize(size) { | |
| 35 this._maxSize = size; | |
| 36 } | |
| 37 | |
| 38 /** | |
| 39 * @param {boolean} dimmed | |
| 40 */ | |
| 41 setDimmed(dimmed) { | |
| 42 this._dimmed = dimmed; | |
| 43 } | |
| 44 | |
| 45 /** | |
| 46 * @param {?number} x | |
| 47 * @param {?number} y | |
| 48 * Position is relative to root element. | |
| 49 */ | |
| 50 setPosition(x, y) { | |
| 51 this._positionX = x; | |
| 52 this._positionY = y; | |
| 53 } | |
| 54 | |
| 55 /** | |
| 56 * @param {?AnchorBox} anchorBox | |
| 57 * Anchor box is relative to the document. | |
| 58 * Showing under anchor if more space. | |
| 59 */ | |
| 60 setAnchorBox(anchorBox) { | |
| 61 this._anchorBox = anchorBox; | |
| 62 } | |
| 63 | |
| 64 /** | |
| 65 * @param {!UI.ModalOverlay.AnchorBehavior} behavior | |
| 66 */ | |
| 67 setAnchorBehavior(behavior) { | |
| 68 this._anchorBehavior = behavior; | |
| 69 } | |
| 70 | |
| 71 /** | |
| 72 * @return {!Document} | |
| 73 */ | |
| 74 document() { | |
| 75 return /** @type {!Document} */ (UI.ModalOverlay._rootElement.ownerDocument) ; | |
| 76 } | |
| 77 | |
| 78 show() { | |
| 79 if (!this._visible) { | |
|
caseq
2017/01/31 21:27:20
nit: if (this._visible) return;
dgozman
2017/01/31 23:39:49
Done.
| |
| 80 this._visible = true; | |
| 81 this._glassPane = new UI.GlassPane(this.document(), this._dimmed, this._bl ockPointerEvents); | |
| 82 this._glassPane.element.appendChild(this.element); | |
| 83 UI.ModalOverlay._overlays.add(this); | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 hide() { | |
| 88 if (!this._visible) | |
| 89 return; | |
| 90 this._visible = false; | |
| 91 this._glassPane.element.removeChild(this.element); | |
| 92 this._glassPane.dispose(); | |
| 93 this._glassPane = null; | |
| 94 UI.ModalOverlay._overlays.delete(this); | |
| 95 } | |
| 96 | |
| 97 /** | |
| 98 * @return {boolean} | |
| 99 */ | |
| 100 visible() { | |
| 101 return this._visible; | |
| 102 } | |
| 103 | |
| 104 /** | |
| 105 * @param {string} eventType | |
| 106 * @param {function(!Event)} listener | |
| 107 * @param {boolean=} capture | |
| 108 */ | |
| 109 addGlassPaneEventListener(eventType, listener, capture) { | |
|
caseq
2017/01/31 21:27:20
should we make the interface simpler by converting
dgozman
2017/01/31 23:39:49
Simplified.
| |
| 110 console.assert(this._visible); | |
| 111 this._glassPane.element.addEventListener(eventType, listener, capture); | |
| 112 } | |
| 113 | |
| 114 /** | |
| 115 * @param {string} eventType | |
| 116 * @param {function(!Event)} listener | |
| 117 * @param {boolean=} capture | |
| 118 */ | |
| 119 removeGlassPaneEventListener(eventType, listener, capture) { | |
| 120 console.assert(this._visible); | |
| 121 this._glassPane.element.removeEventListener(eventType, listener, capture); | |
| 122 } | |
| 123 | |
| 124 position() { | |
| 125 if (!this._visible) | |
| 126 return; | |
| 127 | |
| 128 var gutter = 5; | |
|
caseq
2017/01/31 21:27:20
nit: gutterSize or gutterPixels
dgozman
2017/01/31 23:39:49
Done.
| |
| 129 var container = UI.ModalOverlay._rootElement; | |
| 130 var containerWidth = container.offsetWidth; | |
| 131 var containerHeight = container.offsetHeight; | |
| 132 | |
| 133 var width = containerWidth - gutter * 2; | |
| 134 var height = containerHeight - gutter * 2; | |
| 135 var positionX = gutter; | |
| 136 var positionY = gutter; | |
| 137 | |
| 138 if (this._maxSize) { | |
| 139 width = Math.min(width, this._maxSize.width); | |
| 140 height = Math.min(height, this._maxSize.height); | |
| 141 } | |
| 142 | |
| 143 if (this._anchorBox) { | |
| 144 var anchorBox = this._anchorBox.relativeToElement(container); | |
| 145 var topHeight = anchorBox.y - gutter; | |
| 146 var bottomHeight = containerHeight - anchorBox.y - anchorBox.height - gutt er; | |
| 147 var leftWidth = anchorBox.x - gutter; | |
| 148 var rightWidth = containerWidth - anchorBox.x - anchorBox.width - gutter; | |
|
caseq
2017/01/31 21:27:20
nit: Height/Width looks a bit artificial above. Pe
dgozman
2017/01/31 23:39:49
Reworked.
| |
| 149 | |
| 150 var behavior = this._anchorBehavior; | |
| 151 if (behavior === UI.ModalOverlay.AnchorBehavior.PreferTop && topHeight < h eight && bottomHeight >= height) | |
| 152 behavior = UI.ModalOverlay.AnchorBehavior.PreferBottom; | |
| 153 if (behavior === UI.ModalOverlay.AnchorBehavior.PreferBottom && bottomHeig ht < height && topHeight >= height) | |
| 154 behavior = UI.ModalOverlay.AnchorBehavior.PreferTop; | |
| 155 if (behavior === UI.ModalOverlay.AnchorBehavior.PreferLeft && leftWidth < width && rightWidth >= width) | |
| 156 behavior = UI.ModalOverlay.AnchorBehavior.PreferRight; | |
| 157 if (behavior === UI.ModalOverlay.AnchorBehavior.PreferRight && rightWidth < width && leftWidth >= width) | |
| 158 behavior = UI.ModalOverlay.AnchorBehavior.PreferLeft; | |
| 159 | |
| 160 if (behavior === UI.ModalOverlay.AnchorBehavior.PreferTop || | |
| 161 behavior === UI.ModalOverlay.AnchorBehavior.PreferBottom) { | |
| 162 positionX = Math.max(gutter, Math.min(anchorBox.x, containerWidth - widt h - gutter)); | |
| 163 width = Math.min(width, containerWidth - positionX - gutter); | |
| 164 if (behavior === UI.ModalOverlay.AnchorBehavior.PreferTop) { | |
| 165 positionY = Math.max(gutter, anchorBox.y - height); | |
| 166 height = Math.min(height, anchorBox.y - positionY); | |
| 167 } else { | |
| 168 positionY = anchorBox.y + anchorBox.height; | |
| 169 height = Math.min(height, containerHeight - positionY - gutter); | |
| 170 } | |
| 171 } else { | |
| 172 positionY = Math.max(gutter, Math.min(anchorBox.y, containerHeight - hei ght - gutter)); | |
| 173 height = Math.min(height, containerHeight - positionY - gutter); | |
| 174 if (behavior === UI.ModalOverlay.AnchorBehavior.PreferLeft) { | |
| 175 positionX = Math.max(gutter, anchorBox.x - width); | |
| 176 width = Math.min(width, anchorBox.x - positionX); | |
| 177 } else { | |
| 178 positionX = anchorBox.x + anchorBox.width; | |
| 179 width = Math.min(width, containerWidth - positionX - gutter); | |
| 180 } | |
| 181 } | |
| 182 } else { | |
| 183 positionX = this._positionX !== null ? this._positionX : (containerWidth - width) / 2; | |
| 184 positionY = this._positionY !== null ? this._positionY : (containerHeight - height) / 2; | |
| 185 width = Math.min(width, containerWidth - positionX - gutter); | |
| 186 height = Math.min(height, containerHeight - positionY - gutter); | |
| 187 } | |
| 188 | |
| 189 this.element.style.width = width + 'px'; | |
| 190 this.element.style.height = height + 'px'; | |
| 191 this.element.positionAt(positionX, positionY, container); | |
| 192 } | |
| 193 | |
| 194 /** | |
| 195 * @param {!Element} element | |
| 196 */ | |
| 197 static setRootElement(element) { | |
| 198 UI.ModalOverlay._rootElement = element; | |
| 199 UI.ModalOverlay.rootElementMoved(); | |
| 200 } | |
| 201 | |
| 202 /** | |
| 203 * @return {!Element} | |
| 204 */ | |
| 205 static rootElement() { | |
| 206 return UI.ModalOverlay._rootElement; | |
| 207 } | |
| 208 | |
| 209 static rootElementMoved() { | |
| 210 for (var overlay of UI.ModalOverlay._overlays) | |
| 211 overlay.position(); | |
| 212 } | |
| 213 }; | |
| 214 | |
| 215 /** | |
| 216 * @enum {symbol} | |
| 217 */ | |
| 218 UI.ModalOverlay.AnchorBehavior = { | |
| 219 PreferTop: Symbol('PreferTop'), | |
| 220 PreferBottom: Symbol('PreferBottom'), | |
| 221 PreferLeft: Symbol('PreferLeft'), | |
| 222 PreferRight: Symbol('PreferRight'), | |
| 223 }; | |
| 224 | |
| 225 // TODO(dgozman): if we want to show modals in different documents, this should be a map. | |
| 226 /** @type {!Element} */ | |
| 227 UI.ModalOverlay._rootElement; | |
| 228 /** @type {!Set<!UI.ModalOverlay>} */ | |
| 229 UI.ModalOverlay._overlays = new Set(); | |
| OLD | NEW |