OLD | NEW |
1 <!-- | 1 <!-- |
2 @license | 2 @license |
3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. | 3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. |
4 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | 4 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt |
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | 5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | 6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt |
7 Code distributed by Google as part of the polymer project is also | 7 Code distributed by Google as part of the polymer project is also |
8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | 8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt |
9 --> | 9 --> |
10 | 10 |
(...skipping 21 matching lines...) Expand all Loading... |
32 * @private {number} | 32 * @private {number} |
33 */ | 33 */ |
34 this._minimumZ = 101; | 34 this._minimumZ = 101; |
35 | 35 |
36 /** | 36 /** |
37 * Memoized backdrop element. | 37 * Memoized backdrop element. |
38 * @private {Element|null} | 38 * @private {Element|null} |
39 */ | 39 */ |
40 this._backdropElement = null; | 40 this._backdropElement = null; |
41 | 41 |
42 // Listen to mousedown or touchstart to be sure to be the first to capture | 42 // Enable document-wide tap recognizer. |
43 // clicks outside the overlay. | 43 Polymer.Gestures.add(document, 'tap', null); |
44 var clickEvent = ('ontouchstart' in window) ? 'touchstart' : 'mousedown'; | 44 // Need to have useCapture=true, Polymer.Gestures doesn't offer that. |
45 document.addEventListener(clickEvent, this._onCaptureClick.bind(this), true)
; | 45 document.addEventListener('tap', this._onCaptureClick.bind(this), true); |
46 document.addEventListener('focus', this._onCaptureFocus.bind(this), true); | 46 document.addEventListener('focus', this._onCaptureFocus.bind(this), true); |
47 document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true
); | 47 document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true
); |
48 }; | 48 }; |
49 | 49 |
50 Polymer.IronOverlayManagerClass.prototype = { | 50 Polymer.IronOverlayManagerClass.prototype = { |
51 | 51 |
52 constructor: Polymer.IronOverlayManagerClass, | 52 constructor: Polymer.IronOverlayManagerClass, |
53 | 53 |
54 /** | 54 /** |
55 * The shared backdrop element. | 55 * The shared backdrop element. |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 * Adds the overlay and updates its z-index if it's opened, or removes it if
it's closed. | 115 * Adds the overlay and updates its z-index if it's opened, or removes it if
it's closed. |
116 * Also updates the backdrop z-index. | 116 * Also updates the backdrop z-index. |
117 * @param {!Element} overlay | 117 * @param {!Element} overlay |
118 */ | 118 */ |
119 addOrRemoveOverlay: function(overlay) { | 119 addOrRemoveOverlay: function(overlay) { |
120 if (overlay.opened) { | 120 if (overlay.opened) { |
121 this.addOverlay(overlay); | 121 this.addOverlay(overlay); |
122 } else { | 122 } else { |
123 this.removeOverlay(overlay); | 123 this.removeOverlay(overlay); |
124 } | 124 } |
125 this.trackBackdrop(); | |
126 }, | 125 }, |
127 | 126 |
128 /** | 127 /** |
129 * Tracks overlays for z-index and focus management. | 128 * Tracks overlays for z-index and focus management. |
130 * Ensures the last added overlay with always-on-top remains on top. | 129 * Ensures the last added overlay with always-on-top remains on top. |
131 * @param {!Element} overlay | 130 * @param {!Element} overlay |
132 */ | 131 */ |
133 addOverlay: function(overlay) { | 132 addOverlay: function(overlay) { |
134 var i = this._overlays.indexOf(overlay); | 133 var i = this._overlays.indexOf(overlay); |
135 if (i >= 0) { | 134 if (i >= 0) { |
136 this._bringOverlayAtIndexToFront(i); | 135 this._bringOverlayAtIndexToFront(i); |
| 136 this.trackBackdrop(); |
137 return; | 137 return; |
138 } | 138 } |
139 var insertionIndex = this._overlays.length; | 139 var insertionIndex = this._overlays.length; |
140 var currentOverlay = this._overlays[insertionIndex - 1]; | 140 var currentOverlay = this._overlays[insertionIndex - 1]; |
141 var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ); | 141 var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ); |
142 var newZ = this._getZ(overlay); | 142 var newZ = this._getZ(overlay); |
143 | 143 |
144 // Ensure always-on-top overlay stays on top. | 144 // Ensure always-on-top overlay stays on top. |
145 if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)
) { | 145 if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)
) { |
146 // This bumps the z-index of +2. | 146 // This bumps the z-index of +2. |
147 this._applyOverlayZ(currentOverlay, minimumZ); | 147 this._applyOverlayZ(currentOverlay, minimumZ); |
148 insertionIndex--; | 148 insertionIndex--; |
149 // Update minimumZ to match previous overlay's z-index. | 149 // Update minimumZ to match previous overlay's z-index. |
150 var previousOverlay = this._overlays[insertionIndex - 1]; | 150 var previousOverlay = this._overlays[insertionIndex - 1]; |
151 minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ); | 151 minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ); |
152 } | 152 } |
153 | 153 |
154 // Update z-index and insert overlay. | 154 // Update z-index and insert overlay. |
155 if (newZ <= minimumZ) { | 155 if (newZ <= minimumZ) { |
156 this._applyOverlayZ(overlay, minimumZ); | 156 this._applyOverlayZ(overlay, minimumZ); |
157 } | 157 } |
158 this._overlays.splice(insertionIndex, 0, overlay); | 158 this._overlays.splice(insertionIndex, 0, overlay); |
159 | 159 |
160 // Get focused node. | 160 // Get focused node. |
161 var element = this.deepActiveElement; | 161 var element = this.deepActiveElement; |
162 overlay.restoreFocusNode = this._overlayParent(element) ? null : element; | 162 overlay.restoreFocusNode = this._overlayParent(element) ? null : element; |
| 163 this.trackBackdrop(); |
163 }, | 164 }, |
164 | 165 |
165 /** | 166 /** |
166 * @param {!Element} overlay | 167 * @param {!Element} overlay |
167 */ | 168 */ |
168 removeOverlay: function(overlay) { | 169 removeOverlay: function(overlay) { |
169 var i = this._overlays.indexOf(overlay); | 170 var i = this._overlays.indexOf(overlay); |
170 if (i === -1) { | 171 if (i === -1) { |
171 return; | 172 return; |
172 } | 173 } |
173 this._overlays.splice(i, 1); | 174 this._overlays.splice(i, 1); |
174 | 175 |
175 var node = overlay.restoreFocusOnClose ? overlay.restoreFocusNode : null; | 176 var node = overlay.restoreFocusOnClose ? overlay.restoreFocusNode : null; |
176 overlay.restoreFocusNode = null; | 177 overlay.restoreFocusNode = null; |
177 // Focus back only if still contained in document.body | 178 // Focus back only if still contained in document.body |
178 if (node && Polymer.dom(document.body).deepContains(node)) { | 179 if (node && Polymer.dom(document.body).deepContains(node)) { |
179 node.focus(); | 180 node.focus(); |
180 } | 181 } |
| 182 this.trackBackdrop(); |
181 }, | 183 }, |
182 | 184 |
183 /** | 185 /** |
184 * Returns the current overlay. | 186 * Returns the current overlay. |
185 * @return {Element|undefined} | 187 * @return {Element|undefined} |
186 */ | 188 */ |
187 currentOverlay: function() { | 189 currentOverlay: function() { |
188 var i = this._overlays.length - 1; | 190 var i = this._overlays.length - 1; |
189 return this._overlays[i]; | 191 return this._overlays[i]; |
190 }, | 192 }, |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 } | 321 } |
320 // Use logical parentNode, or native ShadowRoot host. | 322 // Use logical parentNode, or native ShadowRoot host. |
321 node = Polymer.dom(node).parentNode || node.host; | 323 node = Polymer.dom(node).parentNode || node.host; |
322 } | 324 } |
323 }, | 325 }, |
324 | 326 |
325 /** | 327 /** |
326 * Returns the deepest overlay in the path. | 328 * Returns the deepest overlay in the path. |
327 * @param {Array<Element>=} path | 329 * @param {Array<Element>=} path |
328 * @return {Element|undefined} | 330 * @return {Element|undefined} |
| 331 * @suppress {missingProperties} |
329 * @private | 332 * @private |
330 */ | 333 */ |
331 _overlayInPath: function(path) { | 334 _overlayInPath: function(path) { |
332 path = path || []; | 335 path = path || []; |
333 for (var i = 0; i < path.length; i++) { | 336 for (var i = 0; i < path.length; i++) { |
334 if (path[i]._manager === this) { | 337 if (path[i]._manager === this) { |
335 return path[i]; | 338 return path[i]; |
336 } | 339 } |
337 } | 340 } |
338 }, | 341 }, |
339 | 342 |
340 /** | 343 /** |
341 * Ensures the click event is delegated to the right overlay. | 344 * Ensures the click event is delegated to the right overlay. |
342 * @param {!Event} event | 345 * @param {!Event} event |
343 * @private | 346 * @private |
344 */ | 347 */ |
345 _onCaptureClick: function(event) { | 348 _onCaptureClick: function(event) { |
346 var overlay = /** @type {?} */ (this.currentOverlay()); | 349 var overlay = /** @type {?} */ (this.currentOverlay()); |
347 // Check if clicked outside of top overlay. | 350 // Check if clicked outside of top overlay. |
348 if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) { | 351 if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) { |
349 if (overlay.withBackdrop) { | |
350 // There's no need to stop the propagation as the backdrop element | |
351 // already got this mousedown/touchstart event. Calling preventDefault | |
352 // on this event ensures that click/tap won't be triggered at all. | |
353 event.preventDefault(); | |
354 } | |
355 overlay._onCaptureClick(event); | 352 overlay._onCaptureClick(event); |
356 } | 353 } |
357 }, | 354 }, |
358 | 355 |
359 /** | 356 /** |
360 * Ensures the focus event is delegated to the right overlay. | 357 * Ensures the focus event is delegated to the right overlay. |
361 * @param {!Event} event | 358 * @param {!Event} event |
362 * @private | 359 * @private |
363 */ | 360 */ |
364 _onCaptureFocus: function(event) { | 361 _onCaptureFocus: function(event) { |
(...skipping 17 matching lines...) Expand all Loading... |
382 overlay._onCaptureTab(event); | 379 overlay._onCaptureTab(event); |
383 } | 380 } |
384 } | 381 } |
385 }, | 382 }, |
386 | 383 |
387 /** | 384 /** |
388 * Returns if the overlay1 should be behind overlay2. | 385 * Returns if the overlay1 should be behind overlay2. |
389 * @param {!Element} overlay1 | 386 * @param {!Element} overlay1 |
390 * @param {!Element} overlay2 | 387 * @param {!Element} overlay2 |
391 * @return {boolean} | 388 * @return {boolean} |
| 389 * @suppress {missingProperties} |
392 * @private | 390 * @private |
393 */ | 391 */ |
394 _shouldBeBehindOverlay: function(overlay1, overlay2) { | 392 _shouldBeBehindOverlay: function(overlay1, overlay2) { |
395 var o1 = /** @type {?} */ (overlay1); | 393 return !overlay1.alwaysOnTop && overlay2.alwaysOnTop; |
396 var o2 = /** @type {?} */ (overlay2); | |
397 return !o1.alwaysOnTop && o2.alwaysOnTop; | |
398 } | 394 } |
399 }; | 395 }; |
400 | 396 |
401 Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass(); | 397 Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass(); |
402 </script> | 398 </script> |
OLD | NEW |