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 |