| OLD | NEW |
| 1 /** | 1 /** |
| 2 * @struct | 2 * @struct |
| 3 * @constructor | 3 * @constructor |
| 4 * @private | 4 * @private |
| 5 */ | 5 */ |
| 6 Polymer.IronOverlayManagerClass = function() { | 6 Polymer.IronOverlayManagerClass = function() { |
| 7 /** | 7 /** |
| 8 * Used to keep track of the opened overlays. | 8 * Used to keep track of the opened overlays. |
| 9 * @private {Array<Element>} | 9 * @private {Array<Element>} |
| 10 */ | 10 */ |
| 11 this._overlays = []; | 11 this._overlays = []; |
| 12 | 12 |
| 13 /** | 13 /** |
| 14 * iframes have a default z-index of 100, | 14 * iframes have a default z-index of 100, |
| 15 * so this default should be at least that. | 15 * so this default should be at least that. |
| 16 * @private {number} | 16 * @private {number} |
| 17 */ | 17 */ |
| 18 this._minimumZ = 101; | 18 this._minimumZ = 101; |
| 19 | 19 |
| 20 /** | 20 /** |
| 21 * Memoized backdrop element. | 21 * Memoized backdrop element. |
| 22 * @private {Element|null} | 22 * @private {Element|null} |
| 23 */ | 23 */ |
| 24 this._backdropElement = null; | 24 this._backdropElement = null; |
| 25 | 25 |
| 26 // Listen to mousedown or touchstart to be sure to be the first to capture | 26 // Enable document-wide tap recognizer. |
| 27 // clicks outside the overlay. | 27 Polymer.Gestures.add(document, 'tap', null); |
| 28 var clickEvent = ('ontouchstart' in window) ? 'touchstart' : 'mousedown'; | 28 // Need to have useCapture=true, Polymer.Gestures doesn't offer that. |
| 29 document.addEventListener(clickEvent, this._onCaptureClick.bind(this), true)
; | 29 document.addEventListener('tap', this._onCaptureClick.bind(this), true); |
| 30 document.addEventListener('focus', this._onCaptureFocus.bind(this), true); | 30 document.addEventListener('focus', this._onCaptureFocus.bind(this), true); |
| 31 document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true
); | 31 document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true
); |
| 32 }; | 32 }; |
| 33 | 33 |
| 34 Polymer.IronOverlayManagerClass.prototype = { | 34 Polymer.IronOverlayManagerClass.prototype = { |
| 35 | 35 |
| 36 constructor: Polymer.IronOverlayManagerClass, | 36 constructor: Polymer.IronOverlayManagerClass, |
| 37 | 37 |
| 38 /** | 38 /** |
| 39 * The shared backdrop element. | 39 * The shared backdrop element. |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 * Adds the overlay and updates its z-index if it's opened, or removes it if
it's closed. | 99 * Adds the overlay and updates its z-index if it's opened, or removes it if
it's closed. |
| 100 * Also updates the backdrop z-index. | 100 * Also updates the backdrop z-index. |
| 101 * @param {!Element} overlay | 101 * @param {!Element} overlay |
| 102 */ | 102 */ |
| 103 addOrRemoveOverlay: function(overlay) { | 103 addOrRemoveOverlay: function(overlay) { |
| 104 if (overlay.opened) { | 104 if (overlay.opened) { |
| 105 this.addOverlay(overlay); | 105 this.addOverlay(overlay); |
| 106 } else { | 106 } else { |
| 107 this.removeOverlay(overlay); | 107 this.removeOverlay(overlay); |
| 108 } | 108 } |
| 109 this.trackBackdrop(); | |
| 110 }, | 109 }, |
| 111 | 110 |
| 112 /** | 111 /** |
| 113 * Tracks overlays for z-index and focus management. | 112 * Tracks overlays for z-index and focus management. |
| 114 * Ensures the last added overlay with always-on-top remains on top. | 113 * Ensures the last added overlay with always-on-top remains on top. |
| 115 * @param {!Element} overlay | 114 * @param {!Element} overlay |
| 116 */ | 115 */ |
| 117 addOverlay: function(overlay) { | 116 addOverlay: function(overlay) { |
| 118 var i = this._overlays.indexOf(overlay); | 117 var i = this._overlays.indexOf(overlay); |
| 119 if (i >= 0) { | 118 if (i >= 0) { |
| 120 this._bringOverlayAtIndexToFront(i); | 119 this._bringOverlayAtIndexToFront(i); |
| 120 this.trackBackdrop(); |
| 121 return; | 121 return; |
| 122 } | 122 } |
| 123 var insertionIndex = this._overlays.length; | 123 var insertionIndex = this._overlays.length; |
| 124 var currentOverlay = this._overlays[insertionIndex - 1]; | 124 var currentOverlay = this._overlays[insertionIndex - 1]; |
| 125 var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ); | 125 var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ); |
| 126 var newZ = this._getZ(overlay); | 126 var newZ = this._getZ(overlay); |
| 127 | 127 |
| 128 // Ensure always-on-top overlay stays on top. | 128 // Ensure always-on-top overlay stays on top. |
| 129 if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)
) { | 129 if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)
) { |
| 130 // This bumps the z-index of +2. | 130 // This bumps the z-index of +2. |
| 131 this._applyOverlayZ(currentOverlay, minimumZ); | 131 this._applyOverlayZ(currentOverlay, minimumZ); |
| 132 insertionIndex--; | 132 insertionIndex--; |
| 133 // Update minimumZ to match previous overlay's z-index. | 133 // Update minimumZ to match previous overlay's z-index. |
| 134 var previousOverlay = this._overlays[insertionIndex - 1]; | 134 var previousOverlay = this._overlays[insertionIndex - 1]; |
| 135 minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ); | 135 minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ); |
| 136 } | 136 } |
| 137 | 137 |
| 138 // Update z-index and insert overlay. | 138 // Update z-index and insert overlay. |
| 139 if (newZ <= minimumZ) { | 139 if (newZ <= minimumZ) { |
| 140 this._applyOverlayZ(overlay, minimumZ); | 140 this._applyOverlayZ(overlay, minimumZ); |
| 141 } | 141 } |
| 142 this._overlays.splice(insertionIndex, 0, overlay); | 142 this._overlays.splice(insertionIndex, 0, overlay); |
| 143 | 143 |
| 144 // Get focused node. | 144 // Get focused node. |
| 145 var element = this.deepActiveElement; | 145 var element = this.deepActiveElement; |
| 146 overlay.restoreFocusNode = this._overlayParent(element) ? null : element; | 146 overlay.restoreFocusNode = this._overlayParent(element) ? null : element; |
| 147 this.trackBackdrop(); |
| 147 }, | 148 }, |
| 148 | 149 |
| 149 /** | 150 /** |
| 150 * @param {!Element} overlay | 151 * @param {!Element} overlay |
| 151 */ | 152 */ |
| 152 removeOverlay: function(overlay) { | 153 removeOverlay: function(overlay) { |
| 153 var i = this._overlays.indexOf(overlay); | 154 var i = this._overlays.indexOf(overlay); |
| 154 if (i === -1) { | 155 if (i === -1) { |
| 155 return; | 156 return; |
| 156 } | 157 } |
| 157 this._overlays.splice(i, 1); | 158 this._overlays.splice(i, 1); |
| 158 | 159 |
| 159 var node = overlay.restoreFocusOnClose ? overlay.restoreFocusNode : null; | 160 var node = overlay.restoreFocusOnClose ? overlay.restoreFocusNode : null; |
| 160 overlay.restoreFocusNode = null; | 161 overlay.restoreFocusNode = null; |
| 161 // Focus back only if still contained in document.body | 162 // Focus back only if still contained in document.body |
| 162 if (node && Polymer.dom(document.body).deepContains(node)) { | 163 if (node && Polymer.dom(document.body).deepContains(node)) { |
| 163 node.focus(); | 164 node.focus(); |
| 164 } | 165 } |
| 166 this.trackBackdrop(); |
| 165 }, | 167 }, |
| 166 | 168 |
| 167 /** | 169 /** |
| 168 * Returns the current overlay. | 170 * Returns the current overlay. |
| 169 * @return {Element|undefined} | 171 * @return {Element|undefined} |
| 170 */ | 172 */ |
| 171 currentOverlay: function() { | 173 currentOverlay: function() { |
| 172 var i = this._overlays.length - 1; | 174 var i = this._overlays.length - 1; |
| 173 return this._overlays[i]; | 175 return this._overlays[i]; |
| 174 }, | 176 }, |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 | 325 |
| 324 /** | 326 /** |
| 325 * Ensures the click event is delegated to the right overlay. | 327 * Ensures the click event is delegated to the right overlay. |
| 326 * @param {!Event} event | 328 * @param {!Event} event |
| 327 * @private | 329 * @private |
| 328 */ | 330 */ |
| 329 _onCaptureClick: function(event) { | 331 _onCaptureClick: function(event) { |
| 330 var overlay = /** @type {?} */ (this.currentOverlay()); | 332 var overlay = /** @type {?} */ (this.currentOverlay()); |
| 331 // Check if clicked outside of top overlay. | 333 // Check if clicked outside of top overlay. |
| 332 if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) { | 334 if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) { |
| 333 if (overlay.withBackdrop) { | |
| 334 // There's no need to stop the propagation as the backdrop element | |
| 335 // already got this mousedown/touchstart event. Calling preventDefault | |
| 336 // on this event ensures that click/tap won't be triggered at all. | |
| 337 event.preventDefault(); | |
| 338 } | |
| 339 overlay._onCaptureClick(event); | 335 overlay._onCaptureClick(event); |
| 340 } | 336 } |
| 341 }, | 337 }, |
| 342 | 338 |
| 343 /** | 339 /** |
| 344 * Ensures the focus event is delegated to the right overlay. | 340 * Ensures the focus event is delegated to the right overlay. |
| 345 * @param {!Event} event | 341 * @param {!Event} event |
| 346 * @private | 342 * @private |
| 347 */ | 343 */ |
| 348 _onCaptureFocus: function(event) { | 344 _onCaptureFocus: function(event) { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 376 * @private | 372 * @private |
| 377 */ | 373 */ |
| 378 _shouldBeBehindOverlay: function(overlay1, overlay2) { | 374 _shouldBeBehindOverlay: function(overlay1, overlay2) { |
| 379 var o1 = /** @type {?} */ (overlay1); | 375 var o1 = /** @type {?} */ (overlay1); |
| 380 var o2 = /** @type {?} */ (overlay2); | 376 var o2 = /** @type {?} */ (overlay2); |
| 381 return !o1.alwaysOnTop && o2.alwaysOnTop; | 377 return !o1.alwaysOnTop && o2.alwaysOnTop; |
| 382 } | 378 } |
| 383 }; | 379 }; |
| 384 | 380 |
| 385 Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass(); | 381 Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass(); |
| OLD | NEW |