| 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 */ |
| (...skipping 19 matching lines...) Expand all Loading... |
| 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. |
| 40 * @type {Element} backdropElement | 40 * @type {!Element} backdropElement |
| 41 */ | 41 */ |
| 42 get backdropElement() { | 42 get backdropElement() { |
| 43 if (!this._backdropElement) { | 43 if (!this._backdropElement) { |
| 44 this._backdropElement = document.createElement('iron-overlay-backdrop'); | 44 this._backdropElement = document.createElement('iron-overlay-backdrop'); |
| 45 } | 45 } |
| 46 return this._backdropElement; | 46 return this._backdropElement; |
| 47 }, | 47 }, |
| 48 | 48 |
| 49 /** | 49 /** |
| 50 * The deepest active element. | 50 * The deepest active element. |
| 51 * @type {Element} activeElement the active element | 51 * @type {!Element} activeElement the active element |
| 52 */ | 52 */ |
| 53 get deepActiveElement() { | 53 get deepActiveElement() { |
| 54 // document.activeElement can be null | 54 // document.activeElement can be null |
| 55 // https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement | 55 // https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement |
| 56 // In case of null, default it to document.body. | 56 // In case of null, default it to document.body. |
| 57 var active = document.activeElement || document.body; | 57 var active = document.activeElement || document.body; |
| 58 while (active.root && Polymer.dom(active.root).activeElement) { | 58 while (active.root && Polymer.dom(active.root).activeElement) { |
| 59 active = Polymer.dom(active.root).activeElement; | 59 active = Polymer.dom(active.root).activeElement; |
| 60 } | 60 } |
| 61 return active; | 61 return active; |
| 62 }, | 62 }, |
| 63 | 63 |
| 64 /** | 64 /** |
| 65 * Brings the overlay at the specified index to the front. | 65 * Brings the overlay at the specified index to the front. |
| 66 * @param {number} i | 66 * @param {number} i |
| 67 * @private | 67 * @private |
| 68 */ | 68 */ |
| 69 _bringOverlayAtIndexToFront: function(i) { | 69 _bringOverlayAtIndexToFront: function(i) { |
| 70 var overlay = this._overlays[i]; | 70 var overlay = this._overlays[i]; |
| 71 if (!overlay) { |
| 72 return; |
| 73 } |
| 71 var lastI = this._overlays.length - 1; | 74 var lastI = this._overlays.length - 1; |
| 75 var currentOverlay = this._overlays[lastI]; |
| 72 // Ensure always-on-top overlay stays on top. | 76 // Ensure always-on-top overlay stays on top. |
| 73 if (!overlay.alwaysOnTop && this._overlays[lastI].alwaysOnTop) { | 77 if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)
) { |
| 74 lastI--; | 78 lastI--; |
| 75 } | 79 } |
| 76 // If already the top element, return. | 80 // If already the top element, return. |
| 77 if (!overlay || i >= lastI) { | 81 if (i >= lastI) { |
| 78 return; | 82 return; |
| 79 } | 83 } |
| 80 // Update z-index to be on top. | 84 // Update z-index to be on top. |
| 81 var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ); | 85 var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ); |
| 82 if (this._getZ(overlay) <= minimumZ) { | 86 if (this._getZ(overlay) <= minimumZ) { |
| 83 this._applyOverlayZ(overlay, minimumZ); | 87 this._applyOverlayZ(overlay, minimumZ); |
| 84 } | 88 } |
| 85 | 89 |
| 86 // Shift other overlays behind the new on top. | 90 // Shift other overlays behind the new on top. |
| 87 while (i < lastI) { | 91 while (i < lastI) { |
| 88 this._overlays[i] = this._overlays[i + 1]; | 92 this._overlays[i] = this._overlays[i + 1]; |
| 89 i++; | 93 i++; |
| 90 } | 94 } |
| 91 this._overlays[lastI] = overlay; | 95 this._overlays[lastI] = overlay; |
| 92 }, | 96 }, |
| 93 | 97 |
| 94 /** | 98 /** |
| 95 * 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. |
| 96 * Also updates the backdrop z-index. | 100 * Also updates the backdrop z-index. |
| 97 * @param {Element} overlay | 101 * @param {!Element} overlay |
| 98 */ | 102 */ |
| 99 addOrRemoveOverlay: function(overlay) { | 103 addOrRemoveOverlay: function(overlay) { |
| 100 if (overlay.opened) { | 104 if (overlay.opened) { |
| 101 this.addOverlay(overlay); | 105 this.addOverlay(overlay); |
| 102 } else { | 106 } else { |
| 103 this.removeOverlay(overlay); | 107 this.removeOverlay(overlay); |
| 104 } | 108 } |
| 105 this.trackBackdrop(); | 109 this.trackBackdrop(); |
| 106 }, | 110 }, |
| 107 | 111 |
| 108 /** | 112 /** |
| 109 * Tracks overlays for z-index and focus management. | 113 * Tracks overlays for z-index and focus management. |
| 110 * Ensures the last added overlay with always-on-top remains on top. | 114 * Ensures the last added overlay with always-on-top remains on top. |
| 111 * @param {Element} overlay | 115 * @param {!Element} overlay |
| 112 */ | 116 */ |
| 113 addOverlay: function(overlay) { | 117 addOverlay: function(overlay) { |
| 114 var i = this._overlays.indexOf(overlay); | 118 var i = this._overlays.indexOf(overlay); |
| 115 if (i >= 0) { | 119 if (i >= 0) { |
| 116 this._bringOverlayAtIndexToFront(i); | 120 this._bringOverlayAtIndexToFront(i); |
| 117 return; | 121 return; |
| 118 } | 122 } |
| 119 var insertionIndex = this._overlays.length; | 123 var insertionIndex = this._overlays.length; |
| 120 var currentOverlay = this._overlays[insertionIndex - 1]; | 124 var currentOverlay = this._overlays[insertionIndex - 1]; |
| 121 var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ); | 125 var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ); |
| 122 var newZ = this._getZ(overlay); | 126 var newZ = this._getZ(overlay); |
| 123 | 127 |
| 124 // Ensure always-on-top overlay stays on top. | 128 // Ensure always-on-top overlay stays on top. |
| 125 if (currentOverlay && currentOverlay.alwaysOnTop && !overlay.alwaysOnTop)
{ | 129 if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)
) { |
| 126 // This bumps the z-index of +2. | 130 // This bumps the z-index of +2. |
| 127 this._applyOverlayZ(currentOverlay, minimumZ); | 131 this._applyOverlayZ(currentOverlay, minimumZ); |
| 128 insertionIndex--; | 132 insertionIndex--; |
| 129 // Update minimumZ to match previous overlay's z-index. | 133 // Update minimumZ to match previous overlay's z-index. |
| 130 var previousOverlay = this._overlays[insertionIndex - 1]; | 134 var previousOverlay = this._overlays[insertionIndex - 1]; |
| 131 minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ); | 135 minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ); |
| 132 } | 136 } |
| 133 | 137 |
| 134 // Update z-index and insert overlay. | 138 // Update z-index and insert overlay. |
| 135 if (newZ <= minimumZ) { | 139 if (newZ <= minimumZ) { |
| 136 this._applyOverlayZ(overlay, minimumZ); | 140 this._applyOverlayZ(overlay, minimumZ); |
| 137 } | 141 } |
| 138 this._overlays.splice(insertionIndex, 0, overlay); | 142 this._overlays.splice(insertionIndex, 0, overlay); |
| 139 | 143 |
| 140 // Get focused node. | 144 // Get focused node. |
| 141 var element = this.deepActiveElement; | 145 var element = this.deepActiveElement; |
| 142 overlay.restoreFocusNode = this._overlayParent(element) ? null : element; | 146 overlay.restoreFocusNode = this._overlayParent(element) ? null : element; |
| 143 }, | 147 }, |
| 144 | 148 |
| 145 /** | 149 /** |
| 146 * @param {Element} overlay | 150 * @param {!Element} overlay |
| 147 */ | 151 */ |
| 148 removeOverlay: function(overlay) { | 152 removeOverlay: function(overlay) { |
| 149 var i = this._overlays.indexOf(overlay); | 153 var i = this._overlays.indexOf(overlay); |
| 150 if (i === -1) { | 154 if (i === -1) { |
| 151 return; | 155 return; |
| 152 } | 156 } |
| 153 this._overlays.splice(i, 1); | 157 this._overlays.splice(i, 1); |
| 154 | 158 |
| 155 var node = overlay.restoreFocusOnClose ? overlay.restoreFocusNode : null; | 159 var node = overlay.restoreFocusOnClose ? overlay.restoreFocusNode : null; |
| 156 overlay.restoreFocusNode = null; | 160 overlay.restoreFocusNode = null; |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 // Check if is a number | 258 // Check if is a number |
| 255 // Number.isNaN not supported in IE 10+ | 259 // Number.isNaN not supported in IE 10+ |
| 256 if (z1 === z1) { | 260 if (z1 === z1) { |
| 257 z = z1; | 261 z = z1; |
| 258 } | 262 } |
| 259 } | 263 } |
| 260 return z; | 264 return z; |
| 261 }, | 265 }, |
| 262 | 266 |
| 263 /** | 267 /** |
| 264 * @param {Element} element | 268 * @param {!Element} element |
| 265 * @param {number|string} z | 269 * @param {number|string} z |
| 266 * @private | 270 * @private |
| 267 */ | 271 */ |
| 268 _setZ: function(element, z) { | 272 _setZ: function(element, z) { |
| 269 element.style.zIndex = z; | 273 element.style.zIndex = z; |
| 270 }, | 274 }, |
| 271 | 275 |
| 272 /** | 276 /** |
| 273 * @param {Element} overlay | 277 * @param {!Element} overlay |
| 274 * @param {number} aboveZ | 278 * @param {number} aboveZ |
| 275 * @private | 279 * @private |
| 276 */ | 280 */ |
| 277 _applyOverlayZ: function(overlay, aboveZ) { | 281 _applyOverlayZ: function(overlay, aboveZ) { |
| 278 this._setZ(overlay, aboveZ + 2); | 282 this._setZ(overlay, aboveZ + 2); |
| 279 }, | 283 }, |
| 280 | 284 |
| 281 /** | 285 /** |
| 282 * Returns the overlay containing the provided node. If the node is an overl
ay, | 286 * Returns the overlay containing the provided node. If the node is an overl
ay, |
| 283 * it returns the node. | 287 * it returns the node. |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 */ | 347 */ |
| 344 _onCaptureKeyDown: function(event) { | 348 _onCaptureKeyDown: function(event) { |
| 345 var overlay = /** @type {?} */ (this.currentOverlay()); | 349 var overlay = /** @type {?} */ (this.currentOverlay()); |
| 346 if (overlay) { | 350 if (overlay) { |
| 347 if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc'))
{ | 351 if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc'))
{ |
| 348 overlay._onCaptureEsc(event); | 352 overlay._onCaptureEsc(event); |
| 349 } else if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,
'tab')) { | 353 } else if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,
'tab')) { |
| 350 overlay._onCaptureTab(event); | 354 overlay._onCaptureTab(event); |
| 351 } | 355 } |
| 352 } | 356 } |
| 357 }, |
| 358 |
| 359 /** |
| 360 * Returns if the overlay1 should be behind overlay2. |
| 361 * @param {!Element} overlay1 |
| 362 * @param {!Element} overlay2 |
| 363 * @return {boolean} |
| 364 * @private |
| 365 */ |
| 366 _shouldBeBehindOverlay: function(overlay1, overlay2) { |
| 367 var o1 = /** @type {?} */ (overlay1); |
| 368 var o2 = /** @type {?} */ (overlay2); |
| 369 return !o1.alwaysOnTop && o2.alwaysOnTop; |
| 353 } | 370 } |
| 354 }; | 371 }; |
| 355 | 372 |
| 356 Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass(); | 373 Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass(); |
| OLD | NEW |