| Index: third_party/polymer/components/iron-overlay-behavior/iron-overlay-behavior.html
|
| diff --git a/third_party/polymer/components/iron-overlay-behavior/iron-overlay-behavior.html b/third_party/polymer/components/iron-overlay-behavior/iron-overlay-behavior.html
|
| index 63ade848267bed92a2fe203a8bbfea86bcecae62..b1f2326661efadf8dbc47fe40853af5b9230da96 100644
|
| --- a/third_party/polymer/components/iron-overlay-behavior/iron-overlay-behavior.html
|
| +++ b/third_party/polymer/components/iron-overlay-behavior/iron-overlay-behavior.html
|
| @@ -22,9 +22,12 @@ Use `Polymer.IronOverlayBehavior` to implement an element that can be hidden or
|
| on top of other content. It includes an optional backdrop, and can be used to implement a variety
|
| of UI controls including dialogs and drop downs. Multiple overlays may be displayed at once.
|
|
|
| +See the [demo source code](https://github.com/PolymerElements/iron-overlay-behavior/blob/master/demo/simple-overlay.html)
|
| +for an example.
|
| +
|
| ### Closing and canceling
|
|
|
| -A dialog may be hidden by closing or canceling. The difference between close and cancel is user
|
| +An overlay may be hidden by closing or canceling. The difference between close and cancel is user
|
| intent. Closing generally implies that the user acknowledged the content on the overlay. By default,
|
| it will cancel whenever the user taps outside it or presses the escape key. This behavior is
|
| configurable with the `no-cancel-on-esc-key` and the `no-cancel-on-outside-click` properties.
|
| @@ -43,6 +46,10 @@ Set the `with-backdrop` attribute to display a backdrop behind the overlay. The
|
| appended to `<body>` and is of type `<iron-overlay-backdrop>`. See its doc page for styling
|
| options.
|
|
|
| +In addition, `with-backdrop` will wrap the focus within the content in the light DOM.
|
| +Override the [`_focusableNodes` getter](#Polymer.IronOverlayBehavior:property-_focusableNodes)
|
| +to achieve a different behavior.
|
| +
|
| ### Limitations
|
|
|
| The element is styled to appear on top of other content by setting its `z-index` property. You
|
| @@ -78,7 +85,8 @@ context. You should place this element as a child of `<body>` whenever possible.
|
| },
|
|
|
| /**
|
| - * Set to true to display a backdrop behind the overlay.
|
| + * Set to true to display a backdrop behind the overlay. It traps the focus
|
| + * within the light DOM of the overlay.
|
| */
|
| withBackdrop: {
|
| observer: '_withBackdropChanged',
|
| @@ -316,12 +324,17 @@ context. You should place this element as a child of `<body>` whenever possible.
|
| return;
|
| }
|
|
|
| - this._manager.addOrRemoveOverlay(this);
|
| -
|
| if (this.__openChangedAsync) {
|
| window.cancelAnimationFrame(this.__openChangedAsync);
|
| }
|
|
|
| + // Synchronously remove the overlay.
|
| + // The adding is done asynchronously to go out of the scope of the event
|
| + // which might have generated the opening.
|
| + if (!this.opened) {
|
| + this._manager.removeOverlay(this);
|
| + }
|
| +
|
| // Defer any animation-related code on attached
|
| // (_openedChanged gets called again on attached).
|
| if (!this.isAttached) {
|
| @@ -334,6 +347,7 @@ context. You should place this element as a child of `<body>` whenever possible.
|
| this.__openChangedAsync = window.requestAnimationFrame(function() {
|
| this.__openChangedAsync = null;
|
| if (this.opened) {
|
| + this._manager.addOverlay(this);
|
| this._prepareRenderOpened();
|
| this._renderOpened();
|
| } else {
|
| @@ -356,7 +370,7 @@ context. You should place this element as a child of `<body>` whenever possible.
|
| this.removeAttribute('tabindex');
|
| this.__shouldRemoveTabIndex = false;
|
| }
|
| - if (this.opened) {
|
| + if (this.opened && this.isAttached) {
|
| this._manager.trackBackdrop();
|
| }
|
| },
|
| @@ -406,6 +420,12 @@ context. You should place this element as a child of `<body>` whenever possible.
|
|
|
| this.notifyResize();
|
| this.__isAnimating = false;
|
| +
|
| + // Store it so we don't query too much.
|
| + var focusableNodes = this._focusableNodes;
|
| + this.__firstFocusableNode = focusableNodes[0];
|
| + this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
|
| +
|
| this.fire('iron-overlay-opened');
|
| },
|
|
|
| @@ -510,12 +530,32 @@ context. You should place this element as a child of `<body>` whenever possible.
|
| * @protected
|
| */
|
| _onCaptureTab: function(event) {
|
| + if (!this.withBackdrop) {
|
| + return;
|
| + }
|
| // TAB wraps from last to first focusable.
|
| // Shift + TAB wraps from first to last focusable.
|
| var shift = event.shiftKey;
|
| var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusableNode;
|
| var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNode;
|
| - if (this.withBackdrop && this._focusedChild === nodeToCheck) {
|
| + var shouldWrap = false;
|
| + if (nodeToCheck === nodeToSet) {
|
| + // If nodeToCheck is the same as nodeToSet, it means we have an overlay
|
| + // with 0 or 1 focusables; in either case we still need to trap the
|
| + // focus within the overlay.
|
| + shouldWrap = true;
|
| + } else {
|
| + // In dom=shadow, the manager will receive focus changes on the main
|
| + // root but not the ones within other shadow roots, so we can't rely on
|
| + // _focusedChild, but we should check the deepest active element.
|
| + var focusedNode = this._manager.deepActiveElement;
|
| + // If the active element is not the nodeToCheck but the overlay itself,
|
| + // it means the focus is about to go outside the overlay, hence we
|
| + // should prevent that (e.g. user opens the overlay and hit Shift+TAB).
|
| + shouldWrap = (focusedNode === nodeToCheck || focusedNode === this);
|
| + }
|
| +
|
| + if (shouldWrap) {
|
| // When the overlay contains the last focusable element of the document
|
| // and it's already focused, pressing TAB would move the focus outside
|
| // the document (e.g. to the browser search bar). Similarly, when the
|
| @@ -558,10 +598,6 @@ context. You should place this element as a child of `<body>` whenever possible.
|
| if (this.opened && !this.__isAnimating) {
|
| this.notifyResize();
|
| }
|
| - // Store it so we don't query too much.
|
| - var focusableNodes = this._focusableNodes;
|
| - this.__firstFocusableNode = focusableNodes[0];
|
| - this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
|
| }
|
| };
|
|
|
|
|