Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(322)

Side by Side Diff: third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-manager-extracted.js

Issue 1862213002: Roll third_party/polymer. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove obsolete appearance_browsertest.js, result of a previous bad merge. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /** 1 /**
2 * @struct 2 * @struct
3 * @constructor 3 * @constructor
4 * @private
4 */ 5 */
5 Polymer.IronOverlayManagerClass = function() { 6 Polymer.IronOverlayManagerClass = function() {
7 /**
8 * Used to keep track of the opened overlays.
9 * @private {Array<Element>}
10 */
6 this._overlays = []; 11 this._overlays = [];
7 // Used to keep track of the last focused node before an overlay gets opened . 12
8 this._lastFocusedNodes = []; 13 /**
9 14 * iframes have a default z-index of 100,
10 /** 15 * so this default should be at least that.
11 * iframes have a default z-index of 100, so this default should be at least
12 * that.
13 * @private {number} 16 * @private {number}
14 */ 17 */
15 this._minimumZ = 101; 18 this._minimumZ = 101;
16 19
17 this._backdrops = []; 20 /**
18 21 * Memoized backdrop element.
22 * @private {Element|null}
23 */
19 this._backdropElement = null; 24 this._backdropElement = null;
20 Object.defineProperty(this, 'backdropElement', { 25
21 get: function() { 26 // Listen to mousedown or touchstart to be sure to be the first to capture
22 if (!this._backdropElement) { 27 // clicks outside the overlay.
23 this._backdropElement = document.createElement('iron-overlay-backdrop' ); 28 var clickEvent = ('ontouchstart' in window) ? 'touchstart' : 'mousedown';
24 } 29 document.addEventListener(clickEvent, this._onCaptureClick.bind(this), true) ;
25 return this._backdropElement; 30 document.addEventListener('focus', this._onCaptureFocus.bind(this), true);
26 }.bind(this) 31 document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true );
27 }); 32 };
33
34 Polymer.IronOverlayManagerClass.prototype = {
35
36 constructor: Polymer.IronOverlayManagerClass,
37
38 /**
39 * The shared backdrop element.
40 * @type {Element} backdropElement
41 */
42 get backdropElement() {
43 if (!this._backdropElement) {
44 this._backdropElement = document.createElement('iron-overlay-backdrop');
45 }
46 return this._backdropElement;
47 },
28 48
29 /** 49 /**
30 * The deepest active element. 50 * The deepest active element.
31 * returns {?Node} element the active element 51 * @type {Element} activeElement the active element
32 */ 52 */
33 this.deepActiveElement = null; 53 get deepActiveElement() {
34 Object.defineProperty(this, 'deepActiveElement', { 54 // document.activeElement can be null
35 get: function() { 55 // https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
36 var active = document.activeElement; 56 // In case of null, default it to document.body.
37 // document.activeElement can be null 57 var active = document.activeElement || document.body;
38 // https://developer.mozilla.org/en-US/docs/Web/API/Document/activeEleme nt 58 while (active.root && Polymer.dom(active.root).activeElement) {
39 while (active && active.root && Polymer.dom(active.root).activeElement) { 59 active = Polymer.dom(active.root).activeElement;
40 active = Polymer.dom(active.root).activeElement; 60 }
41 } 61 return active;
42 return active; 62 },
43 }.bind(this) 63
44 }); 64 /**
45 }; 65 * Brings the overlay at the specified index to the front.
46 66 * @param {number} i
47 /** 67 * @private
48 * If a node is contained in an overlay. 68 */
49 * @private 69 _bringOverlayAtIndexToFront: function(i) {
50 * @param {Node} node 70 var overlay = this._overlays[i];
51 * @returns {Boolean} 71 var lastI = this._overlays.length - 1;
52 */ 72 // Ensure always-on-top overlay stays on top.
53 Polymer.IronOverlayManagerClass.prototype._isChildOfOverlay = function(node) { 73 if (!overlay.alwaysOnTop && this._overlays[lastI].alwaysOnTop) {
54 while (node && node !== document.body) { 74 lastI--;
55 // Use logical parentNode, or native ShadowRoot host. 75 }
56 node = Polymer.dom(node).parentNode || node.host; 76 // If already the top element, return.
57 // Check if it is an overlay. 77 if (!overlay || i >= lastI) {
58 if (node && node.behaviors && node.behaviors.indexOf(Polymer.IronOverlayBe haviorImpl) !== -1) { 78 return;
59 return true; 79 }
60 } 80 // Update z-index to be on top.
61 } 81 var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ);
62 return false; 82 if (this._getZ(overlay) <= minimumZ) {
63 }; 83 this._applyOverlayZ(overlay, minimumZ);
64 84 }
65 Polymer.IronOverlayManagerClass.prototype._applyOverlayZ = function(overlay, a boveZ) { 85
66 this._setZ(overlay, aboveZ + 2); 86 // Shift other overlays behind the new on top.
67 }; 87 while (i < lastI) {
68 88 this._overlays[i] = this._overlays[i + 1];
69 Polymer.IronOverlayManagerClass.prototype._setZ = function(element, z) { 89 i++;
70 element.style.zIndex = z; 90 }
71 }; 91 this._overlays[lastI] = overlay;
72 92 },
73 /** 93
74 * track overlays for z-index and focus managemant 94 /**
75 */ 95 * Adds the overlay and updates its z-index if it's opened, or removes it if it's closed.
76 Polymer.IronOverlayManagerClass.prototype.addOverlay = function(overlay) { 96 * Also updates the backdrop z-index.
77 var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ); 97 * @param {Element} overlay
78 this._overlays.push(overlay); 98 */
79 var newZ = this.currentOverlayZ(); 99 addOrRemoveOverlay: function(overlay) {
80 if (newZ <= minimumZ) { 100 if (overlay.opened) {
81 this._applyOverlayZ(overlay, minimumZ); 101 this.addOverlay(overlay);
82 } 102 } else {
83 var element = this.deepActiveElement; 103 this.removeOverlay(overlay);
84 // If already in other overlay, don't reset focus there. 104 }
85 if (this._isChildOfOverlay(element)) { 105 this.trackBackdrop();
86 element = null; 106 },
87 } 107
88 this._lastFocusedNodes.push(element); 108 /**
89 }; 109 * Tracks overlays for z-index and focus management.
90 110 * Ensures the last added overlay with always-on-top remains on top.
91 Polymer.IronOverlayManagerClass.prototype.removeOverlay = function(overlay) { 111 * @param {Element} overlay
92 var i = this._overlays.indexOf(overlay); 112 */
93 if (i >= 0) { 113 addOverlay: function(overlay) {
114 var i = this._overlays.indexOf(overlay);
115 if (i >= 0) {
116 this._bringOverlayAtIndexToFront(i);
117 return;
118 }
119 var insertionIndex = this._overlays.length;
120 var currentOverlay = this._overlays[insertionIndex - 1];
121 var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ);
122 var newZ = this._getZ(overlay);
123
124 // Ensure always-on-top overlay stays on top.
125 if (currentOverlay && currentOverlay.alwaysOnTop && !overlay.alwaysOnTop) {
126 // This bumps the z-index of +2.
127 this._applyOverlayZ(currentOverlay, minimumZ);
128 insertionIndex--;
129 // Update minimumZ to match previous overlay's z-index.
130 var previousOverlay = this._overlays[insertionIndex - 1];
131 minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ);
132 }
133
134 // Update z-index and insert overlay.
135 if (newZ <= minimumZ) {
136 this._applyOverlayZ(overlay, minimumZ);
137 }
138 this._overlays.splice(insertionIndex, 0, overlay);
139
140 // Get focused node.
141 var element = this.deepActiveElement;
142 overlay.restoreFocusNode = this._overlayParent(element) ? null : element;
143 },
144
145 /**
146 * @param {Element} overlay
147 */
148 removeOverlay: function(overlay) {
149 var i = this._overlays.indexOf(overlay);
150 if (i === -1) {
151 return;
152 }
94 this._overlays.splice(i, 1); 153 this._overlays.splice(i, 1);
95 this._setZ(overlay, ''); 154
96 155 var node = overlay.restoreFocusOnClose ? overlay.restoreFocusNode : null;
97 var node = this._lastFocusedNodes[i]; 156 overlay.restoreFocusNode = null;
98 // Focus only if still contained in document.body 157 // Focus back only if still contained in document.body
99 if (overlay.restoreFocusOnClose && node && Polymer.dom(document.body).deep Contains(node)) { 158 if (node && Polymer.dom(document.body).deepContains(node)) {
100 node.focus(); 159 node.focus();
101 } 160 }
102 this._lastFocusedNodes.splice(i, 1); 161 },
162
163 /**
164 * Returns the current overlay.
165 * @return {Element|undefined}
166 */
167 currentOverlay: function() {
168 var i = this._overlays.length - 1;
169 return this._overlays[i];
170 },
171
172 /**
173 * Returns the current overlay z-index.
174 * @return {number}
175 */
176 currentOverlayZ: function() {
177 return this._getZ(this.currentOverlay());
178 },
179
180 /**
181 * Ensures that the minimum z-index of new overlays is at least `minimumZ`.
182 * This does not effect the z-index of any existing overlays.
183 * @param {number} minimumZ
184 */
185 ensureMinimumZ: function(minimumZ) {
186 this._minimumZ = Math.max(this._minimumZ, minimumZ);
187 },
188
189 focusOverlay: function() {
190 var current = /** @type {?} */ (this.currentOverlay());
191 // We have to be careful to focus the next overlay _after_ any current
192 // transitions are complete (due to the state being toggled prior to the
193 // transition). Otherwise, we risk infinite recursion when a transitioning
194 // (closed) overlay becomes the current overlay.
195 //
196 // NOTE: We make the assumption that any overlay that completes a transiti on
197 // will call into focusOverlay to kick the process back off. Currently:
198 // transitionend -> _applyFocus -> focusOverlay.
199 if (current && !current.transitioning) {
200 current._applyFocus();
201 }
202 },
203
204 /**
205 * Updates the backdrop z-index.
206 */
207 trackBackdrop: function() {
208 this.backdropElement.style.zIndex = this.backdropZ();
209 },
210
211 /**
212 * @return {Array<Element>}
213 */
214 getBackdrops: function() {
215 var backdrops = [];
216 for (var i = 0; i < this._overlays.length; i++) {
217 if (this._overlays[i].withBackdrop) {
218 backdrops.push(this._overlays[i]);
219 }
220 }
221 return backdrops;
222 },
223
224 /**
225 * Returns the z-index for the backdrop.
226 * @return {number}
227 */
228 backdropZ: function() {
229 return this._getZ(this._overlayWithBackdrop()) - 1;
230 },
231
232 /**
233 * Returns the first opened overlay that has a backdrop.
234 * @return {Element|undefined}
235 * @private
236 */
237 _overlayWithBackdrop: function() {
238 for (var i = 0; i < this._overlays.length; i++) {
239 if (this._overlays[i].withBackdrop) {
240 return this._overlays[i];
241 }
242 }
243 },
244
245 /**
246 * Calculates the minimum z-index for the overlay.
247 * @param {Element=} overlay
248 * @private
249 */
250 _getZ: function(overlay) {
251 var z = this._minimumZ;
252 if (overlay) {
253 var z1 = Number(overlay.style.zIndex || window.getComputedStyle(overlay) .zIndex);
254 // Check if is a number
255 // Number.isNaN not supported in IE 10+
256 if (z1 === z1) {
257 z = z1;
258 }
259 }
260 return z;
261 },
262
263 /**
264 * @param {Element} element
265 * @param {number|string} z
266 * @private
267 */
268 _setZ: function(element, z) {
269 element.style.zIndex = z;
270 },
271
272 /**
273 * @param {Element} overlay
274 * @param {number} aboveZ
275 * @private
276 */
277 _applyOverlayZ: function(overlay, aboveZ) {
278 this._setZ(overlay, aboveZ + 2);
279 },
280
281 /**
282 * Returns the overlay containing the provided node. If the node is an overl ay,
283 * it returns the node.
284 * @param {Element=} node
285 * @return {Element|undefined}
286 * @private
287 */
288 _overlayParent: function(node) {
289 while (node && node !== document.body) {
290 // Check if it is an overlay.
291 if (node._manager === this) {
292 return node;
293 }
294 // Use logical parentNode, or native ShadowRoot host.
295 node = Polymer.dom(node).parentNode || node.host;
296 }
297 },
298
299 /**
300 * Returns the deepest overlay in the path.
301 * @param {Array<Element>=} path
302 * @return {Element|undefined}
303 * @private
304 */
305 _overlayInPath: function(path) {
306 path = path || [];
307 for (var i = 0; i < path.length; i++) {
308 if (path[i]._manager === this) {
309 return path[i];
310 }
311 }
312 },
313
314 /**
315 * Ensures the click event is delegated to the right overlay.
316 * @param {!Event} event
317 * @private
318 */
319 _onCaptureClick: function(event) {
320 var overlay = /** @type {?} */ (this.currentOverlay());
321 // Check if clicked outside of top overlay.
322 if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) {
323 overlay._onCaptureClick(event);
324 }
325 },
326
327 /**
328 * Ensures the focus event is delegated to the right overlay.
329 * @param {!Event} event
330 * @private
331 */
332 _onCaptureFocus: function(event) {
333 var overlay = /** @type {?} */ (this.currentOverlay());
334 if (overlay) {
335 overlay._onCaptureFocus(event);
336 }
337 },
338
339 /**
340 * Ensures TAB and ESC keyboard events are delegated to the right overlay.
341 * @param {!Event} event
342 * @private
343 */
344 _onCaptureKeyDown: function(event) {
345 var overlay = /** @type {?} */ (this.currentOverlay());
346 if (overlay) {
347 if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc')) {
348 overlay._onCaptureEsc(event);
349 } else if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'tab')) {
350 overlay._onCaptureTab(event);
351 }
352 }
103 } 353 }
104 }; 354 };
105 355
106 Polymer.IronOverlayManagerClass.prototype.currentOverlay = function() {
107 var i = this._overlays.length - 1;
108 while (this._overlays[i] && !this._overlays[i].opened) {
109 --i;
110 }
111 return this._overlays[i];
112 };
113
114 Polymer.IronOverlayManagerClass.prototype.currentOverlayZ = function() {
115 return this._getOverlayZ(this.currentOverlay());
116 };
117
118 /**
119 * Ensures that the minimum z-index of new overlays is at least `minimumZ`.
120 * This does not effect the z-index of any existing overlays.
121 *
122 * @param {number} minimumZ
123 */
124 Polymer.IronOverlayManagerClass.prototype.ensureMinimumZ = function(minimumZ) {
125 this._minimumZ = Math.max(this._minimumZ, minimumZ);
126 };
127
128 Polymer.IronOverlayManagerClass.prototype.focusOverlay = function() {
129 var current = this.currentOverlay();
130 // We have to be careful to focus the next overlay _after_ any current
131 // transitions are complete (due to the state being toggled prior to the
132 // transition). Otherwise, we risk infinite recursion when a transitioning
133 // (closed) overlay becomes the current overlay.
134 //
135 // NOTE: We make the assumption that any overlay that completes a transition
136 // will call into focusOverlay to kick the process back off. Currently:
137 // transitionend -> _applyFocus -> focusOverlay.
138 if (current && !current.transitioning) {
139 current._applyFocus();
140 }
141 };
142
143 Polymer.IronOverlayManagerClass.prototype.trackBackdrop = function(element) {
144 // backdrops contains the overlays with a backdrop that are currently
145 // visible
146 var index = this._backdrops.indexOf(element);
147 if (element.opened && element.withBackdrop) {
148 // no duplicates
149 if (index === -1) {
150 this._backdrops.push(element);
151 }
152 } else if (index >= 0) {
153 this._backdrops.splice(index, 1);
154 }
155 };
156
157 Polymer.IronOverlayManagerClass.prototype.getBackdrops = function() {
158 return this._backdrops;
159 };
160
161 /**
162 * Returns the z-index for the backdrop.
163 */
164 Polymer.IronOverlayManagerClass.prototype.backdropZ = function() {
165 return this._getOverlayZ(this._overlayWithBackdrop()) - 1;
166 };
167
168 /**
169 * Returns the first opened overlay that has a backdrop.
170 */
171 Polymer.IronOverlayManagerClass.prototype._overlayWithBackdrop = function() {
172 for (var i = 0; i < this._overlays.length; i++) {
173 if (this._overlays[i].opened && this._overlays[i].withBackdrop) {
174 return this._overlays[i];
175 }
176 }
177 };
178
179 /**
180 * Calculates the minimum z-index for the overlay.
181 */
182 Polymer.IronOverlayManagerClass.prototype._getOverlayZ = function(overlay) {
183 var z = this._minimumZ;
184 if (overlay) {
185 var z1 = Number(window.getComputedStyle(overlay).zIndex);
186 // Check if is a number
187 // Number.isNaN not supported in IE 10+
188 if (z1 === z1) {
189 z = z1;
190 }
191 }
192 return z;
193 };
194
195 Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass(); 356 Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698