mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
update components
This commit is contained in:
parent
ffd37618d5
commit
ccf45da5f9
6 changed files with 274 additions and 214 deletions
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "iron-overlay-behavior",
|
"name": "iron-overlay-behavior",
|
||||||
"version": "1.4.3",
|
"version": "1.5.0",
|
||||||
"license": "http://polymer.github.io/LICENSE.txt",
|
"license": "http://polymer.github.io/LICENSE.txt",
|
||||||
"description": "Provides a behavior for making an element an overlay",
|
"description": "Provides a behavior for making an element an overlay",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
@ -35,11 +35,11 @@
|
||||||
},
|
},
|
||||||
"ignore": [],
|
"ignore": [],
|
||||||
"homepage": "https://github.com/polymerelements/iron-overlay-behavior",
|
"homepage": "https://github.com/polymerelements/iron-overlay-behavior",
|
||||||
"_release": "1.4.3",
|
"_release": "1.5.0",
|
||||||
"_resolution": {
|
"_resolution": {
|
||||||
"type": "version",
|
"type": "version",
|
||||||
"tag": "v1.4.3",
|
"tag": "v1.5.0",
|
||||||
"commit": "6b8662619fbd4e82c2cebce6a846425ff9fc610d"
|
"commit": "700a82504db1c57757dbf4abd176954dcb74e6fb"
|
||||||
},
|
},
|
||||||
"_source": "git://github.com/polymerelements/iron-overlay-behavior.git",
|
"_source": "git://github.com/polymerelements/iron-overlay-behavior.git",
|
||||||
"_target": "^1.0.0",
|
"_target": "^1.0.0",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "iron-overlay-behavior",
|
"name": "iron-overlay-behavior",
|
||||||
"version": "1.4.3",
|
"version": "1.5.0",
|
||||||
"license": "http://polymer.github.io/LICENSE.txt",
|
"license": "http://polymer.github.io/LICENSE.txt",
|
||||||
"description": "Provides a behavior for making an element an overlay",
|
"description": "Provides a behavior for making an element an overlay",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|
|
@ -40,12 +40,14 @@ Custom property | Description | Default
|
||||||
background-color: var(--iron-overlay-backdrop-background-color, #000);
|
background-color: var(--iron-overlay-backdrop-background-color, #000);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.2s;
|
transition: opacity 0.2s;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
@apply(--iron-overlay-backdrop);
|
@apply(--iron-overlay-backdrop);
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([opened]) {
|
:host([opened]) {
|
||||||
opacity: var(--iron-overlay-backdrop-opacity, 0.6);
|
opacity: var(--iron-overlay-backdrop-opacity, 0.6);
|
||||||
|
pointer-events: auto;
|
||||||
|
|
||||||
@apply(--iron-overlay-backdrop-opened);
|
@apply(--iron-overlay-backdrop-opened);
|
||||||
}
|
}
|
||||||
|
@ -93,8 +95,6 @@ Custom property | Description | Default
|
||||||
* Appends the backdrop to document body and sets its `z-index` to be below the latest overlay.
|
* Appends the backdrop to document body and sets its `z-index` to be below the latest overlay.
|
||||||
*/
|
*/
|
||||||
prepare: function() {
|
prepare: function() {
|
||||||
// Always update z-index
|
|
||||||
this.style.zIndex = this._manager.backdropZ();
|
|
||||||
if (!this.parentNode) {
|
if (!this.parentNode) {
|
||||||
Polymer.dom(document.body).appendChild(this);
|
Polymer.dom(document.body).appendChild(this);
|
||||||
}
|
}
|
||||||
|
@ -114,8 +114,6 @@ Custom property | Description | Default
|
||||||
* Hides the backdrop if needed.
|
* Hides the backdrop if needed.
|
||||||
*/
|
*/
|
||||||
close: function() {
|
close: function() {
|
||||||
// Always update z-index
|
|
||||||
this.style.zIndex = this._manager.backdropZ();
|
|
||||||
// close only if no element with backdrop is left
|
// close only if no element with backdrop is left
|
||||||
if (this._manager.getBackdrops().length === 0) {
|
if (this._manager.getBackdrops().length === 0) {
|
||||||
// Read style before setting opened.
|
// Read style before setting opened.
|
||||||
|
|
|
@ -9,7 +9,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<link rel="import" href="../polymer/polymer.html">
|
<link rel="import" href="../polymer/polymer.html">
|
||||||
<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
|
|
||||||
<link rel="import" href="../iron-fit-behavior/iron-fit-behavior.html">
|
<link rel="import" href="../iron-fit-behavior/iron-fit-behavior.html">
|
||||||
<link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
|
<link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
|
||||||
<link rel="import" href="iron-overlay-backdrop.html">
|
<link rel="import" href="iron-overlay-backdrop.html">
|
||||||
|
@ -119,15 +118,6 @@ context. You should place this element as a child of `<body>` whenever possible.
|
||||||
type: Object
|
type: Object
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* The HTMLElement that will be firing relevant KeyboardEvents.
|
|
||||||
* Used for capturing esc and tab. Overridden from `IronA11yKeysBehavior`.
|
|
||||||
*/
|
|
||||||
keyEventTarget: {
|
|
||||||
type: Object,
|
|
||||||
value: document
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set to true to enable restoring of focus when overlay is closed.
|
* Set to true to enable restoring of focus when overlay is closed.
|
||||||
*/
|
*/
|
||||||
|
@ -146,20 +136,6 @@ context. You should place this element as a child of `<body>` whenever possible.
|
||||||
value: Polymer.IronOverlayManager
|
value: Polymer.IronOverlayManager
|
||||||
},
|
},
|
||||||
|
|
||||||
_boundOnCaptureClick: {
|
|
||||||
type: Function,
|
|
||||||
value: function() {
|
|
||||||
return this._onCaptureClick.bind(this);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_boundOnCaptureFocus: {
|
|
||||||
type: Function,
|
|
||||||
value: function() {
|
|
||||||
return this._onCaptureFocus.bind(this);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The node being focused.
|
* The node being focused.
|
||||||
* @type {?Node}
|
* @type {?Node}
|
||||||
|
@ -170,11 +146,6 @@ context. You should place this element as a child of `<body>` whenever possible.
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
keyBindings: {
|
|
||||||
'esc': '__onEsc',
|
|
||||||
'tab': '__onTab'
|
|
||||||
},
|
|
||||||
|
|
||||||
listeners: {
|
listeners: {
|
||||||
'iron-resize': '_onIronResize'
|
'iron-resize': '_onIronResize'
|
||||||
},
|
},
|
||||||
|
@ -270,8 +241,10 @@ context. You should place this element as a child of `<body>` whenever possible.
|
||||||
Polymer.dom(this).unobserveNodes(this._observer);
|
Polymer.dom(this).unobserveNodes(this._observer);
|
||||||
this._observer = null;
|
this._observer = null;
|
||||||
this.opened = false;
|
this.opened = false;
|
||||||
this._manager.trackBackdrop(this);
|
if (this.withBackdrop) {
|
||||||
this._manager.removeOverlay(this);
|
// Allow user interactions right away.
|
||||||
|
this.backdropElement.close();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -333,18 +306,20 @@ context. You should place this element as a child of `<body>` whenever possible.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._manager.trackBackdrop(this);
|
|
||||||
|
|
||||||
this.__isAnimating = true;
|
this.__isAnimating = true;
|
||||||
|
|
||||||
if (this.opened) {
|
if (this.opened) {
|
||||||
this._prepareRenderOpened();
|
this._prepareRenderOpened();
|
||||||
|
} else {
|
||||||
|
this._manager.removeOverlay(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._manager.trackBackdrop(this);
|
||||||
|
|
||||||
if (this._openChangedAsync) {
|
if (this._openChangedAsync) {
|
||||||
this.cancelAsync(this._openChangedAsync);
|
this.cancelAsync(this._openChangedAsync);
|
||||||
}
|
}
|
||||||
// Async here to allow overlay layer to become visible, and to avoid
|
// Async here to allow overlay layer to become visible.
|
||||||
// listeners to immediately close via a click.
|
|
||||||
this._openChangedAsync = this.async(function() {
|
this._openChangedAsync = this.async(function() {
|
||||||
// overlay becomes visible here
|
// overlay becomes visible here
|
||||||
this.style.display = '';
|
this.style.display = '';
|
||||||
|
@ -356,7 +331,6 @@ context. You should place this element as a child of `<body>` whenever possible.
|
||||||
} else {
|
} else {
|
||||||
this._renderClosed();
|
this._renderClosed();
|
||||||
}
|
}
|
||||||
this._toggleListeners();
|
|
||||||
this._openChangedAsync = null;
|
this._openChangedAsync = null;
|
||||||
}, 1);
|
}, 1);
|
||||||
},
|
},
|
||||||
|
@ -389,28 +363,10 @@ context. You should place this element as a child of `<body>` whenever possible.
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_toggleListener: function(enable, node, event, boundListener, capture) {
|
/**
|
||||||
if (enable) {
|
* tasks which must occur before opening; e.g. making the element visible.
|
||||||
// enable document-wide tap recognizer
|
* @protected
|
||||||
if (event === 'tap') {
|
*/
|
||||||
Polymer.Gestures.add(document, 'tap', null);
|
|
||||||
}
|
|
||||||
node.addEventListener(event, boundListener, capture);
|
|
||||||
} else {
|
|
||||||
// disable document-wide tap recognizer
|
|
||||||
if (event === 'tap') {
|
|
||||||
Polymer.Gestures.remove(document, 'tap', null);
|
|
||||||
}
|
|
||||||
node.removeEventListener(event, boundListener, capture);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_toggleListeners: function() {
|
|
||||||
this._toggleListener(this.opened, document, 'tap', this._boundOnCaptureClick, true);
|
|
||||||
this._toggleListener(this.opened, document, 'focus', this._boundOnCaptureFocus, true);
|
|
||||||
},
|
|
||||||
|
|
||||||
// tasks which must occur before opening; e.g. making the element visible
|
|
||||||
_prepareRenderOpened: function() {
|
_prepareRenderOpened: function() {
|
||||||
|
|
||||||
this._manager.addOverlay(this);
|
this._manager.addOverlay(this);
|
||||||
|
@ -432,8 +388,10 @@ context. You should place this element as a child of `<body>` whenever possible.
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// tasks which cause the overlay to actually open; typically play an
|
/**
|
||||||
// animation
|
* Tasks which cause the overlay to actually open; typically play an animation.
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
_renderOpened: function() {
|
_renderOpened: function() {
|
||||||
if (this.withBackdrop) {
|
if (this.withBackdrop) {
|
||||||
this.backdropElement.open();
|
this.backdropElement.open();
|
||||||
|
@ -441,6 +399,10 @@ context. You should place this element as a child of `<body>` whenever possible.
|
||||||
this._finishRenderOpened();
|
this._finishRenderOpened();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tasks which cause the overlay to actually close; typically play an animation.
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
_renderClosed: function() {
|
_renderClosed: function() {
|
||||||
if (this.withBackdrop) {
|
if (this.withBackdrop) {
|
||||||
this.backdropElement.close();
|
this.backdropElement.close();
|
||||||
|
@ -448,6 +410,10 @@ context. You should place this element as a child of `<body>` whenever possible.
|
||||||
this._finishRenderClosed();
|
this._finishRenderClosed();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tasks to be performed at the end of open action. Will fire `iron-overlay-opened`.
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
_finishRenderOpened: function() {
|
_finishRenderOpened: function() {
|
||||||
// Focus the child node with [autofocus]
|
// Focus the child node with [autofocus]
|
||||||
this._applyFocus();
|
this._applyFocus();
|
||||||
|
@ -457,10 +423,13 @@ context. You should place this element as a child of `<body>` whenever possible.
|
||||||
this.fire('iron-overlay-opened');
|
this.fire('iron-overlay-opened');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tasks to be performed at the end of close action. Will fire `iron-overlay-closed`.
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
_finishRenderClosed: function() {
|
_finishRenderClosed: function() {
|
||||||
// Hide the overlay and remove the backdrop.
|
// Hide the overlay and remove the backdrop.
|
||||||
this.style.display = 'none';
|
this.style.display = 'none';
|
||||||
this._manager.removeOverlay(this);
|
|
||||||
|
|
||||||
this._applyFocus();
|
this._applyFocus();
|
||||||
|
|
||||||
|
@ -484,6 +453,10 @@ context. You should place this element as a child of `<body>` whenever possible.
|
||||||
this.style.transition = this.style.webkitTransition = '';
|
this.style.transition = this.style.webkitTransition = '';
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies focus according to the opened state.
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
_applyFocus: function() {
|
_applyFocus: function() {
|
||||||
if (this.opened) {
|
if (this.opened) {
|
||||||
if (!this.noAutoFocus) {
|
if (!this.noAutoFocus) {
|
||||||
|
@ -496,29 +469,69 @@ context. You should place this element as a child of `<body>` whenever possible.
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels (closes) the overlay. Call when click happens outside the overlay.
|
||||||
|
* @param {!Event} event
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
_onCaptureClick: function(event) {
|
_onCaptureClick: function(event) {
|
||||||
if (this._manager.currentOverlay() === this &&
|
if (!this.noCancelOnOutsideClick) {
|
||||||
Polymer.dom(event).path.indexOf(this) === -1) {
|
this.cancel(event);
|
||||||
if (this.noCancelOnOutsideClick) {
|
|
||||||
this._applyFocus();
|
|
||||||
} else {
|
|
||||||
this.cancel(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps track of the focused child. If withBackdrop, traps focus within overlay.
|
||||||
|
* @param {!Event} event
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
_onCaptureFocus: function (event) {
|
_onCaptureFocus: function (event) {
|
||||||
if (this._manager.currentOverlay() === this && this.withBackdrop) {
|
if (!this.withBackdrop) {
|
||||||
var path = Polymer.dom(event).path;
|
return;
|
||||||
if (path.indexOf(this) === -1) {
|
}
|
||||||
event.stopPropagation();
|
var path = Polymer.dom(event).path;
|
||||||
this._applyFocus();
|
if (path.indexOf(this) === -1) {
|
||||||
} else {
|
event.stopPropagation();
|
||||||
this._focusedChild = path[0];
|
this._applyFocus();
|
||||||
}
|
} else {
|
||||||
|
this._focusedChild = path[0];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the ESC key event and cancels (closes) the overlay.
|
||||||
|
* @param {!Event} event
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
_onCaptureEsc: function(event) {
|
||||||
|
if (!this.noCancelOnEscKey) {
|
||||||
|
this.cancel(event);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles TAB key events to track focus changes.
|
||||||
|
* Will wrap focus for overlays withBackdrop.
|
||||||
|
* @param {!Event} event
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
_onCaptureTab: function(event) {
|
||||||
|
// 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) {
|
||||||
|
// We set here the _focusedChild so that _onCaptureFocus will handle the
|
||||||
|
// wrapping of the focus (the next event after tab is focus).
|
||||||
|
this._focusedChild = nodeToSet;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refits if the overlay is opened and not animating.
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
_onIronResize: function() {
|
_onIronResize: function() {
|
||||||
if (this.__isAnimating) {
|
if (this.__isAnimating) {
|
||||||
return;
|
return;
|
||||||
|
@ -530,9 +543,9 @@ context. You should place this element as a child of `<body>` whenever possible.
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @protected
|
|
||||||
* Will call notifyResize if overlay is opened.
|
* Will call notifyResize if overlay is opened.
|
||||||
* Can be overridden in order to avoid multiple observers on the same node.
|
* Can be overridden in order to avoid multiple observers on the same node.
|
||||||
|
* @protected
|
||||||
*/
|
*/
|
||||||
_onNodesChange: function() {
|
_onNodesChange: function() {
|
||||||
if (this.opened && !this.__isAnimating) {
|
if (this.opened && !this.__isAnimating) {
|
||||||
|
@ -542,33 +555,6 @@ context. You should place this element as a child of `<body>` whenever possible.
|
||||||
var focusableNodes = this._focusableNodes;
|
var focusableNodes = this._focusableNodes;
|
||||||
this.__firstFocusableNode = focusableNodes[0];
|
this.__firstFocusableNode = focusableNodes[0];
|
||||||
this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
|
this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
|
||||||
},
|
|
||||||
|
|
||||||
__onEsc: function(event) {
|
|
||||||
// Not opened or not on top, so return.
|
|
||||||
if (this._manager.currentOverlay() !== this) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.noCancelOnEscKey) {
|
|
||||||
this.cancel(event);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
__onTab: function(event) {
|
|
||||||
// Not opened or not on top, so return.
|
|
||||||
if (this._manager.currentOverlay() !== this) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// TAB wraps from last to first focusable.
|
|
||||||
// Shift + TAB wraps from first to last focusable.
|
|
||||||
var shift = event.detail.keyboardEvent.shiftKey;
|
|
||||||
var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusableNode;
|
|
||||||
var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNode;
|
|
||||||
if (this.withBackdrop && this._focusedChild === nodeToCheck) {
|
|
||||||
// We set here the _focusedChild so that _onCaptureFocus will handle the
|
|
||||||
// wrapping of the focus (the next event after tab is focus).
|
|
||||||
this._focusedChild = nodeToSet;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<link rel="import" href="../polymer/polymer.html">
|
<link rel="import" href="../polymer/polymer.html">
|
||||||
|
<link rel="import" href="../iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
@ -24,12 +25,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
*/
|
*/
|
||||||
this._overlays = [];
|
this._overlays = [];
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to keep track of the last focused node before an overlay gets opened.
|
|
||||||
* @private {Array<Element>}
|
|
||||||
*/
|
|
||||||
this._lastFocusedNodes = [];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* iframes have a default z-index of 100,
|
* iframes have a default z-index of 100,
|
||||||
* so this default should be at least that.
|
* so this default should be at least that.
|
||||||
|
@ -37,17 +32,19 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
*/
|
*/
|
||||||
this._minimumZ = 101;
|
this._minimumZ = 101;
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to keep track of the opened overlays with backdrop.
|
|
||||||
* @private {Array<Element>}
|
|
||||||
*/
|
|
||||||
this._backdrops = [];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Memoized backdrop element.
|
* Memoized backdrop element.
|
||||||
* @private {Element|null}
|
* @private {Element|null}
|
||||||
*/
|
*/
|
||||||
this._backdropElement = null;
|
this._backdropElement = null;
|
||||||
|
|
||||||
|
// Enable document-wide tap recognizer.
|
||||||
|
Polymer.Gestures.add(document, 'tap', null);
|
||||||
|
// We should be using only 'tap', but this would be a breaking change.
|
||||||
|
var tapEvent = ('ontouchstart' in window) ? 'tap' : 'click';
|
||||||
|
document.addEventListener(tapEvent, this._onCaptureClick.bind(this), true);
|
||||||
|
document.addEventListener('focus', this._onCaptureFocus.bind(this), true);
|
||||||
|
document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true);
|
||||||
};
|
};
|
||||||
|
|
||||||
Polymer.IronOverlayManagerClass.prototype = {
|
Polymer.IronOverlayManagerClass.prototype = {
|
||||||
|
@ -67,54 +64,19 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The deepest active element.
|
* The deepest active element.
|
||||||
* @type {Element|undefined} activeElement the active element
|
* @type {Element} activeElement the active element
|
||||||
*/
|
*/
|
||||||
get deepActiveElement() {
|
get deepActiveElement() {
|
||||||
var active = document.activeElement;
|
|
||||||
// document.activeElement can be null
|
// document.activeElement can be null
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
|
// https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
|
||||||
while (active && active.root && Polymer.dom(active.root).activeElement) {
|
// In case of null, default it to document.body.
|
||||||
|
var active = document.activeElement || document.body;
|
||||||
|
while (active.root && Polymer.dom(active.root).activeElement) {
|
||||||
active = Polymer.dom(active.root).activeElement;
|
active = Polymer.dom(active.root).activeElement;
|
||||||
}
|
}
|
||||||
return active;
|
return active;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* If a node is contained in an overlay.
|
|
||||||
* @param {Element=} node
|
|
||||||
* @return {boolean}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_isChildOfOverlay: function(node) {
|
|
||||||
while (node && node !== document.body) {
|
|
||||||
// Use logical parentNode, or native ShadowRoot host.
|
|
||||||
node = Polymer.dom(node).parentNode || node.host;
|
|
||||||
// Check if it is an overlay.
|
|
||||||
if (node && node.behaviors && node.behaviors.indexOf(Polymer.IronOverlayBehaviorImpl) !== -1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Element} overlay
|
|
||||||
* @param {number} aboveZ
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_applyOverlayZ: function(overlay, aboveZ) {
|
|
||||||
this._setZ(overlay, aboveZ + 2);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Element} element
|
|
||||||
* @param {number|string} z
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_setZ: function(element, z) {
|
|
||||||
element.style.zIndex = z;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tracks overlays for z-index and focus management.
|
* Tracks overlays for z-index and focus management.
|
||||||
* @param {Element} overlay
|
* @param {Element} overlay
|
||||||
|
@ -127,11 +89,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
this._applyOverlayZ(overlay, minimumZ);
|
this._applyOverlayZ(overlay, minimumZ);
|
||||||
}
|
}
|
||||||
var element = this.deepActiveElement;
|
var element = this.deepActiveElement;
|
||||||
// If already in other overlay, don't reset focus there.
|
overlay.restoreFocusNode = this._overlayParent(element) ? null : element;
|
||||||
if (this._isChildOfOverlay(element)) {
|
|
||||||
element = null;
|
|
||||||
}
|
|
||||||
this._lastFocusedNodes.push(element);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -143,31 +101,30 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
this._overlays.splice(i, 1);
|
this._overlays.splice(i, 1);
|
||||||
this._setZ(overlay, '');
|
this._setZ(overlay, '');
|
||||||
|
|
||||||
var node = this._lastFocusedNodes[i];
|
var node = overlay.restoreFocusOnClose ? overlay.restoreFocusNode : null;
|
||||||
// Focus only if still contained in document.body
|
overlay.restoreFocusNode = null;
|
||||||
if (overlay.restoreFocusOnClose && node && Polymer.dom(document.body).deepContains(node)) {
|
// Focus back only if still contained in document.body
|
||||||
|
if (node && Polymer.dom(document.body).deepContains(node)) {
|
||||||
node.focus();
|
node.focus();
|
||||||
}
|
}
|
||||||
this._lastFocusedNodes.splice(i, 1);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {Element|undefined} overlay The current overlay.
|
* Returns the current overlay.
|
||||||
|
* @return {Element|undefined}
|
||||||
*/
|
*/
|
||||||
currentOverlay: function() {
|
currentOverlay: function() {
|
||||||
var i = this._overlays.length - 1;
|
var i = this._overlays.length - 1;
|
||||||
while (this._overlays[i] && !this._overlays[i].opened) {
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
return this._overlays[i];
|
return this._overlays[i];
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {number} zIndex the current overlay z-index.
|
* Returns the current overlay z-index.
|
||||||
|
* @return {number}
|
||||||
*/
|
*/
|
||||||
currentOverlayZ: function() {
|
currentOverlayZ: function() {
|
||||||
return this._getOverlayZ(this.currentOverlay());
|
return this._getZ(this.currentOverlay());
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -198,38 +155,38 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
* @param {Element} overlay The overlay that updated its withBackdrop.
|
* @param {Element} overlay The overlay that updated its withBackdrop.
|
||||||
*/
|
*/
|
||||||
trackBackdrop: function(overlay) {
|
trackBackdrop: function(overlay) {
|
||||||
var index = this._backdrops.indexOf(overlay);
|
this.backdropElement.style.zIndex = this.backdropZ();
|
||||||
if (overlay.opened && overlay.withBackdrop) {
|
|
||||||
// no duplicates
|
|
||||||
if (index === -1) {
|
|
||||||
this._backdrops.push(overlay);
|
|
||||||
}
|
|
||||||
} else if (index >= 0) {
|
|
||||||
this._backdrops.splice(index, 1);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {Array<Element>} backdrops
|
* @return {Array<Element>}
|
||||||
*/
|
*/
|
||||||
getBackdrops: function() {
|
getBackdrops: function() {
|
||||||
return this._backdrops;
|
var backdrops = [];
|
||||||
|
for (var i = 0; i < this._overlays.length; i++) {
|
||||||
|
if (this._overlays[i].withBackdrop) {
|
||||||
|
backdrops.push(this._overlays[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return backdrops;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {number} index The z-index for the backdrop.
|
* Returns the z-index for the backdrop.
|
||||||
|
* @return {number}
|
||||||
*/
|
*/
|
||||||
backdropZ: function() {
|
backdropZ: function() {
|
||||||
return this._getOverlayZ(this._overlayWithBackdrop()) - 1;
|
return this._getZ(this._overlayWithBackdrop()) - 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {Element|undefined} overlay The first opened overlay that has a backdrop.
|
* Returns the first opened overlay that has a backdrop.
|
||||||
|
* @return {Element|undefined}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_overlayWithBackdrop: function() {
|
_overlayWithBackdrop: function() {
|
||||||
for (var i = 0; i < this._overlays.length; i++) {
|
for (var i = 0; i < this._overlays.length; i++) {
|
||||||
if (this._overlays[i].opened && this._overlays[i].withBackdrop) {
|
if (this._overlays[i].withBackdrop) {
|
||||||
return this._overlays[i];
|
return this._overlays[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,7 +197,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
* @param {Element=} overlay
|
* @param {Element=} overlay
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_getOverlayZ: function(overlay) {
|
_getZ: function(overlay) {
|
||||||
var z = this._minimumZ;
|
var z = this._minimumZ;
|
||||||
if (overlay) {
|
if (overlay) {
|
||||||
var z1 = Number(window.getComputedStyle(overlay).zIndex);
|
var z1 = Number(window.getComputedStyle(overlay).zIndex);
|
||||||
|
@ -251,6 +208,84 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return z;
|
return z;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Element} element
|
||||||
|
* @param {number|string} z
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_setZ: function(element, z) {
|
||||||
|
element.style.zIndex = z;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Element} overlay
|
||||||
|
* @param {number} aboveZ
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_applyOverlayZ: function(overlay, aboveZ) {
|
||||||
|
this._setZ(overlay, aboveZ + 2);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the overlay containing the provided node. If the node is an overlay,
|
||||||
|
* it returns the node.
|
||||||
|
* @param {Element=} node
|
||||||
|
* @return {Element|undefined}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_overlayParent: function(node) {
|
||||||
|
while (node && node !== document.body) {
|
||||||
|
// Check if it is an overlay.
|
||||||
|
if (node._manager === this) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
// Use logical parentNode, or native ShadowRoot host.
|
||||||
|
node = Polymer.dom(node).parentNode || node.host;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures the click event is delegated to the right overlay.
|
||||||
|
* @param {!Event} event
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_onCaptureClick: function(event) {
|
||||||
|
var overlay = /** @type {?} */ (this.currentOverlay());
|
||||||
|
// Check if clicked outside of any overlay.
|
||||||
|
var target = Polymer.dom(event).rootTarget;
|
||||||
|
if (overlay && this._overlayParent(target) !== overlay) {
|
||||||
|
overlay._onCaptureClick(event);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures the focus event is delegated to the right overlay.
|
||||||
|
* @param {!Event} event
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_onCaptureFocus: function(event) {
|
||||||
|
var overlay = /** @type {?} */ (this.currentOverlay());
|
||||||
|
if (overlay) {
|
||||||
|
overlay._onCaptureFocus(event);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures TAB and ESC keyboard events are delegated to the right overlay.
|
||||||
|
* @param {!Event} event
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_onCaptureKeyDown: function(event) {
|
||||||
|
var overlay = /** @type {?} */ (this.currentOverlay());
|
||||||
|
if (overlay) {
|
||||||
|
if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc')) {
|
||||||
|
overlay._onCaptureEsc(event);
|
||||||
|
} else if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'tab')) {
|
||||||
|
overlay._onCaptureTab(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -186,27 +186,23 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('closed overlay does not trigger iron-resize when its content changes', function(done) {
|
test('closed overlay does not trigger iron-resize when its content changes', function() {
|
||||||
// Ignore iron-resize triggered by window resize.
|
// Ignore iron-resize triggered by window resize.
|
||||||
var callCount = 0;
|
var callCount = 0;
|
||||||
window.addEventListener('resize', function() { callCount--; }, true);
|
window.addEventListener('resize', function() { callCount--; }, true);
|
||||||
overlay.addEventListener('iron-resize', function() { callCount++; });
|
overlay.addEventListener('iron-resize', function() { callCount++; });
|
||||||
Polymer.dom(overlay).appendChild(document.createElement('div'));
|
Polymer.dom(overlay).appendChild(document.createElement('div'));
|
||||||
overlay.async(function() {
|
Polymer.dom.flush();
|
||||||
assert.equal(callCount, 0, 'iron-resize should not be called');
|
assert.equal(callCount, 0, 'iron-resize should not be called');
|
||||||
done();
|
|
||||||
}, 10);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('open overlay triggers iron-resize when its content changes', function(done) {
|
test('open overlay triggers iron-resize when its content changes', function() {
|
||||||
runAfterOpen(overlay, function() {
|
runAfterOpen(overlay, function() {
|
||||||
var spy = sinon.stub();
|
var spy = sinon.stub();
|
||||||
overlay.addEventListener('iron-resize', spy);
|
overlay.addEventListener('iron-resize', spy);
|
||||||
Polymer.dom(overlay).appendChild(document.createElement('div'));
|
Polymer.dom(overlay).appendChild(document.createElement('div'));
|
||||||
overlay.async(function() {
|
Polymer.dom.flush();
|
||||||
assert.equal(spy.callCount, 1, 'iron-resize should be called once');
|
assert.equal(spy.callCount, 1, 'iron-resize should be called once');
|
||||||
done();
|
|
||||||
}, 10);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -334,6 +330,38 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
suite('keyboard event listener', function() {
|
||||||
|
var overlay;
|
||||||
|
|
||||||
|
var preventKeyDown = function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
suiteSetup(function() {
|
||||||
|
// Worst case scenario: listener with useCapture = true that prevents & stops propagation
|
||||||
|
// added before the overlay is initialized.
|
||||||
|
document.addEventListener('keydown', preventKeyDown, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
setup(function() {
|
||||||
|
overlay = fixture('basic');
|
||||||
|
});
|
||||||
|
|
||||||
|
suiteTeardown(function() {
|
||||||
|
document.removeEventListener('keydown', preventKeyDown, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('cancel an overlay with esc key even if event is prevented by other listeners', function(done) {
|
||||||
|
runAfterOpen(overlay, function() {
|
||||||
|
overlay.addEventListener('iron-overlay-canceled', function(event) {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
MockInteractions.pressAndReleaseKeyOn(document, 27);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
suite('opened overlay', function() {
|
suite('opened overlay', function() {
|
||||||
var overlay;
|
var overlay;
|
||||||
|
|
||||||
|
@ -369,7 +397,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('focus handling', function() {
|
suite('focus handling', function() {
|
||||||
|
@ -632,7 +659,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
runAfterOpen(overlay, function() {
|
runAfterOpen(overlay, function() {
|
||||||
runAfterClose(overlay, function() {
|
runAfterClose(overlay, function() {
|
||||||
assert.isFalse(overlay.backdropElement.opened, 'backdrop is closed');
|
assert.isFalse(overlay.backdropElement.opened, 'backdrop is closed');
|
||||||
assert.isNull(overlay.backdropElement.parentNode, 'backdrop is removed from the DOM');
|
assert.isNotOk(overlay.backdropElement.parentNode, 'backdrop is removed from the DOM');
|
||||||
assert.lengthOf(document.querySelectorAll('iron-overlay-backdrop'), 0, 'no backdrop elements on body');
|
assert.lengthOf(document.querySelectorAll('iron-overlay-backdrop'), 0, 'no backdrop elements on body');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -642,12 +669,13 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
test('backdrop is removed when the element is removed from DOM', function(done) {
|
test('backdrop is removed when the element is removed from DOM', function(done) {
|
||||||
runAfterOpen(overlay, function() {
|
runAfterOpen(overlay, function() {
|
||||||
Polymer.dom(overlay).parentNode.removeChild(overlay);
|
Polymer.dom(overlay).parentNode.removeChild(overlay);
|
||||||
// Wait enough so detached is executed.
|
// Ensure detached is executed.
|
||||||
Polymer.Base.async(function() {
|
Polymer.dom.flush();
|
||||||
assert.isNull(overlay.backdropElement.parentNode, 'backdrop is removed from the DOM');
|
assert.isFalse(overlay.backdropElement.opened, 'backdrop is closed');
|
||||||
assert.lengthOf(document.querySelectorAll('iron-overlay-backdrop'), 0, 'no backdrop elements on body');
|
assert.isNotOk(overlay.backdropElement.parentNode, 'backdrop is removed from the DOM');
|
||||||
done();
|
assert.lengthOf(document.querySelectorAll('iron-overlay-backdrop'), 0, 'no backdrop elements on body');
|
||||||
}, 100);
|
assert.isNotOk(overlay._manager.currentOverlay(), 'currentOverlay ok');
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -676,7 +704,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('multiple overlays', function() {
|
suite('multiple overlays', function() {
|
||||||
|
@ -819,6 +846,20 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('click events handled only by top overlay', function(done) {
|
||||||
|
var btn = document.createElement('button');
|
||||||
|
btn.addEventListener('tap', overlay2.close.bind(overlay2));
|
||||||
|
Polymer.dom(overlay2).appendChild(btn);
|
||||||
|
runAfterOpen(overlay1, function() {
|
||||||
|
runAfterOpen(overlay2, function() {
|
||||||
|
MockInteractions.tap(btn);
|
||||||
|
assert.isFalse(overlay2.opened, 'overlay2 closed');
|
||||||
|
assert.isTrue(overlay1.opened, 'overlay1 still opened');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('updating with-backdrop updates z-index', function(done) {
|
test('updating with-backdrop updates z-index', function(done) {
|
||||||
runAfterOpen(overlay1, function() {
|
runAfterOpen(overlay1, function() {
|
||||||
runAfterOpen(overlay2, function() {
|
runAfterOpen(overlay2, function() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue