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
b4ae58347b
commit
d90d4de2b0
42 changed files with 1514 additions and 361 deletions
|
@ -15,12 +15,12 @@
|
|||
},
|
||||
"devDependencies": {},
|
||||
"ignore": [],
|
||||
"version": "1.0.26",
|
||||
"_release": "1.0.26",
|
||||
"version": "1.0.29",
|
||||
"_release": "1.0.29",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "1.0.26",
|
||||
"commit": "f3cd4149e26d75861ab29a3e44647195bb97728b"
|
||||
"tag": "1.0.29",
|
||||
"commit": "2e60e59d116fee68281235ba19f1e74073565c50"
|
||||
},
|
||||
"_source": "git://github.com/MediaBrowser/emby-webcomponents.git",
|
||||
"_target": "~1.0.0",
|
||||
|
|
415
dashboard-ui/bower_components/emby-webcomponents/focusmanager.js
vendored
Normal file
415
dashboard-ui/bower_components/emby-webcomponents/focusmanager.js
vendored
Normal file
|
@ -0,0 +1,415 @@
|
|||
define([], function () {
|
||||
|
||||
function autoFocus(view, defaultToFirst) {
|
||||
|
||||
var element = view.querySelector('*[autofocus]');
|
||||
if (element) {
|
||||
focus(element);
|
||||
} else if (defaultToFirst !== false) {
|
||||
element = getFocusableElements(view)[0];
|
||||
|
||||
if (element) {
|
||||
focus(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function focus(element) {
|
||||
|
||||
var tagName = element.tagName;
|
||||
if (tagName == 'PAPER-INPUT' || tagName == 'PAPER-DROPDOWN-MENU' || tagName == 'EMBY-DROPDOWN-MENU') {
|
||||
element = element.querySelector('input');
|
||||
}
|
||||
|
||||
element.focus();
|
||||
}
|
||||
|
||||
var focusableTagNames = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A', 'PAPER-BUTTON', 'PAPER-INPUT', 'PAPER-TEXTAREA', 'PAPER-ICON-BUTTON', 'PAPER-FAB', 'PAPER-ICON-ITEM', 'PAPER-MENU-ITEM', 'PAPER-DROPDOWN-MENU', 'EMBY-DROPDOWN-MENU'];
|
||||
var focusableContainerTagNames = ['BODY', 'PAPER-DIALOG'];
|
||||
var focusableQuery = focusableTagNames.join(',') + ',.focusable';
|
||||
|
||||
function isFocusable(elem) {
|
||||
|
||||
if (focusableTagNames.indexOf(elem.tagName) != -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (elem.classList && elem.classList.contains('focusable')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function focusableParent(elem) {
|
||||
|
||||
while (!isFocusable(elem)) {
|
||||
elem = elem.parentNode;
|
||||
|
||||
if (!elem) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
function isFocusableElementValid(elem) {
|
||||
|
||||
if (elem.disabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (elem.getAttribute('tabindex') == "-1") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom
|
||||
if (elem.offsetParent === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getFocusableElements(parent) {
|
||||
var elems = (parent || document).querySelectorAll(focusableQuery);
|
||||
var focusableElements = [];
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var elem = elems[i];
|
||||
|
||||
if (isFocusableElementValid(elem)) {
|
||||
focusableElements.push(elem);
|
||||
}
|
||||
}
|
||||
|
||||
return focusableElements;
|
||||
}
|
||||
|
||||
function isFocusContainer(elem, direction) {
|
||||
|
||||
if (focusableContainerTagNames.indexOf(elem.tagName) != -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (direction < 2) {
|
||||
if (elem.classList.contains('focuscontainer-x')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (direction == 3) {
|
||||
if (elem.classList.contains('focuscontainer-down')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getFocusContainer(elem, direction) {
|
||||
while (!isFocusContainer(elem, direction)) {
|
||||
elem = elem.parentNode;
|
||||
|
||||
if (!elem) {
|
||||
return document.body;
|
||||
}
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
function getOffset(elem, doc) {
|
||||
|
||||
var box = { top: 0, left: 0 };
|
||||
|
||||
if (!doc) {
|
||||
return box;
|
||||
}
|
||||
|
||||
var docElem = doc.documentElement;
|
||||
|
||||
// Support: BlackBerry 5, iOS 3 (original iPhone)
|
||||
// If we don't have gBCR, just use 0,0 rather than error
|
||||
if (elem.getBoundingClientRect) {
|
||||
box = elem.getBoundingClientRect();
|
||||
}
|
||||
var win = doc.defaultView;
|
||||
return {
|
||||
top: box.top + win.pageYOffset - docElem.clientTop,
|
||||
left: box.left + win.pageXOffset - docElem.clientLeft
|
||||
};
|
||||
}
|
||||
|
||||
function getViewportBoundingClientRect(elem) {
|
||||
|
||||
var doc = elem.ownerDocument;
|
||||
var offset = getOffset(elem, doc);
|
||||
var win = doc.defaultView;
|
||||
|
||||
var posY = offset.top - win.pageXOffset;
|
||||
var posX = offset.left - win.pageYOffset;
|
||||
|
||||
var width = elem.offsetWidth;
|
||||
var height = elem.offsetHeight;
|
||||
|
||||
return {
|
||||
left: posX,
|
||||
top: posY,
|
||||
width: width,
|
||||
height: height,
|
||||
right: posX + width,
|
||||
bottom: posY + height
|
||||
};
|
||||
var scrollLeft = (((t = document.documentElement) || (t = document.body.parentNode))
|
||||
&& typeof t.scrollLeft == 'number' ? t : document.body).scrollLeft;
|
||||
|
||||
var scrollTop = (((t = document.documentElement) || (t = document.body.parentNode))
|
||||
&& typeof t.scrollTop == 'number' ? t : document.body).scrollTop;
|
||||
}
|
||||
|
||||
function nav(activeElement, direction) {
|
||||
|
||||
activeElement = activeElement || document.activeElement;
|
||||
|
||||
if (activeElement) {
|
||||
activeElement = focusableParent(activeElement);
|
||||
}
|
||||
|
||||
var container = activeElement ? getFocusContainer(activeElement, direction) : document.body;
|
||||
|
||||
if (!activeElement) {
|
||||
autoFocus(container, true);
|
||||
return;
|
||||
}
|
||||
|
||||
var focusableContainer = parentWithClass(activeElement, 'focusable');
|
||||
|
||||
var rect = getViewportBoundingClientRect(activeElement);
|
||||
var focusableElements = [];
|
||||
|
||||
var focusable = container.querySelectorAll(focusableQuery);
|
||||
for (var i = 0, length = focusable.length; i < length; i++) {
|
||||
var curr = focusable[i];
|
||||
|
||||
if (curr == activeElement) {
|
||||
continue;
|
||||
}
|
||||
// Don't refocus into the same container
|
||||
if (curr == focusableContainer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isFocusableElementValid(curr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var elementRect = getViewportBoundingClientRect(curr);
|
||||
|
||||
switch (direction) {
|
||||
|
||||
case 0:
|
||||
// left
|
||||
if (elementRect.left >= rect.left) {
|
||||
continue;
|
||||
}
|
||||
if (elementRect.right == rect.right) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// right
|
||||
if (elementRect.right <= rect.right) {
|
||||
continue;
|
||||
}
|
||||
if (elementRect.left == rect.left) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// up
|
||||
if (elementRect.top >= rect.top) {
|
||||
continue;
|
||||
}
|
||||
if (elementRect.bottom >= rect.bottom) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// down
|
||||
if (elementRect.bottom <= rect.bottom) {
|
||||
continue;
|
||||
}
|
||||
if (elementRect.top <= rect.top) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
focusableElements.push({
|
||||
element: curr,
|
||||
clientRect: elementRect
|
||||
});
|
||||
}
|
||||
|
||||
var nearest = getNearestElements(focusableElements, rect, direction);
|
||||
|
||||
if (nearest.length) {
|
||||
|
||||
var nearestElement = nearest[0].node;
|
||||
|
||||
// See if there's a focusable container, and if so, send the focus command to that
|
||||
var nearestElementFocusableParent = parentWithClass(nearestElement, 'focusable');
|
||||
if (nearestElementFocusableParent && nearestElementFocusableParent != nearestElement && activeElement) {
|
||||
if (parentWithClass(activeElement, 'focusable') != nearestElementFocusableParent) {
|
||||
nearestElement = nearestElementFocusableParent;
|
||||
}
|
||||
}
|
||||
|
||||
focus(nearestElement);
|
||||
}
|
||||
}
|
||||
|
||||
function parentWithClass(elem, className) {
|
||||
|
||||
while (!elem.classList || !elem.classList.contains(className)) {
|
||||
elem = elem.parentNode;
|
||||
|
||||
if (!elem) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
function getNearestElements(elementInfos, options, direction) {
|
||||
|
||||
// Get elements and work out x/y points
|
||||
var cache = [],
|
||||
point1x = parseFloat(options.left) || 0,
|
||||
point1y = parseFloat(options.top) || 0,
|
||||
point2x = parseFloat(point1x + options.width - 1) || point1x,
|
||||
point2y = parseFloat(point1y + options.height - 1) || point1y,
|
||||
// Shortcuts to help with compression
|
||||
min = Math.min,
|
||||
max = Math.max;
|
||||
|
||||
var sourceMidX = options.left + (options.width / 2);
|
||||
var sourceMidY = options.top + (options.height / 2);
|
||||
|
||||
// Loop through all elements and check their positions
|
||||
for (var i = 0, length = elementInfos.length; i < length; i++) {
|
||||
|
||||
var elementInfo = elementInfos[i];
|
||||
var elem = elementInfo.element;
|
||||
|
||||
var off = elementInfo.clientRect,
|
||||
x = off.left,
|
||||
y = off.top,
|
||||
x2 = x + off.width - 1,
|
||||
y2 = y + off.height - 1,
|
||||
maxX1 = max(x, point1x),
|
||||
minX2 = min(x2, point2x),
|
||||
maxY1 = max(y, point1y),
|
||||
minY2 = min(y2, point2y),
|
||||
intersectX = minX2 >= maxX1,
|
||||
intersectY = minY2 >= maxY1;
|
||||
|
||||
var midX = off.left + (off.width / 2);
|
||||
var midY = off.top + (off.height / 2);
|
||||
|
||||
var distX;
|
||||
var distY;
|
||||
|
||||
switch (direction) {
|
||||
|
||||
case 0:
|
||||
// left
|
||||
distX = intersectX ? 0 : Math.abs(point1x - x2);
|
||||
distY = intersectY ? 0 : Math.abs(sourceMidY - midY);
|
||||
break;
|
||||
case 1:
|
||||
// right
|
||||
distX = intersectX ? 0 : Math.abs(x - point2x);
|
||||
distY = intersectY ? 0 : Math.abs(sourceMidY - midY);
|
||||
break;
|
||||
case 2:
|
||||
// up
|
||||
distY = intersectY ? 0 : Math.abs(point1y - y2);
|
||||
distX = intersectX ? 0 : Math.abs(sourceMidX - midX);
|
||||
break;
|
||||
case 3:
|
||||
// down
|
||||
distY = intersectY ? 0 : Math.abs(y - point2y);
|
||||
distX = intersectX ? 0 : Math.abs(sourceMidX - midX);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
var distT = Math.sqrt(distX * distX + distY * distY);
|
||||
|
||||
cache.push({
|
||||
node: elem,
|
||||
distX: distX,
|
||||
distY: distY,
|
||||
distT: distT
|
||||
});
|
||||
}
|
||||
|
||||
cache.sort(sortNodesT);
|
||||
//if (direction < 2) {
|
||||
// cache.sort(sortNodesX);
|
||||
//} else {
|
||||
// cache.sort(sortNodesY);
|
||||
//}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
function sortNodesX(a, b) {
|
||||
var result = a.distX - b.distX;
|
||||
|
||||
if (result == 0) {
|
||||
return a.distY - b.distY;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function sortNodesT(a, b) {
|
||||
return a.distT - b.distT;
|
||||
}
|
||||
|
||||
function sortNodesY(a, b) {
|
||||
var result = a.distY - b.distY;
|
||||
|
||||
if (result == 0) {
|
||||
return a.distX - b.distX;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return {
|
||||
autoFocus: autoFocus,
|
||||
focus: focus,
|
||||
focusableParent: focusableParent,
|
||||
getFocusableElements: getFocusableElements,
|
||||
moveLeft: function (sourceElement) {
|
||||
nav(sourceElement, 0);
|
||||
},
|
||||
moveRight: function (sourceElement) {
|
||||
nav(sourceElement, 1);
|
||||
},
|
||||
moveUp: function (sourceElement) {
|
||||
nav(sourceElement, 2);
|
||||
},
|
||||
moveDown: function (sourceElement) {
|
||||
nav(sourceElement, 3);
|
||||
}
|
||||
};
|
||||
});
|
28
dashboard-ui/bower_components/emby-webcomponents/paperdialoghelper/paperdialoghelper.css
vendored
Normal file
28
dashboard-ui/bower_components/emby-webcomponents/paperdialoghelper/paperdialoghelper.css
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
.paperDialog {
|
||||
margin: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
position: fixed;
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.paperDialog.scrollY {
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.paperDialog.hiddenScroll::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.paperDialog.hiddenScroll {
|
||||
-ms-overflow-style: none;
|
||||
overflow: -moz-scrollbars-none;
|
||||
}
|
188
dashboard-ui/bower_components/emby-webcomponents/paperdialoghelper/paperdialoghelper.js
vendored
Normal file
188
dashboard-ui/bower_components/emby-webcomponents/paperdialoghelper/paperdialoghelper.js
vendored
Normal file
|
@ -0,0 +1,188 @@
|
|||
define(['historyManager', 'focusManager', 'performanceManager', 'browser', 'paper-dialog', 'scale-up-animation', 'fade-out-animation', 'fade-in-animation', 'css!./paperdialoghelper.css'], function (historyManager, focusManager, performanceManager, browser) {
|
||||
|
||||
function paperDialogHashHandler(dlg, hash, resolve, lockDocumentScroll) {
|
||||
|
||||
var self = this;
|
||||
self.originalUrl = window.location.href;
|
||||
var activeElement = document.activeElement;
|
||||
|
||||
function onHashChange(e) {
|
||||
|
||||
var isBack = self.originalUrl == window.location.href;
|
||||
|
||||
if (isBack || !dlg.opened) {
|
||||
window.removeEventListener('popstate', onHashChange);
|
||||
}
|
||||
|
||||
if (isBack) {
|
||||
self.closedByBack = true;
|
||||
dlg.close();
|
||||
}
|
||||
}
|
||||
|
||||
function onDialogClosed() {
|
||||
|
||||
if (lockDocumentScroll !== false) {
|
||||
// TODO
|
||||
//Dashboard.onPopupClose();
|
||||
}
|
||||
|
||||
window.removeEventListener('popstate', onHashChange);
|
||||
|
||||
if (!self.closedByBack) {
|
||||
var state = history.state || {};
|
||||
if (state.dialogId == hash) {
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
|
||||
activeElement.focus();
|
||||
|
||||
if (dlg.getAttribute('data-removeonclose') == 'true') {
|
||||
dlg.parentNode.removeChild(dlg);
|
||||
}
|
||||
|
||||
//resolve();
|
||||
// if we just called history.back(), then use a timeout to allow the history events to fire first
|
||||
setTimeout(function () {
|
||||
resolve({
|
||||
element: dlg,
|
||||
closedByBack: self.closedByBack
|
||||
});
|
||||
}, 1);
|
||||
}
|
||||
|
||||
dlg.addEventListener('iron-overlay-closed', onDialogClosed);
|
||||
dlg.open();
|
||||
|
||||
if (lockDocumentScroll !== false) {
|
||||
// TODO
|
||||
//Dashboard.onPopupOpen();
|
||||
}
|
||||
|
||||
historyManager.pushState({ dialogId: hash }, "Dialog", hash);
|
||||
|
||||
window.addEventListener('popstate', onHashChange);
|
||||
}
|
||||
|
||||
function open(dlg) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
new paperDialogHashHandler(dlg, 'dlg' + new Date().getTime(), resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function close(dlg) {
|
||||
|
||||
if (dlg.opened) {
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
|
||||
function onDialogOpened(e) {
|
||||
|
||||
focusManager.autoFocus(e.target);
|
||||
}
|
||||
|
||||
function createDialog(options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
var dlg = document.createElement('paper-dialog');
|
||||
|
||||
dlg.setAttribute('with-backdrop', 'with-backdrop');
|
||||
dlg.setAttribute('role', 'alertdialog');
|
||||
|
||||
// without this safari will scroll the background instead of the dialog contents
|
||||
// but not needed here since this is already on top of an existing dialog
|
||||
// but skip it in IE because it's causing the entire browser to hang
|
||||
// Also have to disable for firefox because it's causing select elements to not be clickable
|
||||
if (!browser.msie && !browser.firefox && options.modal !== false) {
|
||||
dlg.setAttribute('modal', 'modal');
|
||||
}
|
||||
|
||||
// seeing max call stack size exceeded in the debugger with this
|
||||
dlg.setAttribute('noAutoFocus', 'noAutoFocus');
|
||||
|
||||
var defaultEntryAnimation = performanceManager.getAnimationPerformance() <= 1 ? 'fade-in-animation' : 'scale-up-animation';
|
||||
dlg.entryAnimation = options.entryAnimation || defaultEntryAnimation;
|
||||
dlg.exitAnimation = 'fade-out-animation';
|
||||
|
||||
dlg.animationConfig = {
|
||||
// scale up
|
||||
'entry': {
|
||||
name: options.entryAnimation || 'scale-up-animation',
|
||||
node: dlg,
|
||||
timing: { duration: options.entryAnimationDuration || 300, easing: 'ease-out' }
|
||||
},
|
||||
// fade out
|
||||
'exit': {
|
||||
name: 'fade-out-animation',
|
||||
node: dlg,
|
||||
timing: { duration: options.exitAnimationDuration || 400, easing: 'ease-in' }
|
||||
}
|
||||
};
|
||||
|
||||
dlg.classList.add('paperDialog');
|
||||
|
||||
dlg.classList.add('scrollY');
|
||||
|
||||
// TODO: Don't hide for mouse?
|
||||
dlg.classList.add('hiddenScroll');
|
||||
|
||||
if (options.removeOnClose) {
|
||||
dlg.setAttribute('data-removeonclose', 'true');
|
||||
}
|
||||
|
||||
dlg.addEventListener('iron-overlay-opened', onDialogOpened);
|
||||
|
||||
return dlg;
|
||||
}
|
||||
|
||||
function positionTo(dlg, elem) {
|
||||
|
||||
var windowHeight = $(window).height();
|
||||
|
||||
// If the window height is under a certain amount, don't bother trying to position
|
||||
// based on an element.
|
||||
if (windowHeight >= 540) {
|
||||
|
||||
var pos = $(elem).offset();
|
||||
|
||||
pos.top += elem.offsetHeight / 2;
|
||||
pos.left += elem.offsetWidth / 2;
|
||||
|
||||
// Account for margins
|
||||
pos.top -= 24;
|
||||
pos.left -= 24;
|
||||
|
||||
// Account for popup size - we can't predict this yet so just estimate
|
||||
pos.top -= $(dlg).height() / 2;
|
||||
pos.left -= $(dlg).width() / 2;
|
||||
|
||||
// Account for scroll position
|
||||
pos.top -= $(window).scrollTop();
|
||||
pos.left -= $(window).scrollLeft();
|
||||
|
||||
// Avoid showing too close to the bottom
|
||||
pos.top = Math.min(pos.top, windowHeight - 300);
|
||||
pos.left = Math.min(pos.left, $(window).width() - 300);
|
||||
|
||||
// Do some boundary checking
|
||||
pos.top = Math.max(pos.top, 0);
|
||||
pos.left = Math.max(pos.left, 0);
|
||||
|
||||
dlg.style.position = 'fixed';
|
||||
dlg.style.left = pos.left + 'px';
|
||||
dlg.style.top = pos.top + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
open: open,
|
||||
close: close,
|
||||
createDialog: createDialog,
|
||||
positionTo: positionTo
|
||||
};
|
||||
});
|
15
dashboard-ui/bower_components/emby-webcomponents/performancemanager.js
vendored
Normal file
15
dashboard-ui/bower_components/emby-webcomponents/performancemanager.js
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
define(['browser'], function (browser) {
|
||||
|
||||
function getAnimationPerformance() {
|
||||
|
||||
if (browser.mobile) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
return {
|
||||
getAnimationPerformance: getAnimationPerformance
|
||||
};
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue