| OLD | NEW |
| 1 (function() { | 1 (function() { |
| 2 'use strict'; | 2 'use strict'; |
| 3 | 3 |
| 4 /** | 4 /** |
| 5 Use `Polymer.IronOverlayBehavior` to implement an element that can be hidden or
shown, and displays | 5 Use `Polymer.IronOverlayBehavior` to implement an element that can be hidden or
shown, and displays |
| 6 on top of other content. It includes an optional backdrop, and can be used to im
plement a variety | 6 on top of other content. It includes an optional backdrop, and can be used to im
plement a variety |
| 7 of UI controls including dialogs and drop downs. Multiple overlays may be displa
yed at once. | 7 of UI controls including dialogs and drop downs. Multiple overlays may be displa
yed at once. |
| 8 | 8 |
| 9 ### Closing and canceling | 9 ### Closing and canceling |
| 10 | 10 |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 293 this.removeAttribute('aria-hidden'); | 293 this.removeAttribute('aria-hidden'); |
| 294 } else { | 294 } else { |
| 295 this.setAttribute('aria-hidden', 'true'); | 295 this.setAttribute('aria-hidden', 'true'); |
| 296 } | 296 } |
| 297 | 297 |
| 298 // wait to call after ready only if we're initially open | 298 // wait to call after ready only if we're initially open |
| 299 if (!this._overlaySetup) { | 299 if (!this._overlaySetup) { |
| 300 return; | 300 return; |
| 301 } | 301 } |
| 302 | 302 |
| 303 this._manager.addOrRemoveOverlay(this); | |
| 304 | |
| 305 if (this.__openChangedAsync) { | 303 if (this.__openChangedAsync) { |
| 306 window.cancelAnimationFrame(this.__openChangedAsync); | 304 window.cancelAnimationFrame(this.__openChangedAsync); |
| 307 } | 305 } |
| 308 | 306 |
| 307 // Synchronously remove the overlay. |
| 308 // The adding is done asynchronously to go out of the scope of the event |
| 309 // which might have generated the opening. |
| 310 if (!this.opened) { |
| 311 this._manager.removeOverlay(this); |
| 312 } |
| 313 |
| 309 // Defer any animation-related code on attached | 314 // Defer any animation-related code on attached |
| 310 // (_openedChanged gets called again on attached). | 315 // (_openedChanged gets called again on attached). |
| 311 if (!this.isAttached) { | 316 if (!this.isAttached) { |
| 312 return; | 317 return; |
| 313 } | 318 } |
| 314 | 319 |
| 315 this.__isAnimating = true; | 320 this.__isAnimating = true; |
| 316 | 321 |
| 317 // requestAnimationFrame for non-blocking rendering | 322 // requestAnimationFrame for non-blocking rendering |
| 318 this.__openChangedAsync = window.requestAnimationFrame(function() { | 323 this.__openChangedAsync = window.requestAnimationFrame(function() { |
| 319 this.__openChangedAsync = null; | 324 this.__openChangedAsync = null; |
| 320 if (this.opened) { | 325 if (this.opened) { |
| 326 this._manager.addOverlay(this); |
| 321 this._prepareRenderOpened(); | 327 this._prepareRenderOpened(); |
| 322 this._renderOpened(); | 328 this._renderOpened(); |
| 323 } else { | 329 } else { |
| 324 this._renderClosed(); | 330 this._renderClosed(); |
| 325 } | 331 } |
| 326 }.bind(this)); | 332 }.bind(this)); |
| 327 }, | 333 }, |
| 328 | 334 |
| 329 _canceledChanged: function() { | 335 _canceledChanged: function() { |
| 330 this.closingReason = this.closingReason || {}; | 336 this.closingReason = this.closingReason || {}; |
| 331 this.closingReason.canceled = this.canceled; | 337 this.closingReason.canceled = this.canceled; |
| 332 }, | 338 }, |
| 333 | 339 |
| 334 _withBackdropChanged: function() { | 340 _withBackdropChanged: function() { |
| 335 // If tabindex is already set, no need to override it. | 341 // If tabindex is already set, no need to override it. |
| 336 if (this.withBackdrop && !this.hasAttribute('tabindex')) { | 342 if (this.withBackdrop && !this.hasAttribute('tabindex')) { |
| 337 this.setAttribute('tabindex', '-1'); | 343 this.setAttribute('tabindex', '-1'); |
| 338 this.__shouldRemoveTabIndex = true; | 344 this.__shouldRemoveTabIndex = true; |
| 339 } else if (this.__shouldRemoveTabIndex) { | 345 } else if (this.__shouldRemoveTabIndex) { |
| 340 this.removeAttribute('tabindex'); | 346 this.removeAttribute('tabindex'); |
| 341 this.__shouldRemoveTabIndex = false; | 347 this.__shouldRemoveTabIndex = false; |
| 342 } | 348 } |
| 343 if (this.opened) { | 349 if (this.opened && this.isAttached) { |
| 344 this._manager.trackBackdrop(); | 350 this._manager.trackBackdrop(); |
| 345 } | 351 } |
| 346 }, | 352 }, |
| 347 | 353 |
| 348 /** | 354 /** |
| 349 * tasks which must occur before opening; e.g. making the element visible. | 355 * tasks which must occur before opening; e.g. making the element visible. |
| 350 * @protected | 356 * @protected |
| 351 */ | 357 */ |
| 352 _prepareRenderOpened: function() { | 358 _prepareRenderOpened: function() { |
| 353 | 359 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 383 /** | 389 /** |
| 384 * Tasks to be performed at the end of open action. Will fire `iron-overlay-
opened`. | 390 * Tasks to be performed at the end of open action. Will fire `iron-overlay-
opened`. |
| 385 * @protected | 391 * @protected |
| 386 */ | 392 */ |
| 387 _finishRenderOpened: function() { | 393 _finishRenderOpened: function() { |
| 388 // Focus the child node with [autofocus] | 394 // Focus the child node with [autofocus] |
| 389 this._applyFocus(); | 395 this._applyFocus(); |
| 390 | 396 |
| 391 this.notifyResize(); | 397 this.notifyResize(); |
| 392 this.__isAnimating = false; | 398 this.__isAnimating = false; |
| 399 |
| 400 // Store it so we don't query too much. |
| 401 var focusableNodes = this._focusableNodes; |
| 402 this.__firstFocusableNode = focusableNodes[0]; |
| 403 this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1]; |
| 404 |
| 393 this.fire('iron-overlay-opened'); | 405 this.fire('iron-overlay-opened'); |
| 394 }, | 406 }, |
| 395 | 407 |
| 396 /** | 408 /** |
| 397 * Tasks to be performed at the end of close action. Will fire `iron-overlay
-closed`. | 409 * Tasks to be performed at the end of close action. Will fire `iron-overlay
-closed`. |
| 398 * @protected | 410 * @protected |
| 399 */ | 411 */ |
| 400 _finishRenderClosed: function() { | 412 _finishRenderClosed: function() { |
| 401 // Hide the overlay and remove the backdrop. | 413 // Hide the overlay and remove the backdrop. |
| 402 this.style.display = 'none'; | 414 this.style.display = 'none'; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 487 } | 499 } |
| 488 }, | 500 }, |
| 489 | 501 |
| 490 /** | 502 /** |
| 491 * Handles TAB key events to track focus changes. | 503 * Handles TAB key events to track focus changes. |
| 492 * Will wrap focus for overlays withBackdrop. | 504 * Will wrap focus for overlays withBackdrop. |
| 493 * @param {!Event} event | 505 * @param {!Event} event |
| 494 * @protected | 506 * @protected |
| 495 */ | 507 */ |
| 496 _onCaptureTab: function(event) { | 508 _onCaptureTab: function(event) { |
| 509 if (!this.withBackdrop) { |
| 510 return; |
| 511 } |
| 497 // TAB wraps from last to first focusable. | 512 // TAB wraps from last to first focusable. |
| 498 // Shift + TAB wraps from first to last focusable. | 513 // Shift + TAB wraps from first to last focusable. |
| 499 var shift = event.shiftKey; | 514 var shift = event.shiftKey; |
| 500 var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusable
Node; | 515 var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusable
Node; |
| 501 var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNo
de; | 516 var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNo
de; |
| 502 if (this.withBackdrop && this._focusedChild === nodeToCheck) { | 517 var shouldWrap = false; |
| 518 if (nodeToCheck === nodeToSet) { |
| 519 // If nodeToCheck is the same as nodeToSet, it means we have an overlay |
| 520 // with 0 or 1 focusables; in either case we still need to trap the |
| 521 // focus within the overlay. |
| 522 shouldWrap = true; |
| 523 } else { |
| 524 // In dom=shadow, the manager will receive focus changes on the main |
| 525 // root but not the ones within other shadow roots, so we can't rely on |
| 526 // _focusedChild, but we should check the deepest active element. |
| 527 var focusedNode = this._manager.deepActiveElement; |
| 528 // If the active element is not the nodeToCheck but the overlay itself, |
| 529 // it means the focus is about to go outside the overlay, hence we |
| 530 // should prevent that (e.g. user opens the overlay and hit Shift+TAB). |
| 531 shouldWrap = (focusedNode === nodeToCheck || focusedNode === this); |
| 532 } |
| 533 |
| 534 if (shouldWrap) { |
| 503 // When the overlay contains the last focusable element of the document | 535 // When the overlay contains the last focusable element of the document |
| 504 // and it's already focused, pressing TAB would move the focus outside | 536 // and it's already focused, pressing TAB would move the focus outside |
| 505 // the document (e.g. to the browser search bar). Similarly, when the | 537 // the document (e.g. to the browser search bar). Similarly, when the |
| 506 // overlay contains the first focusable element of the document and it's | 538 // overlay contains the first focusable element of the document and it's |
| 507 // already focused, pressing Shift+TAB would move the focus outside the | 539 // already focused, pressing Shift+TAB would move the focus outside the |
| 508 // document (e.g. to the browser search bar). | 540 // document (e.g. to the browser search bar). |
| 509 // In both cases, we would not receive a focus event, but only a blur. | 541 // In both cases, we would not receive a focus event, but only a blur. |
| 510 // In order to achieve focus wrapping, we prevent this TAB event and | 542 // In order to achieve focus wrapping, we prevent this TAB event and |
| 511 // force the focus. This will also prevent the focus to temporarily move | 543 // force the focus. This will also prevent the focus to temporarily move |
| 512 // outside the overlay, which might cause scrolling. | 544 // outside the overlay, which might cause scrolling. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 535 | 567 |
| 536 /** | 568 /** |
| 537 * Will call notifyResize if overlay is opened. | 569 * Will call notifyResize if overlay is opened. |
| 538 * Can be overridden in order to avoid multiple observers on the same node. | 570 * Can be overridden in order to avoid multiple observers on the same node. |
| 539 * @protected | 571 * @protected |
| 540 */ | 572 */ |
| 541 _onNodesChange: function() { | 573 _onNodesChange: function() { |
| 542 if (this.opened && !this.__isAnimating) { | 574 if (this.opened && !this.__isAnimating) { |
| 543 this.notifyResize(); | 575 this.notifyResize(); |
| 544 } | 576 } |
| 545 // Store it so we don't query too much. | |
| 546 var focusableNodes = this._focusableNodes; | |
| 547 this.__firstFocusableNode = focusableNodes[0]; | |
| 548 this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1]; | |
| 549 } | 577 } |
| 550 }; | 578 }; |
| 551 | 579 |
| 552 /** @polymerBehavior */ | 580 /** @polymerBehavior */ |
| 553 Polymer.IronOverlayBehavior = [Polymer.IronFitBehavior, Polymer.IronResizableB
ehavior, Polymer.IronOverlayBehaviorImpl]; | 581 Polymer.IronOverlayBehavior = [Polymer.IronFitBehavior, Polymer.IronResizableB
ehavior, Polymer.IronOverlayBehaviorImpl]; |
| 554 | 582 |
| 555 /** | 583 /** |
| 556 * Fired after the overlay opens. | 584 * Fired after the overlay opens. |
| 557 * @event iron-overlay-opened | 585 * @event iron-overlay-opened |
| 558 */ | 586 */ |
| 559 | 587 |
| 560 /** | 588 /** |
| 561 * Fired when the overlay is canceled, but before it is closed. | 589 * Fired when the overlay is canceled, but before it is closed. |
| 562 * @event iron-overlay-canceled | 590 * @event iron-overlay-canceled |
| 563 * @param {Event} event The closing of the overlay can be prevented | 591 * @param {Event} event The closing of the overlay can be prevented |
| 564 * by calling `event.preventDefault()`. The `event.detail` is the original eve
nt that | 592 * by calling `event.preventDefault()`. The `event.detail` is the original eve
nt that |
| 565 * originated the canceling (e.g. ESC keyboard event or click event outside th
e overlay). | 593 * originated the canceling (e.g. ESC keyboard event or click event outside th
e overlay). |
| 566 */ | 594 */ |
| 567 | 595 |
| 568 /** | 596 /** |
| 569 * Fired after the overlay closes. | 597 * Fired after the overlay closes. |
| 570 * @event iron-overlay-closed | 598 * @event iron-overlay-closed |
| 571 * @param {Event} event The `event.detail` is the `closingReason` property | 599 * @param {Event} event The `event.detail` is the `closingReason` property |
| 572 * (contains `canceled`, whether the overlay was canceled). | 600 * (contains `canceled`, whether the overlay was canceled). |
| 573 */ | 601 */ |
| 574 | 602 |
| 575 })(); | 603 })(); |
| OLD | NEW |