1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

update components

This commit is contained in:
Luke Pulverenti 2016-02-24 00:36:48 -05:00
parent feb5e91986
commit 4da1e38cc5
26 changed files with 320 additions and 125 deletions

View file

@ -1,6 +1,6 @@
{
"name": "iron-overlay-behavior",
"version": "1.4.0",
"version": "1.4.1",
"license": "http://polymer.github.io/LICENSE.txt",
"description": "Provides a behavior for making an element an overlay",
"private": true,
@ -35,11 +35,11 @@
},
"ignore": [],
"homepage": "https://github.com/polymerelements/iron-overlay-behavior",
"_release": "1.4.0",
"_release": "1.4.1",
"_resolution": {
"type": "version",
"tag": "v1.4.0",
"commit": "9731850e81b004723f0c1878a85479f7aa9cfda1"
"tag": "v1.4.1",
"commit": "4aefb7bc41aecef69022d6435133c430fc52d3ba"
},
"_source": "git://github.com/polymerelements/iron-overlay-behavior.git",
"_target": "^1.0.0",

View file

@ -1,6 +1,6 @@
{
"name": "iron-overlay-behavior",
"version": "1.4.0",
"version": "1.4.1",
"license": "http://polymer.github.io/LICENSE.txt",
"description": "Provides a behavior for making an element an overlay",
"private": true,

View file

@ -61,6 +61,17 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
</template>
</demo-snippet>
<h3>Use <code>restore-focus-on-close</code> to return the focus to the element that opened the overlay when it gets closed.</h3>
<demo-snippet>
<template>
<button onclick="returnFocus.open()">Overlay that restores focus</button>
<simple-overlay id="returnFocus" restore-focus-on-close>
<p>Hello world!</p>
<button onclick="returnFocus.close()">Close</button>
</simple-overlay>
</template>
</demo-snippet>
<h3>The child with <code>autofocus</code> gets focused when opening the overlay.</h3>
<demo-snippet>
<template>

View file

@ -128,6 +128,14 @@ context. You should place this element as a child of `<body>` whenever possible.
value: document
},
/**
* Set to true to enable restoring of focus when overlay is closed.
*/
restoreFocusOnClose: {
type: Boolean,
value: false
},
_manager: {
type: Object,
value: Polymer.IronOverlayManager
@ -179,7 +187,7 @@ context. You should place this element as a child of `<body>` whenever possible.
* @type {Node}
*/
get _focusNode() {
return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]') || this.__firstFocusableNode || this;
return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]') || this;
},
/**
@ -235,7 +243,7 @@ context. You should place this element as a child of `<body>` whenever possible.
},
ready: function() {
// with-backdrop need tabindex to be set in order to trap the focus.
// with-backdrop needs 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.
@ -245,7 +253,7 @@ context. You should place this element as a child of `<body>` whenever possible.
attached: function() {
// Call _openedChanged here so that position can be computed correctly.
if (this._callOpenedWhenReady) {
if (this.opened) {
this._openedChanged();
}
this._observer = Polymer.dom(this).observeNodes(this._onNodesChange);
@ -315,7 +323,6 @@ context. You should place this element as a child of `<body>` whenever possible.
// wait to call after ready only if we're initially open
if (!this._overlaySetup) {
this._callOpenedWhenReady = this.opened;
return;
}
@ -552,28 +559,29 @@ context. You should place this element as a child of `<body>` whenever possible.
this._focusedChild = nodeToSet;
}
}
/**
* Fired after the `iron-overlay` opens.
* @event iron-overlay-opened
*/
/**
* Fired when the `iron-overlay` is canceled, but before it is closed.
* Cancel the event to prevent the `iron-overlay` from closing.
* @event iron-overlay-canceled
* @param {?Event} event The event in case the user pressed ESC or clicked outside the overlay
*/
/**
* Fired after the `iron-overlay` closes.
* @event iron-overlay-closed
* @param {{canceled: (boolean|undefined)}} set to the `closingReason` attribute
*/
};
/** @polymerBehavior */
Polymer.IronOverlayBehavior = [Polymer.IronA11yKeysBehavior, Polymer.IronFitBehavior, Polymer.IronResizableBehavior, Polymer.IronOverlayBehaviorImpl];
/**
* Fired after the `iron-overlay` opens.
* @event iron-overlay-opened
*/
/**
* Fired when the `iron-overlay` is canceled, but before it is closed.
* Cancel the event to prevent the `iron-overlay` from closing.
* @event iron-overlay-canceled
* @param {Event} event The closing of the `iron-overlay` can be prevented
* by calling `event.preventDefault()`. The `event.detail` is the original event that originated
* the canceling (e.g. ESC keyboard event or click event outside the `iron-overlay`).
*/
/**
* Fired after the `iron-overlay` closes.
* @event iron-overlay-closed
* @param {{canceled: (boolean|undefined)}} closingReason Contains `canceled` (whether the overlay was canceled).
*/
</script>

View file

@ -18,6 +18,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
*/
Polymer.IronOverlayManagerClass = function() {
this._overlays = [];
// Used to keep track of the last focused node before an overlay gets opened.
this._lastFocusedNodes = [];
/**
* iframes have a default z-index of 100, so this default should be at least
* that.
@ -36,7 +39,42 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
return this._backdropElement;
}.bind(this)
});
}
/**
* The deepest active element.
* returns {?Node} element the active element
*/
this.deepActiveElement = null;
Object.defineProperty(this, 'deepActiveElement', {
get: function() {
var active = document.activeElement;
// document.activeElement can be null
// https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
while (active && active.root && Polymer.dom(active.root).activeElement) {
active = Polymer.dom(active.root).activeElement;
}
return active;
}.bind(this)
});
};
/**
* If a node is contained in an overlay.
* @private
* @param {Node} node
* @returns {Boolean}
*/
Polymer.IronOverlayManagerClass.prototype._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;
};
Polymer.IronOverlayManagerClass.prototype._applyOverlayZ = function(overlay, aboveZ) {
this._setZ(overlay, aboveZ + 2);
@ -56,6 +94,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
if (newZ <= minimumZ) {
this._applyOverlayZ(overlay, minimumZ);
}
var element = this.deepActiveElement;
// If already in other overlay, don't reset focus there.
if (this._isChildOfOverlay(element)) {
element = null;
}
this._lastFocusedNodes.push(element);
};
Polymer.IronOverlayManagerClass.prototype.removeOverlay = function(overlay) {
@ -63,6 +107,13 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
if (i >= 0) {
this._overlays.splice(i, 1);
this._setZ(overlay, '');
var node = this._lastFocusedNodes[i];
// Focus only if still contained in document.body
if (overlay.restoreFocusOnClose && node && Polymer.dom(document.body).deepContains(node)) {
node.focus();
}
this._lastFocusedNodes.splice(i, 1);
}
};

View file

@ -24,6 +24,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<link rel="import" href="../../iron-test-helpers/iron-test-helpers.html">
<link rel="import" href="test-overlay.html">
<link rel="import" href="test-overlay2.html">
<link rel="import" href="test-buttons.html">
<style is="custom-style">
iron-overlay-backdrop {
@ -112,6 +113,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
</template>
</test-fixture>
<test-buttons id="buttons"></test-buttons>
<input id="focusInput" placeholder="focus input">
<script>
function runAfterOpen(overlay, callback) {
overlay.addEventListener('iron-overlay-opened', function() {
@ -453,13 +457,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
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;
@ -498,6 +495,109 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
});
suite('Polymer.IronOverlayManager.deepActiveElement', function() {
test('handles document.body', function () {
document.body.focus();
assert.equal(Polymer.IronOverlayManager.deepActiveElement, document.body);
});
test('handles light dom', function () {
var focusable = document.getElementById('focusInput');
focusable.focus();
assert.equal(Polymer.IronOverlayManager.deepActiveElement, focusable, 'input is handled');
focusable.blur();
});
test('handles shadow dom', function () {
var focusable = document.getElementById('buttons').$.button0;
focusable.focus();
assert.equal(Polymer.IronOverlayManager.deepActiveElement, focusable);
focusable.blur();
});
});
suite('restore-focus-on-close', function() {
var overlay;
setup(function () {
overlay = fixture('autofocus');
overlay.restoreFocusOnClose = true;
});
teardown(function () {
// No matter what, return the focus to body!
document.body.focus();
});
test('does not return focus on close by default (restore-focus-on-close=false)', function(done) {
overlay.restoreFocusOnClose = false;
var focusable = document.getElementById('focusInput');
focusable.focus();
runAfterOpen(overlay, function() {
runAfterClose(overlay, function() {
assert.notEqual(Polymer.IronOverlayManager.deepActiveElement, focusable, 'focus is not restored to focusable');
done();
});
});
});
test('overlay returns focus on close', function(done) {
var focusable = document.getElementById('focusInput');
focusable.focus();
runAfterOpen(overlay, function() {
runAfterClose(overlay, function() {
assert.equal(Polymer.IronOverlayManager.deepActiveElement, focusable, 'focus restored to focusable');
done();
});
});
});
test('overlay returns focus on close (ShadowDOM)', function(done) {
var focusable = document.getElementById('buttons').$.button0;
focusable.focus();
runAfterOpen(overlay, function() {
runAfterClose(overlay, function() {
assert.equal(Polymer.IronOverlayManager.deepActiveElement, focusable, 'focus restored to focusable');
done();
});
});
});
test('overlay does not return focus to elements contained in another overlay', function(done) {
var overlay2 = fixture('basic');
// So it doesn't interfere with focus changes.
overlay2.noAutoFocus = true;
var focusable = document.createElement('input');
runAfterOpen(overlay2,function () {
Polymer.dom(overlay2).appendChild(focusable);
focusable.focus();
runAfterOpen(overlay, function() {
runAfterClose(overlay, function() {
assert.notEqual(Polymer.IronOverlayManager.deepActiveElement, focusable, 'focus not restored to focusable inside overlay2');
done();
});
});
});
});
test('overlay does not return focus to elements that are not in the body anymore', function(done) {
var focusable = document.createElement('input');
document.body.appendChild(focusable);
focusable.focus();
var focusSpy = sinon.spy(focusable, 'focus');
runAfterOpen(overlay, function() {
document.body.removeChild(focusable);
runAfterClose(overlay, function() {
assert.isFalse(focusSpy.called, 'focus not called');
done();
});
});
});
});
suite('overlay with backdrop', function() {
var overlay;
@ -548,9 +648,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
test('manager.getBackdrops() immediately updated on opened changes', function() {
overlay.opened = true;
assert.equal(overlay._manager.getBackdrops().length, 1, 'overlay added to manager backdrops');
assert.equal(Polymer.IronOverlayManager.getBackdrops().length, 1, 'overlay added to manager backdrops');
overlay.opened = false;
assert.equal(overlay._manager.getBackdrops().length, 0, 'overlay removed from manager backdrops');
assert.equal(Polymer.IronOverlayManager.getBackdrops().length, 0, 'overlay removed from manager backdrops');
});
test('updating with-backdrop to false closes backdrop', function(done) {