mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
update confirm
This commit is contained in:
parent
166a16b60d
commit
1ea5d5f307
191 changed files with 8714 additions and 48569 deletions
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "iron-overlay-behavior",
|
||||
"version": "1.3.3",
|
||||
"version": "1.4.0",
|
||||
"license": "http://polymer.github.io/LICENSE.txt",
|
||||
"description": "Provides a behavior for making an element an overlay",
|
||||
"private": true,
|
||||
|
@ -19,6 +19,7 @@
|
|||
"url": "git://github.com/PolymerElements/iron-overlay-behavior.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0",
|
||||
"iron-fit-behavior": "PolymerElements/iron-fit-behavior#^1.0.0",
|
||||
"iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0",
|
||||
"polymer": "Polymer/polymer#^1.0.0"
|
||||
|
@ -34,11 +35,11 @@
|
|||
},
|
||||
"ignore": [],
|
||||
"homepage": "https://github.com/polymerelements/iron-overlay-behavior",
|
||||
"_release": "1.3.3",
|
||||
"_release": "1.4.0",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "v1.3.3",
|
||||
"commit": "7279b3bedd0f0dd70dbfb3d7557d1f49c7432941"
|
||||
"tag": "v1.4.0",
|
||||
"commit": "9731850e81b004723f0c1878a85479f7aa9cfda1"
|
||||
},
|
||||
"_source": "git://github.com/polymerelements/iron-overlay-behavior.git",
|
||||
"_target": "^1.0.0",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "iron-overlay-behavior",
|
||||
"version": "1.3.3",
|
||||
"version": "1.4.0",
|
||||
"license": "http://polymer.github.io/LICENSE.txt",
|
||||
"description": "Provides a behavior for making an element an overlay",
|
||||
"private": true,
|
||||
|
@ -19,6 +19,7 @@
|
|||
"url": "git://github.com/PolymerElements/iron-overlay-behavior.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0",
|
||||
"iron-fit-behavior": "PolymerElements/iron-fit-behavior#^1.0.0",
|
||||
"iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0",
|
||||
"polymer": "Polymer/polymer#^1.0.0"
|
||||
|
|
|
@ -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="../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-resizable-behavior/iron-resizable-behavior.html">
|
||||
<link rel="import" href="iron-overlay-backdrop.html">
|
||||
|
@ -118,6 +119,15 @@ context. You should place this element as a child of `<body>` whenever possible.
|
|||
type: Object
|
||||
},
|
||||
|
||||
/**
|
||||
* The HTMLElement that will be firing relevant KeyboardEvents.
|
||||
* Used for capturing esc and tab. Overridden from `IronA11yKeysBehavior`.
|
||||
*/
|
||||
keyEventTarget: {
|
||||
type: Object,
|
||||
value: document
|
||||
},
|
||||
|
||||
_manager: {
|
||||
type: Object,
|
||||
value: Polymer.IronOverlayManager
|
||||
|
@ -130,13 +140,6 @@ context. You should place this element as a child of `<body>` whenever possible.
|
|||
}
|
||||
},
|
||||
|
||||
_boundOnCaptureKeydown: {
|
||||
type: Function,
|
||||
value: function() {
|
||||
return this._onCaptureKeydown.bind(this);
|
||||
}
|
||||
},
|
||||
|
||||
_boundOnCaptureFocus: {
|
||||
type: Function,
|
||||
value: function() {
|
||||
|
@ -144,33 +147,99 @@ context. You should place this element as a child of `<body>` whenever possible.
|
|||
}
|
||||
},
|
||||
|
||||
/** @type {?Node} */
|
||||
/**
|
||||
* The node being focused.
|
||||
* @type {?Node}
|
||||
*/
|
||||
_focusedChild: {
|
||||
type: Object
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
keyBindings: {
|
||||
'esc': '__onEsc',
|
||||
'tab': '__onTab'
|
||||
},
|
||||
|
||||
listeners: {
|
||||
'iron-resize': '_onIronResize'
|
||||
},
|
||||
|
||||
/**
|
||||
* The backdrop element.
|
||||
* @type Node
|
||||
* @type {Node}
|
||||
*/
|
||||
get backdropElement() {
|
||||
return this._manager.backdropElement;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the node to give focus to.
|
||||
* @type {Node}
|
||||
*/
|
||||
get _focusNode() {
|
||||
return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]') || this;
|
||||
return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]') || this.__firstFocusableNode || this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Array of nodes that can receive focus (overlay included), ordered by `tabindex`.
|
||||
* This is used to retrieve which is the first and last focusable nodes in order
|
||||
* to wrap the focus for overlays `with-backdrop`.
|
||||
*
|
||||
* If you know what is your content (specifically the first and last focusable children),
|
||||
* you can override this method to return only `[firstFocusable, lastFocusable];`
|
||||
* @type {[Node]}
|
||||
* @protected
|
||||
*/
|
||||
get _focusableNodes() {
|
||||
// Elements that can be focused even if they have [disabled] attribute.
|
||||
var FOCUSABLE_WITH_DISABLED = [
|
||||
'a[href]',
|
||||
'area[href]',
|
||||
'iframe',
|
||||
'[tabindex]',
|
||||
'[contentEditable=true]'
|
||||
];
|
||||
|
||||
// Elements that cannot be focused if they have [disabled] attribute.
|
||||
var FOCUSABLE_WITHOUT_DISABLED = [
|
||||
'input',
|
||||
'select',
|
||||
'textarea',
|
||||
'button'
|
||||
];
|
||||
|
||||
// Discard elements with tabindex=-1 (makes them not focusable).
|
||||
var selector = FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),') +
|
||||
':not([tabindex="-1"]),' +
|
||||
FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([tabindex="-1"]),') +
|
||||
':not([disabled]):not([tabindex="-1"])';
|
||||
|
||||
var focusables = Polymer.dom(this).querySelectorAll(selector);
|
||||
if (this.tabIndex >= 0) {
|
||||
// Insert at the beginning because we might have all elements with tabIndex = 0,
|
||||
// and the overlay should be the first of the list.
|
||||
focusables.splice(0, 0, this);
|
||||
}
|
||||
// Sort by tabindex.
|
||||
return focusables.sort(function (a, b) {
|
||||
if (a.tabIndex === b.tabIndex) {
|
||||
return 0;
|
||||
}
|
||||
if (a.tabIndex === 0 || a.tabIndex > b.tabIndex) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
});
|
||||
},
|
||||
|
||||
ready: function() {
|
||||
// with-backdrop need tabindex to be set in order to trap the focus.
|
||||
// If it is not set, IronOverlayBehavior will set it, and remove it if with-backdrop = false.
|
||||
this.__shouldRemoveTabIndex = false;
|
||||
// Used for wrapping the focus on TAB / Shift+TAB.
|
||||
this.__firstFocusableNode = this.__lastFocusableNode = null;
|
||||
this._ensureSetup();
|
||||
},
|
||||
|
||||
|
@ -321,9 +390,8 @@ context. You should place this element as a child of `<body>` whenever possible.
|
|||
}
|
||||
},
|
||||
|
||||
_toggleListeners: function () {
|
||||
_toggleListeners: function() {
|
||||
this._toggleListener(this.opened, document, 'tap', this._boundOnCaptureClick, true);
|
||||
this._toggleListener(this.opened, document, 'keydown', this._boundOnCaptureKeydown, true);
|
||||
this._toggleListener(this.opened, document, 'focus', this._boundOnCaptureFocus, true);
|
||||
},
|
||||
|
||||
|
@ -425,18 +493,8 @@ context. You should place this element as a child of `<body>` whenever possible.
|
|||
}
|
||||
},
|
||||
|
||||
_onCaptureKeydown: function(event) {
|
||||
var ESC = 27;
|
||||
if (this._manager.currentOverlay() === this &&
|
||||
!this.noCancelOnEscKey &&
|
||||
event.keyCode === ESC) {
|
||||
this.cancel(event);
|
||||
}
|
||||
},
|
||||
|
||||
_onCaptureFocus: function (event) {
|
||||
if (this._manager.currentOverlay() === this &&
|
||||
this.withBackdrop) {
|
||||
if (this._manager.currentOverlay() === this && this.withBackdrop) {
|
||||
var path = Polymer.dom(event).path;
|
||||
if (path.indexOf(this) === -1) {
|
||||
event.stopPropagation();
|
||||
|
@ -462,6 +520,37 @@ context. You should place this element as a child of `<body>` whenever possible.
|
|||
if (this.opened) {
|
||||
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];
|
||||
},
|
||||
|
||||
__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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -484,7 +573,7 @@ context. You should place this element as a child of `<body>` whenever possible.
|
|||
};
|
||||
|
||||
/** @polymerBehavior */
|
||||
Polymer.IronOverlayBehavior = [Polymer.IronFitBehavior, Polymer.IronResizableBehavior, Polymer.IronOverlayBehaviorImpl];
|
||||
Polymer.IronOverlayBehavior = [Polymer.IronA11yKeysBehavior, Polymer.IronFitBehavior, Polymer.IronResizableBehavior, Polymer.IronOverlayBehaviorImpl];
|
||||
|
||||
|
||||
</script>
|
||||
|
|
|
@ -63,6 +63,33 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<test-fixture id="focusables">
|
||||
<template>
|
||||
<test-overlay tabindex="-1">
|
||||
<h2>Focusables (no tabindex)</h2>
|
||||
<div>
|
||||
<input class="focusable1" placeholder="1 (nested)">
|
||||
</div>
|
||||
<button class="focusable2">1</button>
|
||||
<button disabled> disabled button</button>
|
||||
<div tabindex="-1">not focusable</div>
|
||||
<button class="focusable3">2</button>
|
||||
</test-overlay>
|
||||
<test-overlay tabindex="-1">
|
||||
<h2>Focusables (with tabindex)</h2>
|
||||
<div tabindex="-1">not focusable</div>
|
||||
<div tabindex="3" class="focusable3">3</div>
|
||||
<div tabindex="4" class="focusable4">4</div>
|
||||
<div tabindex="5" class="focusable5">5</div>
|
||||
<div>
|
||||
<div tabindex="1" class="focusable1">1 (nested)</div>
|
||||
<div tabindex="6" class="focusable6">6 (nested)</div>
|
||||
</div>
|
||||
<div tabindex="2" class="focusable2">2</div>
|
||||
</test-overlay>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<test-fixture id="backdrop">
|
||||
<template>
|
||||
<test-overlay with-backdrop>
|
||||
|
@ -391,6 +418,86 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
|
||||
});
|
||||
|
||||
suite('focusable nodes', function() {
|
||||
var overlay, overlayWithTabIndex;
|
||||
|
||||
setup(function() {
|
||||
var f = fixture('focusables');
|
||||
overlay = f[0];
|
||||
overlayWithTabIndex = f[1];
|
||||
});
|
||||
|
||||
test('_focusableNodes returns nodes that are focusable', function() {
|
||||
var focusableNodes = overlay._focusableNodes;
|
||||
assert.equal(focusableNodes.length, 3, '3 nodes are focusable');
|
||||
assert.equal(focusableNodes[0], Polymer.dom(overlay).querySelector('.focusable1'));
|
||||
assert.equal(focusableNodes[1], Polymer.dom(overlay).querySelector('.focusable2'));
|
||||
assert.equal(focusableNodes[2], Polymer.dom(overlay).querySelector('.focusable3'));
|
||||
});
|
||||
|
||||
test('_focusableNodes includes overlay if it has a valid tabindex', function() {
|
||||
overlay.setAttribute('tabindex', '0');
|
||||
var focusableNodes = overlay._focusableNodes;
|
||||
assert.equal(focusableNodes.length, 4, '4 focusable nodes');
|
||||
assert.notEqual(focusableNodes.indexOf(overlay), -1, 'overlay is included');
|
||||
});
|
||||
|
||||
test('_focusableNodes respects the tabindex order', function() {
|
||||
var focusableNodes = overlayWithTabIndex._focusableNodes;
|
||||
assert.equal(focusableNodes.length, 6, '6 nodes are focusable');
|
||||
assert.equal(focusableNodes[0], Polymer.dom(overlayWithTabIndex).querySelector('.focusable1'));
|
||||
assert.equal(focusableNodes[1], Polymer.dom(overlayWithTabIndex).querySelector('.focusable2'));
|
||||
assert.equal(focusableNodes[2], Polymer.dom(overlayWithTabIndex).querySelector('.focusable3'));
|
||||
assert.equal(focusableNodes[3], Polymer.dom(overlayWithTabIndex).querySelector('.focusable4'));
|
||||
assert.equal(focusableNodes[4], Polymer.dom(overlayWithTabIndex).querySelector('.focusable5'));
|
||||
assert.equal(focusableNodes[5], Polymer.dom(overlayWithTabIndex).querySelector('.focusable6'));
|
||||
});
|
||||
|
||||
test('first focusable is focused if no [autofocus] node is present', function(done) {
|
||||
runAfterOpen(overlay, function() {
|
||||
assert.equal(Polymer.dom(overlay).querySelector('.focusable1'), document.activeElement, 'focusable1 is focused');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('with-backdrop: TAB & Shift+TAB wrap focus', function(done) {
|
||||
overlay.withBackdrop = true;
|
||||
var focusableNodes = overlay._focusableNodes;
|
||||
runAfterOpen(overlay, function() {
|
||||
// Go to last element.
|
||||
MockInteractions.focus(focusableNodes[focusableNodes.length-1]);
|
||||
// Simulate TAB & focus out of overlay.
|
||||
MockInteractions.pressAndReleaseKeyOn(document, 9);
|
||||
MockInteractions.focus(document.body);
|
||||
assert.equal(focusableNodes[0], document.activeElement, 'focus wrapped to first focusable');
|
||||
// Simulate Shift+TAB & focus out of overlay.
|
||||
MockInteractions.pressAndReleaseKeyOn(document, 9, ['shift']);
|
||||
MockInteractions.focus(document.body);
|
||||
assert.equal(focusableNodes[focusableNodes.length-1], document.activeElement, 'focus wrapped to last focusable');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('with-backdrop: TAB & Shift+TAB wrap focus respecting tabindex', function(done) {
|
||||
overlayWithTabIndex.withBackdrop = true;
|
||||
var focusableNodes = overlayWithTabIndex._focusableNodes;
|
||||
runAfterOpen(overlayWithTabIndex, function() {
|
||||
// Go to last element.
|
||||
MockInteractions.focus(focusableNodes[focusableNodes.length-1]);
|
||||
// Simulate TAB & focus out of overlay.
|
||||
MockInteractions.pressAndReleaseKeyOn(document, 9);
|
||||
MockInteractions.focus(document.body);
|
||||
assert.equal(focusableNodes[0], document.activeElement, 'focus wrapped to first focusable');
|
||||
// Simulate Shift+TAB & focus out of overlay.
|
||||
MockInteractions.pressAndReleaseKeyOn(document, 9, ['shift']);
|
||||
MockInteractions.focus(document.body);
|
||||
assert.equal(focusableNodes[focusableNodes.length-1], document.activeElement, 'focus wrapped to last focusable');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('overlay with backdrop', function() {
|
||||
var overlay;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue